557 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
Stephen F. Booth
5cb589a5b8 Updated NEWS for the latest changes 2018-10-28 08:43:45 -05:00
Stephen F. Booth
a4d04e0c40 Added APE, DSF, and DFF formats to the list 2018-10-28 08:42:19 -05:00
Stephen F. Booth
4ab0891646 Added DSF and DSDIFF authors 2018-10-28 08:35:15 -05:00
Jonas Kvinge
d71398c953 Add DSF and DSDIFF file types management (#878)
* Add DSF and DSDIFF file types management

* Fixes for some build chains

* unit64_t replaced by unsigned long long, warning fixes

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

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

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

* Restyling

* Restyling to reduce length of excessively long lines

* Add to detectByExtension

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

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

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

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

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

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

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

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

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

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

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

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

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

ID3 (2.3, 2.4; MVN, MVI for 2.2):
    MVNM: Movement Name
    MVIN: Movement Number/Count
2016-10-18 20:45:54 +02:00
Tsuda Kageyu
0dac721ce2 Update NEWS. 2016-09-26 17:48:44 +09:00
Stephen F. Booth
bbeeca6fdb Merge pull request #754 from hyperquantum/master
Fix defect in ByteVectorStream::seek when Position==End.
2016-09-15 21:11:08 -04:00
Kevin André
7e90313690 Fix defect in ByteVectorStream::seek when Position==End. 2016-09-15 16:30:16 +02:00
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
Tsuda Kageyu
1d3c95f692 Merge pull request #752 from evpobr/cmake-ver
Move cmake_minimum_required at the top
2016-09-12 15:56:45 +09:00
Tsuda Kageyu
8c3801f18d Merge pull request #753 from FestusHagen/fh1.m_AddBuildSharedLibsOption
Add BUILD_SHARED_LIBS option for CMake GUI.
2016-09-12 15:56:33 +09:00
Festus Hagen
c9bdd416ef Add BUILD_SHARED_LIBS option for CMake GUI. 2016-08-25 15:03:44 -04:00
evpobr
9f28e037fe Move cmake_minimum_required at the top 2016-08-20 22:37:53 +05:00
Stephen F. Booth
92c070ba9e Merge pull request #749 from jwelton/fix-typo
Fix Typo
2016-08-14 17:10:18 -04:00
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
Jake Welton
75e3ec73aa Change string to end offset 2016-08-14 22:02:33 +01: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
Tsuda Kageyu
3e47a036fb Update NEWS. 2016-05-14 10:46:42 +09:00
Tsuda Kageyu
9b995544e4 Fix reading table of contents frames with a lot of children. 2016-05-14 09:58:19 +09:00
Tsuda Kageyu
d8e5077961 Update NEWS. 2016-04-29 17:26:33 +09: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
6422054540 Merge pull request #739 from frgm/master
c: fix a typo
2016-04-23 06:54:59 +09:00
Svyatoslav Mishyn
1b878102f0 c: fix a typo
readble => readable
2016-04-22 16:46:15 +03:00
Tsuda Kageyu
0a85f9b227 Revert "Hide a private static variable."
This reverts commit 25ffbcb4b9.

# Conflicts:
#	taglib/mpeg/id3v2/id3v2framefactory.cpp
#	taglib/mpeg/id3v2/id3v2framefactory.h
2016-04-22 09:27:04 +09:00
Stephen F. Booth
31f3109b47 Merge pull request #732 from dirkvdb/master
Also ignore the virtual destructor warning when compiling with clang
2016-04-02 13:21:39 -04:00
Dirk Vanden Boer
76f8ff388f Also ignore the virtual destructor warning when compiling with clang 2016-03-20 20:33:04 +01:00
Tsuda Kageyu
7627ae48ed Change some static_casts to dynamic_casts in test_id3v2.cpp.
static_casts are unsafe and some of following tests doesn't work well with them.
2016-03-17 22:50:34 +09:00
Tsuda Kageyu
b2a6768704 Don't stop parsing an ID3v2 SYLT frame when its description is empty. 2016-03-14 20:35:09 +09:00
Tsuda Kageyu
7d270a7e20 Update NEWS. 2016-03-10 21:38:08 +09:00
Tsuda Kageyu
bf53dc6131 Merge pull request #726 from amethystAnt/ape-keys-bug
Fixed bug #725 - changed the maximum length of an APE key to 255
2016-03-07 06:41:21 +09:00
Karel Patlejch
ff8b6a91e7 Fixed bug #725 - changed the maximum length of an APE key to 255 2016-03-06 21:15:18 +01:00
Tsuda Kageyu
1a82419872 Add myself to maintainers. 2016-03-03 10:06:51 +09: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
289 changed files with 13907 additions and 7021 deletions

3
.gitignore vendored
View File

@@ -19,8 +19,10 @@ CMakeFiles/
/taglib.pc
/tests/test_runner
/tests/Testing
/taglib/libtag.a
/taglib_config.h
/taglib-config
/bindings/c/libtag_c.a
/bindings/c/taglib_c.pc
/bindings/c/Debug
/bindings/c/MinSizeRel
@@ -42,5 +44,6 @@ CMakeFiles/
/taglib/tag.dir/Release
/ALL_BUILD.dir
/ZERO_CHECK.dir
taglib.h.stamp
taglib.xcodeproj
CMakeScripts

View File

@@ -6,6 +6,8 @@ os:
- linux
- osx
dist: trusty
compiler:
- gcc
- clang
@@ -15,6 +17,7 @@ addons:
packages:
- libcppunit-dev
- zlib1g-dev
- libboost-dev
matrix:
exclude:
@@ -24,5 +27,4 @@ matrix:
install:
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew install cppunit; fi
script: cmake -DBUILD_TESTS=ON -DBUILD_EXAMPLES=ON -DBUILD_BINDINGS=ON . && make && make check
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

View File

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

View File

@@ -1,7 +1,7 @@
project(taglib)
cmake_minimum_required(VERSION 2.8.0 FATAL_ERROR)
project(taglib)
if(NOT ${CMAKE_VERSION} VERSION_LESS 2.8.12)
cmake_policy(SET CMP0022 OLD)
endif()
@@ -12,6 +12,15 @@ 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)
option(BUILD_FRAMEWORK "Build an OS X framework" OFF)
if(BUILD_FRAMEWORK)
set(BUILD_SHARED_LIBS ON)
#set(CMAKE_MACOSX_RPATH 1)
set(FRAMEWORK_INSTALL_DIR "/Library/Frameworks" CACHE STRING "Directory to install frameworks to.")
endif()
endif()
if(NOT BUILD_SHARED_LIBS)
add_definitions(-DTAGLIB_STATIC)
endif()
@@ -27,16 +36,17 @@ if(ENABLE_CCACHE)
endif()
option(VISIBILITY_HIDDEN "Build with -fvisibility=hidden" OFF)
if(VISIBILITY_HIDDEN)
add_definitions(-fvisibility=hidden)
endif()
option(BUILD_TESTS "Build the test suite" OFF)
option(BUILD_EXAMPLES "Build the examples" OFF)
option(BUILD_BINDINGS "Build the bindings" ON)
option(NO_ITUNES_HACKS "Disable workarounds for iTunes bugs" OFF)
option(PLATFORM_WINRT "Enable WinRT support" OFF)
if(PLATFORM_WINRT)
add_definitions(-DPLATFORM_WINRT)
endif()
add_definitions(-DHAVE_CONFIG_H)
set(TESTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/tests/")
@@ -47,11 +57,6 @@ set(BIN_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/bin" CACHE PATH "The subdirectory to
set(LIB_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is /lib${LIB_SUFFIX})")
set(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "The subdirectory to the header prefix")
if(APPLE)
option(BUILD_FRAMEWORK "Build an OS X framework" OFF)
set(FRAMEWORK_INSTALL_DIR "/Library/Frameworks" CACHE STRING "Directory to install frameworks to.")
endif()
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
@@ -89,9 +94,9 @@ endif()
# 2. If any interfaces have been added, removed, or changed since the last update, increment current, and set revision to 0.
# 3. If any interfaces have been added since the last public release, then increment age.
# 4. If any interfaces have been removed since the last public release, then set age to 0.
set(TAGLIB_SOVERSION_CURRENT 17)
set(TAGLIB_SOVERSION_CURRENT 18)
set(TAGLIB_SOVERSION_REVISION 0)
set(TAGLIB_SOVERSION_AGE 16)
set(TAGLIB_SOVERSION_AGE 17)
math(EXPR TAGLIB_SOVERSION_MAJOR "${TAGLIB_SOVERSION_CURRENT} - ${TAGLIB_SOVERSION_AGE}")
math(EXPR TAGLIB_SOVERSION_MINOR "${TAGLIB_SOVERSION_AGE}")
@@ -122,20 +127,11 @@ endif()
include_directories(${CMAKE_CURRENT_BINARY_DIR})
configure_file(config.h.cmake "${CMAKE_CURRENT_BINARY_DIR}/config.h")
if(WITH_ASF)
set(TAGLIB_WITH_ASF TRUE)
endif()
if(WITH_MP4)
set(TAGLIB_WITH_MP4 TRUE)
endif()
option(TRACE_IN_RELEASE "Output debug messages even in release mode" OFF)
option(TRACE_IN_RELEASE "Output debug messages even in release mode" OFF)
if(TRACE_IN_RELEASE)
set(TRACE_IN_RELEASE TRUE)
endif()
configure_file(taglib/taglib_config.h.cmake "${CMAKE_CURRENT_BINARY_DIR}/taglib_config.h")
add_subdirectory(taglib)
if(BUILD_BINDINGS)

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,15 @@ 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)
@@ -46,135 +57,125 @@ endif()
check_cxx_source_compiles("
#include <atomic>
int main() {
std::atomic<unsigned int> x;
x.fetch_add(1);
x.fetch_sub(1);
std::atomic_int x(1);
++x;
--x;
return 0;
}
" HAVE_STD_ATOMIC)
if(NOT HAVE_STD_ATOMIC)
find_package(Boost COMPONENTS atomic)
if(Boost_ATOMIC_FOUND)
set(HAVE_BOOST_ATOMIC 1)
else()
set(HAVE_BOOST_ATOMIC 0)
endif()
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_BOOST_ATOMIC)
if(NOT HAVE_GCC_ATOMIC)
check_cxx_source_compiles("
#include <libkern/OSAtomic.h>
int main() {
volatile int x;
__sync_add_and_fetch(&x, 1);
int y = __sync_sub_and_fetch(&x, 1);
volatile int32_t x;
OSAtomicIncrement32Barrier(&x);
int32_t y = OSAtomicDecrement32Barrier(&x);
return 0;
}
" HAVE_GCC_ATOMIC)
" HAVE_MAC_ATOMIC)
if(NOT HAVE_GCC_ATOMIC)
if(NOT HAVE_MAC_ATOMIC)
check_cxx_source_compiles("
#include <libkern/OSAtomic.h>
#include <windows.h>
int main() {
volatile int32_t x;
OSAtomicIncrement32Barrier(&x);
int32_t y = OSAtomicDecrement32Barrier(&x);
volatile LONG x;
InterlockedIncrement(&x);
LONG y = InterlockedDecrement(&x);
return 0;
}
" HAVE_MAC_ATOMIC)
" HAVE_WIN_ATOMIC)
if(NOT HAVE_MAC_ATOMIC)
if(NOT HAVE_WIN_ATOMIC)
check_cxx_source_compiles("
#include <windows.h>
#include <ia64intrin.h>
int main() {
volatile LONG x;
InterlockedIncrement(&x);
LONG y = InterlockedDecrement(&x);
volatile int x;
__sync_add_and_fetch(&x, 1);
int y = __sync_sub_and_fetch(&x, 1);
return 0;
}
" HAVE_WIN_ATOMIC)
if(NOT HAVE_WIN_ATOMIC)
check_cxx_source_compiles("
#include <ia64intrin.h>
int main() {
volatile int x;
__sync_add_and_fetch(&x, 1);
int y = __sync_sub_and_fetch(&x, 1);
return 0;
}
" HAVE_IA64_ATOMIC)
endif()
" 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("
#include <boost/endian/conversion.hpp>
int main() {
boost::endian::endian_reverse(static_cast<uint16_t>(1));
boost::endian::endian_reverse(static_cast<uint32_t>(1));
boost::endian::endian_reverse(static_cast<uint64_t>(1));
__builtin_bswap16(0);
__builtin_bswap32(0);
__builtin_bswap64(0);
return 0;
}
" HAVE_BOOST_BYTESWAP)
" HAVE_GCC_BYTESWAP)
if(NOT HAVE_BOOST_BYTESWAP)
if(NOT HAVE_GCC_BYTESWAP)
check_cxx_source_compiles("
#include <byteswap.h>
int main() {
__builtin_bswap16(0);
__builtin_bswap32(0);
__builtin_bswap64(0);
__bswap_16(0);
__bswap_32(0);
__bswap_64(0);
return 0;
}
" HAVE_GCC_BYTESWAP)
" HAVE_GLIBC_BYTESWAP)
if(NOT HAVE_GCC_BYTESWAP)
if(NOT HAVE_GLIBC_BYTESWAP)
check_cxx_source_compiles("
#include <byteswap.h>
#include <stdlib.h>
int main() {
__bswap_16(0);
__bswap_32(0);
__bswap_64(0);
_byteswap_ushort(0);
_byteswap_ulong(0);
_byteswap_uint64(0);
return 0;
}
" HAVE_GLIBC_BYTESWAP)
" HAVE_MSC_BYTESWAP)
if(NOT HAVE_GLIBC_BYTESWAP)
if(NOT HAVE_MSC_BYTESWAP)
check_cxx_source_compiles("
#include <stdlib.h>
#include <libkern/OSByteOrder.h>
int main() {
_byteswap_ushort(0);
_byteswap_ulong(0);
_byteswap_uint64(0);
OSSwapInt16(0);
OSSwapInt32(0);
OSSwapInt64(0);
return 0;
}
" HAVE_MSC_BYTESWAP)
" HAVE_MAC_BYTESWAP)
if(NOT HAVE_MSC_BYTESWAP)
if(NOT HAVE_MAC_BYTESWAP)
check_cxx_source_compiles("
#include <libkern/OSByteOrder.h>
#include <sys/endian.h>
int main() {
OSSwapInt16(0);
OSSwapInt32(0);
OSSwapInt64(0);
swap16(0);
swap32(0);
swap64(0);
return 0;
}
" HAVE_MAC_BYTESWAP)
if(NOT HAVE_MAC_BYTESWAP)
check_cxx_source_compiles("
#include <sys/endian.h>
int main() {
swap16(0);
swap32(0);
swap64(0);
return 0;
}
" HAVE_OPENBSD_BYTESWAP)
endif()
" HAVE_OPENBSD_BYTESWAP)
endif()
endif()
endif()
@@ -225,15 +226,6 @@ if(NOT ZLIB_SOURCE)
else()
set(HAVE_ZLIB 0)
endif()
if(NOT HAVE_ZLIB)
find_package(Boost COMPONENTS iostreams zlib)
if(Boost_IOSTREAMS_FOUND AND Boost_ZLIB_FOUND)
set(HAVE_BOOST_ZLIB 1)
else()
set(HAVE_BOOST_ZLIB 0)
endif()
endif()
endif()
# Determine whether CppUnit is installed.
@@ -246,3 +238,7 @@ if(BUILD_TESTS AND NOT BUILD_SHARED_LIBS)
endif()
endif()
# Detect WinRT mode
if(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
set(PLATFORM_WINRT 1)
endif()

159
INSTALL
View File

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

175
INSTALL.md Normal file
View File

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

39
NEWS
View File

@@ -1,5 +1,40 @@
TagLib 1.11 (Mar 4, 2016)
=========================
============================
* Added support for DSF and DSDIFF files.
* Added support for WinRT.
* 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.
* 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.
* Fixed OOB read on invalid Ogg FLAC files (CVE-2018-11439).
* Fixed handling of empty MPEG files.
* 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.
* TableOfContentsFrame::toString() improved.
* UserTextIdentificationFrame::toString() improved.
* Marked FileRef::create() deprecated.
* Several smaller bug fixes and performance improvements.
TagLib 1.11.1 (Oct 24, 2016)
============================
* Fixed binary incompatible change in TagLib::String.
* Fixed reading ID3v2 CTOC frames with a lot of entries.
* Fixed seeking ByteVectorStream from the end.
TagLib 1.11 (Apr 29, 2016)
==========================
1.11:
* Fixed reading APE items with long keys.
* Fixed reading ID3v2 SYLT frames when description is empty.
1.11 BETA 2:

26
README.md Normal file
View File

@@ -0,0 +1,26 @@
# TagLib
[![Build Status](https://travis-ci.org/taglib/taglib.svg?branch=master)](https://travis-ci.org/taglib/taglib)
### TagLib Audio Metadata Library
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
in [FLAC][], MPC, Speex, WavPack, TrueAudio, WAV, AIFF, MP4, APE,
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
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]: http://www.id3.org
[Ogg Vorbis]: http://vorbis.com/
[FLAC]: https://xiph.org/flac/
[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

@@ -21,7 +21,14 @@ set(tag_c_HDRS tag_c.h)
add_library(tag_c tag_c.cpp ${tag_c_HDRS})
target_link_libraries(tag_c tag)
set_target_properties(tag_c PROPERTIES PUBLIC_HEADER "${tag_c_HDRS}")
set_target_properties(tag_c PROPERTIES
PUBLIC_HEADER "${tag_c_HDRS}"
DEFINE_SYMBOL MAKE_TAGLIB_LIB
)
if(VISIBILITY_HIDDEN)
set_target_properties(tag_c PROPERTIES C_VISIBILITY_PRESET hidden
)
endif()
if(BUILD_FRAMEWORK)
set_target_properties(tag_c PROPERTIES FRAMEWORK TRUE)
endif()

View File

@@ -92,32 +92,32 @@ void taglib_free(void* pointer)
TagLib_File *taglib_file_new(const char *filename)
{
return reinterpret_cast<TagLib_File *>(FileRef::create(filename));
return reinterpret_cast<TagLib_File *>(new FileRef(filename));
}
TagLib_File *taglib_file_new_type(const char *filename, TagLib_File_Type type)
{
switch(type) {
case TagLib_File_MPEG:
return reinterpret_cast<TagLib_File *>(new MPEG::File(filename));
return reinterpret_cast<TagLib_File *>(new FileRef(new MPEG::File(filename)));
case TagLib_File_OggVorbis:
return reinterpret_cast<TagLib_File *>(new Ogg::Vorbis::File(filename));
return reinterpret_cast<TagLib_File *>(new FileRef(new Ogg::Vorbis::File(filename)));
case TagLib_File_FLAC:
return reinterpret_cast<TagLib_File *>(new FLAC::File(filename));
return reinterpret_cast<TagLib_File *>(new FileRef(new FLAC::File(filename)));
case TagLib_File_MPC:
return reinterpret_cast<TagLib_File *>(new MPC::File(filename));
return reinterpret_cast<TagLib_File *>(new FileRef(new MPC::File(filename)));
case TagLib_File_OggFlac:
return reinterpret_cast<TagLib_File *>(new Ogg::FLAC::File(filename));
return reinterpret_cast<TagLib_File *>(new FileRef(new Ogg::FLAC::File(filename)));
case TagLib_File_WavPack:
return reinterpret_cast<TagLib_File *>(new WavPack::File(filename));
return reinterpret_cast<TagLib_File *>(new FileRef(new WavPack::File(filename)));
case TagLib_File_Speex:
return reinterpret_cast<TagLib_File *>(new Ogg::Speex::File(filename));
return reinterpret_cast<TagLib_File *>(new FileRef(new Ogg::Speex::File(filename)));
case TagLib_File_TrueAudio:
return reinterpret_cast<TagLib_File *>(new TrueAudio::File(filename));
return reinterpret_cast<TagLib_File *>(new FileRef(new TrueAudio::File(filename)));
case TagLib_File_MP4:
return reinterpret_cast<TagLib_File *>(new MP4::File(filename));
return reinterpret_cast<TagLib_File *>(new FileRef(new MP4::File(filename)));
case TagLib_File_ASF:
return reinterpret_cast<TagLib_File *>(new ASF::File(filename));
return reinterpret_cast<TagLib_File *>(new FileRef(new ASF::File(filename)));
default:
return 0;
}
@@ -125,29 +125,29 @@ TagLib_File *taglib_file_new_type(const char *filename, TagLib_File_Type type)
void taglib_file_free(TagLib_File *file)
{
delete reinterpret_cast<File *>(file);
delete reinterpret_cast<FileRef *>(file);
}
BOOL taglib_file_is_valid(const TagLib_File *file)
{
return reinterpret_cast<const File *>(file)->isValid();
return reinterpret_cast<const FileRef *>(file)->isValid();
}
TagLib_Tag *taglib_file_tag(const TagLib_File *file)
{
const File *f = reinterpret_cast<const File *>(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)
{
const File *f = reinterpret_cast<const File *>(file);
const FileRef *f = reinterpret_cast<const FileRef *>(file);
return reinterpret_cast<const TagLib_AudioProperties *>(f->audioProperties());
}
BOOL taglib_file_save(TagLib_File *file)
{
return reinterpret_cast<File *>(file)->save();
return reinterpret_cast<FileRef *>(file)->save();
}
////////////////////////////////////////////////////////////////////////////////

View File

@@ -124,7 +124,7 @@ TAGLIB_C_EXPORT TagLib_File *taglib_file_new_type(const char *filename, TagLib_F
TAGLIB_C_EXPORT void taglib_file_free(TagLib_File *file);
/*!
* Returns true if the file is open and readble and valid information for
* Returns true if the file is open and readable and valid information for
* the Tag and / or AudioProperties was found.
*/
@@ -137,7 +137,7 @@ TAGLIB_C_EXPORT BOOL taglib_file_is_valid(const TagLib_File *file);
TAGLIB_C_EXPORT TagLib_Tag *taglib_file_tag(const TagLib_File *file);
/*!
* Returns a pointer to the the audio properties associated with this file. This
* Returns a pointer to the audio properties associated with this file. This
* will be freed automatically when the file is freed.
*/
TAGLIB_C_EXPORT const TagLib_AudioProperties *taglib_file_audioproperties(const TagLib_File *file);

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

@@ -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

@@ -1,7 +1,14 @@
/* config.h. Generated by cmake from config.h.cmake */
#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_BOOST_BYTESWAP 1
#cmakedefine HAVE_GCC_BYTESWAP 1
#cmakedefine HAVE_GLIBC_BYTESWAP 1
#cmakedefine HAVE_MSC_BYTESWAP 1
@@ -10,12 +17,14 @@
/* Defined if your compiler supports some atomic operations */
#cmakedefine HAVE_STD_ATOMIC 1
#cmakedefine HAVE_BOOST_ATOMIC 1
#cmakedefine HAVE_GCC_ATOMIC 1
#cmakedefine HAVE_MAC_ATOMIC 1
#cmakedefine HAVE_WIN_ATOMIC 1
#cmakedefine HAVE_IA64_ATOMIC 1
/* Defined if your compiler supports 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
@@ -25,9 +34,10 @@
/* Defined if zlib is installed */
#cmakedefine HAVE_ZLIB 1
#cmakedefine HAVE_BOOST_ZLIB 1
/* Indicates whether debug messages are shown even in release mode */
#cmakedefine TRACE_IN_RELEASE 1
#cmakedefine TESTS_DIR "@TESTS_DIR@"
#endif

View File

@@ -37,3 +37,7 @@ target_link_libraries(framelist tag)
add_executable(strip-id3v1 strip-id3v1.cpp)
target_link_libraries(strip-id3v1 tag)
########### next target ###############
add_executable(inspect inspect.cpp)
target_link_libraries(inspect tag)

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

@@ -28,6 +28,7 @@
#include <fileref.h>
#include <tag.h>
#include <tpicturemap.h>
#include <tpropertymap.h>
using namespace std;
@@ -45,13 +46,15 @@ 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.file()->properties();

View File

@@ -22,8 +22,10 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <fstream>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string.h>
#include <stdio.h>
@@ -34,6 +36,8 @@
#include <tlist.h>
#include <fileref.h>
#include <tfile.h>
#include <tpicturemap.h>
#include <tag.h>
#include <tpropertymap.h>
@@ -70,6 +74,7 @@ void usage()
cout << " -R <tagname> <tagvalue>" << endl;
cout << " -I <tagname> <tagvalue>" << endl;
cout << " -D <tagname>" << endl;
cout << " -p <picture(jpg only, file between double quotes)>" << endl;
cout << endl;
exit(1);
@@ -110,14 +115,16 @@ int main(int argc, char *argv[])
if(fileList.isEmpty())
usage();
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];
TagLib::List<TagLib::FileRef>::ConstIterator it;
TagLib::List<TagLib::FileRef>::Iterator it;
for(it = fileList.begin(); it != fileList.end(); ++it) {
TagLib::Tag *t = (*it).tag();
@@ -167,6 +174,31 @@ int main(int argc, char *argv[])
checkForRejectedProperties((*it).file()->setProperties(map));
break;
}
case 'p':
{
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));
if(!data.find("JFIF")) {
cout << value.toCString() << " is not a JPEG." << endl;
return 1;
}
TagLib::Picture pic(data,
TagLib::Picture::FrontCover,
"image/jpeg",
"Added with taglib");
TagLib::PictureMap picMap(pic);
t->setPictures(picMap);
}
break;
default:
usage();
break;

View File

@@ -1,36 +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${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
@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

@@ -24,6 +24,11 @@ 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)
@@ -32,21 +37,17 @@ elseif(HAVE_ZLIB_SOURCE)
include_directories(${ZLIB_SOURCE})
endif()
if(HAVE_BOOST_BYTESWAP OR HAVE_BOOST_ATOMIC OR HAVE_BOOST_ZLIB)
include_directories(${Boost_INCLUDE_DIR})
endif()
set(tag_HDRS
tag.h
fileref.h
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/tbytevectorstream.h
@@ -55,6 +56,8 @@ set(tag_HDRS
toolkit/tfilestream.h
toolkit/tmap.h
toolkit/tmap.tcc
toolkit/tpicture.h
toolkit/tpicturemap.h
toolkit/tpropertymap.h
toolkit/trefcounter.h
toolkit/tdebuglistener.h
@@ -141,6 +144,17 @@ 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
dsdiff/dsdiffproperties.h
dsdiff/dsdiffdiintag.h
)
set(mpeg_SRCS
@@ -296,9 +310,32 @@ set(xm_SRCS
xm/xmproperties.cpp
)
set(dsf_SRCS
dsf/dsffile.cpp
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
dsdiff/dsdiffdiintag.cpp
)
set(toolkit_SRCS
toolkit/taglib.cpp
toolkit/tstring.cpp
toolkit/tstringlist.cpp
toolkit/tstringhandler.cpp
toolkit/tbytevector.cpp
toolkit/tbytevectorlist.cpp
toolkit/tbytevectorstream.cpp
@@ -306,18 +343,14 @@ set(toolkit_SRCS
toolkit/tfile.cpp
toolkit/tfilestream.cpp
toolkit/tdebug.cpp
toolkit/tpicture.cpp
toolkit/tpicturemap.cpp
toolkit/tpropertymap.cpp
toolkit/trefcounter.cpp
toolkit/tdebuglistener.cpp
toolkit/tzlib.cpp
)
if(NOT WIN32)
set(unicode_SRCS
toolkit/unicode.cpp
)
endif()
if(HAVE_ZLIB_SOURCE)
set(zlib_SRCS
${ZLIB_SOURCE}/adler32.c
@@ -334,7 +367,8 @@ set(tag_LIB_SRCS
${vorbis_SRCS} ${oggflacs_SRCS} ${mpc_SRCS} ${ape_SRCS} ${toolkit_SRCS} ${flacs_SRCS}
${wavpack_SRCS} ${speex_SRCS} ${trueaudio_SRCS} ${riff_SRCS} ${aiff_SRCS} ${wav_SRCS}
${asf_SRCS} ${mp4_SRCS} ${mod_SRCS} ${s3m_SRCS} ${it_SRCS} ${xm_SRCS} ${opus_SRCS}
${unicode_SRCS} ${zlib_SRCS}
${ebml_SRCS} ${matroska_SRCS} ${dsf_SRCS} ${dsdiff_SRCS}
${zlib_SRCS}
tag.cpp
tagunion.cpp
fileref.cpp
@@ -344,18 +378,10 @@ set(tag_LIB_SRCS
add_library(tag ${tag_LIB_SRCS} ${tag_HDRS})
if(ZLIB_FOUND)
if(HAVE_ZLIB AND NOT HAVE_ZLIB_SOURCE)
target_link_libraries(tag ${ZLIB_LIBRARIES})
endif()
if(HAVE_BOOST_ATOMIC)
target_link_libraries(tag ${Boost_ATOMIC_LIBRARY})
endif()
if(HAVE_BOOST_ZLIB)
target_link_libraries(tag ${Boost_IOSTREAMS_LIBRARY} ${Boost_ZLIB_LIBRARY})
endif()
set_target_properties(tag PROPERTIES
VERSION ${TAGLIB_SOVERSION_MAJOR}.${TAGLIB_SOVERSION_MINOR}.${TAGLIB_SOVERSION_PATCH}
SOVERSION ${TAGLIB_SOVERSION_MAJOR}
@@ -364,8 +390,19 @@ set_target_properties(tag PROPERTIES
LINK_INTERFACE_LIBRARIES ""
PUBLIC_HEADER "${tag_HDRS}"
)
if(VISIBILITY_HIDDEN)
set_target_properties(tag PROPERTIES C_VISIBILITY_PRESET hidden
)
endif()
if(BUILD_FRAMEWORK)
set_target_properties(tag PROPERTIES FRAMEWORK TRUE)
unset(INSTALL_NAME_DIR)
set_target_properties(tag PROPERTIES
FRAMEWORK TRUE
MACOSX_RPATH 1
VERSION "A"
SOVERSION "A"
)
endif()
install(TARGETS tag

View File

@@ -39,6 +39,7 @@
#include <id3v2header.h>
#include <tpropertymap.h>
#include <tagutils.h>
#include <tsmartptr.h>
#include "apefile.h"
#include "apetag.h"
@@ -58,36 +59,40 @@ public:
APELocation(-1),
APESize(0),
ID3v1Location(-1),
ID3v2Header(0),
ID3v2Location(-1),
ID3v2Size(0),
properties(0) {}
ID3v2Size(0) {}
~FilePrivate()
{
delete ID3v2Header;
delete properties;
}
long long APELocation;
long long APESize;
long APELocation;
long APESize;
long long ID3v1Location;
long ID3v1Location;
SCOPED_PTR<ID3v2::Header> ID3v2Header;
long long ID3v2Location;
long long ID3v2Size;
ID3v2::Header *ID3v2Header;
long ID3v2Location;
long ID3v2Size;
DoubleTagUnion tag;
TagUnion tag;
Properties *properties;
SCOPED_PTR<AudioProperties> properties;
};
////////////////////////////////////////////////////////////////////////////////
// static members
////////////////////////////////////////////////////////////////////////////////
bool APE::File::isSupported(IOStream *stream)
{
// An APE file has an ID "MAC " somewhere. An ID3v2 tag may precede.
const ByteVector buffer = Utils::readHeader(stream, bufferSize(), true);
return (buffer.find("MAC ") != 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(new FilePrivate())
{
@@ -95,7 +100,7 @@ APE::File::File(FileName file, bool readProperties, Properties::ReadStyle) :
read(readProperties);
}
APE::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle) :
APE::File::File(IOStream *stream, bool readProperties, AudioProperties::ReadStyle) :
TagLib::File(stream),
d(new FilePrivate())
{
@@ -113,16 +118,6 @@ 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())
@@ -131,9 +126,9 @@ 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;
return d->properties.get();
}
bool APE::File::save()
@@ -183,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);
@@ -195,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;
@@ -252,7 +247,7 @@ void APE::File::read(bool readProperties)
if(d->ID3v2Location >= 0) {
seek(d->ID3v2Location);
d->ID3v2Header = new ID3v2::Header(readBlock(ID3v2::Header::size()));
d->ID3v2Header.reset(new ID3v2::Header(readBlock(ID3v2::Header::size())));
d->ID3v2Size = d->ID3v2Header->completeTagSize();
}
@@ -280,7 +275,7 @@ void APE::File::read(bool readProperties)
if(readProperties) {
long streamLength;
long long streamLength;
if(d->APELocation >= 0)
streamLength = d->APELocation;
@@ -297,6 +292,6 @@ void APE::File::read(bool readProperties)
seek(0);
}
d->properties = new 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,7 +102,7 @@ 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.
@@ -115,31 +115,18 @@ namespace TagLib {
*/
virtual TagLib::Tag *tag() const;
/*!
* Implements the unified property interface -- export function.
* If the file contains both an APE and an ID3v1 tag, only APE
* will be converted to the PropertyMap.
*/
PropertyMap properties() const;
/*!
* Removes unsupported properties. Forwards to the actual Tag's
* removeUnsupportedProperties() function.
*/
void removeUnsupportedProperties(const StringList &properties);
/*!
* Implements the unified property interface -- import function.
* Creates an APEv2 tag if necessary. A potentially existing ID3v1
* tag will be updated as well.
*/
PropertyMap setProperties(const PropertyMap &);
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.
*/
virtual Properties *audioProperties() const;
virtual AudioProperties *audioProperties() const;
/*!
* Saves the file.
@@ -211,6 +198,15 @@ namespace TagLib {
*/
bool hasID3v1Tag() const;
/*!
* Returns whether or not the given \a stream can be opened as an APE
* file.
*
* \note This method is designed to do a quick check. The result may
* not necessarily be correct.
*/
static bool isSupported(IOStream *stream);
private:
File(const File &);
File &operator=(const File &);

View File

@@ -175,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];
@@ -206,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
@@ -224,11 +224,11 @@ ByteVector APE::Footer::render(bool isHeader) const
flags[30] = false; // footer is always present
flags[29] = isHeader;
v.append(ByteVector::fromUInt(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,7 +54,7 @@ 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.

View File

@@ -25,17 +25,17 @@
#include <tbytevectorlist.h>
#include <tdebug.h>
#include <tsmartptr.h>
#include "apeitem.h"
using namespace TagLib;
using namespace APE;
class APE::Item::ItemPrivate
struct ItemData
{
public:
ItemPrivate() :
type(Text),
ItemData() :
type(Item::Text),
readOnly(false) {}
Item::ItemTypes type;
@@ -45,6 +45,15 @@ public:
bool readOnly;
};
class APE::Item::ItemPrivate
{
public:
ItemPrivate() :
data(new ItemData()) {}
SHARED_PTR<ItemData> data;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
@@ -57,27 +66,27 @@ APE::Item::Item() :
APE::Item::Item(const String &key, const String &value) :
d(new ItemPrivate())
{
d->key = key;
d->text.append(value);
d->data->key = key;
d->data->text.append(value);
}
APE::Item::Item(const String &key, const StringList &values) :
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(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);
}
}
@@ -106,135 +115,122 @@ void APE::Item::swap(Item &item)
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();
}
ByteVector APE::Item::value() const
{
// This seems incorrect as it won't be actually rendering the value to keep it
// up to date.
return d->value;
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()) {
StringList::ConstIterator it = d->text.begin();
if(!d->data->text.isEmpty()) {
StringList::ConstIterator it = d->data->text.begin();
result += it->data(String::UTF8).size();
it++;
for(; it != d->text.end(); ++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;
}
StringList APE::Item::toStringList() const
{
return d->text;
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();
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;
if(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;
}
@@ -249,51 +245,51 @@ 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 value = data.mid(8 + d->key.size() + 1, valueLength);
const ByteVector value = data.mid(8 + d->data->key.size() + 1, valueLength);
setReadOnly(flags & 1);
setType(ItemTypes((flags >> 1) & 3));
if(Text == d->type)
d->text = StringList(ByteVectorList::split(value, '\0'), String::UTF8);
if(Text == d->data->type)
d->data->text = StringList(ByteVectorList::split(value, '\0'), String::UTF8);
else
d->value = value;
d->data->value = value;
}
ByteVector APE::Item::render() const
{
ByteVector data;
unsigned int flags = ((d->readOnly) ? 1 : 0) | (d->type << 1);
unsigned int flags = ((d->data->readOnly) ? 1 : 0) | (d->data->type << 1);
ByteVector value;
if(isEmpty())
return data;
if(d->type == Text) {
StringList::ConstIterator it = d->text.begin();
if(d->data->type == Text) {
StringList::ConstIterator it = d->data->text.begin();
value.append(it->data(String::UTF8));
it++;
for(; it != d->text.end(); ++it) {
for(; it != d->data->text.end(); ++it) {
value.append('\0');
value.append(it->data(String::UTF8));
}
d->value = value;
d->data->value = value;
}
else
value.append(d->value);
value.append(d->data->value);
data.append(ByteVector::fromUInt(value.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(value);

View File

@@ -61,7 +61,6 @@ namespace TagLib {
/*!
* Constructs a text item with \a key and \a value.
*/
// BIC: Remove this, StringList has a constructor from a single string
Item(const String &key, const String &value);
/*!
@@ -112,11 +111,6 @@ namespace TagLib {
*/
void setBinaryData(const ByteVector &value);
#ifndef DO_NOT_DOCUMENT
/* Remove in next binary incompatible release */
ByteVector value() const;
#endif
/*!
* Sets the key for the item to \a key.
*/
@@ -163,11 +157,6 @@ namespace TagLib {
*/
String toString() const;
#ifndef DO_NOT_DOCUMENT
/* Remove in next binary incompatible release */
StringList toStringList() const;
#endif
/*!
* Returns the list of text values. If the data type is not \a Text, always
* returns an empty StringList.

View File

@@ -29,7 +29,7 @@
#include <tstring.h>
#include <tdebug.h>
#include <bitset>
#include "id3v2tag.h"
#include "apeproperties.h"
#include "apefile.h"
@@ -38,7 +38,7 @@
using namespace TagLib;
class APE::Properties::PropertiesPrivate
class APE::AudioProperties::PropertiesPrivate
{
public:
PropertiesPrivate() :
@@ -63,66 +63,59 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
APE::Properties::Properties(File *, ReadStyle style) :
AudioProperties(style),
d(new PropertiesPrivate())
{
debug("APE::Properties::Properties() -- This constructor is no longer used.");
}
APE::Properties::Properties(File *file, long streamLength, ReadStyle style) :
AudioProperties(style),
APE::AudioProperties::AudioProperties(File *file, long long streamLength, ReadStyle) :
TagLib::AudioProperties(),
d(new PropertiesPrivate())
{
read(file, streamLength);
}
APE::Properties::~Properties()
APE::AudioProperties::~AudioProperties()
{
delete d;
}
int APE::Properties::length() const
int APE::AudioProperties::length() const
{
return lengthInSeconds();
}
int APE::Properties::lengthInSeconds() const
int APE::AudioProperties::lengthInSeconds() const
{
return d->length / 1000;
}
int APE::Properties::lengthInMilliseconds() const
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;
}
@@ -138,14 +131,14 @@ namespace
if(header.size() < 6 || !header.startsWith("MAC "))
return -1;
return header.toUShort(4, false);
return header.toUInt16LE(4);
}
}
void APE::Properties::read(File *file, long streamLength)
void APE::AudioProperties::read(File *file, long long streamLength)
{
// First, we assume that the file pointer is set at the first descriptor.
long offset = file->tell();
long long offset = file->tell();
int version = headerVersion(file->readBlock(6));
// Next, we look for the descriptor.
@@ -156,7 +149,7 @@ void APE::Properties::read(File *file, long streamLength)
}
if(version < 0) {
debug("APE::Properties::read() -- APE descriptor not found");
debug("APE::AudioProperties::read() -- APE descriptor not found");
return;
}
@@ -174,17 +167,17 @@ void APE::Properties::read(File *file, long 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);
@@ -192,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;
@@ -234,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

@@ -46,27 +46,19 @@ 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.
*
* \deprecated
*/
Properties(File *file, ReadStyle style = Average);
AudioProperties(File *file, long long streamLength, ReadStyle style = Average);
/*!
* Create an instance of APE::Properties with the data read from the
* APE::File \a file.
* Destroys this APE::AudioProperties instance.
*/
Properties(File *file, long streamLength, ReadStyle style = Average);
/*!
* Destroys this APE::Properties instance.
*/
virtual ~Properties();
virtual ~AudioProperties();
/*!
* Returns the length of the file in seconds. The length is rounded down to
@@ -84,16 +76,14 @@ namespace TagLib {
*
* \see lengthInMilliseconds()
*/
// BIC: make virtual
int lengthInSeconds() const;
virtual int lengthInSeconds() const;
/*!
* Returns the length of the file in milliseconds.
*
* \see lengthInSeconds()
*/
// BIC: make virtual
int lengthInMilliseconds() const;
virtual int lengthInMilliseconds() const;
/*!
* Returns the average bit rate of the file in kb/s.
@@ -126,11 +116,7 @@ namespace TagLib {
int version() const;
private:
Properties(const Properties &);
Properties &operator=(const Properties &);
void read(File *file, long streamLength);
void read(File *file, long long streamLength);
void analyzeCurrent(File *file);
void analyzeOld(File *file);

View File

@@ -34,6 +34,7 @@
#include <tfile.h>
#include <tstring.h>
#include <tmap.h>
#include <tpicturemap.h>
#include <tpropertymap.h>
#include <tdebug.h>
#include <tutils.h>
@@ -47,23 +48,24 @@ using namespace APE;
namespace
{
bool isKeyValid(const char *key, size_t length)
const unsigned int MinKeyLength = 2;
const unsigned int MaxKeyLength = 255;
bool isKeyValid(const ByteVector &key)
{
const char *invalidKeys[] = { "ID3", "TAG", "OGGS", "MP+", 0 };
if(length < 2 || length > 16)
return false;
// only allow printable ASCII including space (32..126)
for(const char *p = key; p < key + length; ++p) {
const int c = static_cast<unsigned char>(*p);
for(ByteVector::ConstIterator it = key.begin(); it != key.end(); ++it) {
const int c = static_cast<unsigned char>(*it);
if(c < 32 || c > 126)
return false;
}
const String upperKey = String(key).upper();
for(size_t i = 0; invalidKeys[i] != 0; ++i) {
if(Utils::equalsIgnoreCase(key, invalidKeys[i]))
if(upperKey == invalidKeys[i])
return false;
}
@@ -79,7 +81,7 @@ public:
footerLocation(0) {}
File *file;
long footerLocation;
long long footerLocation;
Footer footer;
ItemListMap itemListMap;
@@ -95,7 +97,7 @@ APE::Tag::Tag() :
{
}
APE::Tag::Tag(TagLib::File *file, long footerLocation) :
APE::Tag::Tag(TagLib::File *file, long long footerLocation) :
TagLib::Tag(),
d(new TagPrivate())
{
@@ -164,6 +166,42 @@ unsigned int APE::Tag::track() const
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)
{
addValue("TITLE", s, true);
@@ -191,7 +229,7 @@ void APE::Tag::setGenre(const String &s)
void APE::Tag::setYear(unsigned int i)
{
if(i <= 0)
if(i == 0)
removeItem("YEAR");
else
addValue("YEAR", String::number(i), true);
@@ -199,12 +237,69 @@ void APE::Tag::setYear(unsigned int i)
void APE::Tag::setTrack(unsigned int i)
{
if(i <= 0)
if(i == 0)
removeItem("TRACK");
else
addValue("TRACK", String::number(i), true);
}
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
@@ -235,7 +330,7 @@ PropertyMap APE::Tag::properties() const
if(tagName == keyConversions[i][1])
tagName = keyConversions[i][0];
}
properties[tagName].append(it->second.toStringList());
properties[tagName].append(it->second.values());
}
}
return properties;
@@ -296,11 +391,10 @@ PropertyMap APE::Tag::setProperties(const PropertyMap &origProps)
bool APE::Tag::checkKey(const String &key)
{
if(!key.isLatin1())
if(key.size() < MinKeyLength || key.size() > MaxKeyLength)
return false;
const std::string data = key.to8Bit(false);
return isKeyValid(data.c_str(), data.size());
return isKeyValid(key.data(String::UTF8));
}
APE::Footer *APE::Tag::footer() const
@@ -393,7 +487,7 @@ ByteVector APE::Tag::render() const
}
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();
@@ -406,20 +500,23 @@ 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 valLegnth = data.toUInt(pos, false);
const size_t keyLength = nullPos - pos - 8;
const size_t valLegnth = data.toUInt32LE(pos);
if(isKeyValid(&data[pos + 8], keyLength)){
if(keyLength >= MinKeyLength
&& keyLength <= MaxKeyLength
&& isKeyValid(data.mid(pos + 8, keyLength)))
{
APE::Item item;
item.parse(data.mid(pos));

View File

@@ -34,6 +34,9 @@
#include "apeitem.h"
#define FRONT_COVER "COVER ART (FRONT)"
#define BACK_COVER "COVER ART (BACK)"
namespace TagLib {
class File;
@@ -49,7 +52,7 @@ namespace TagLib {
*
* \see APE::Tag::itemListMap()
*/
typedef Map<const String, Item> ItemListMap;
typedef Map<String, Item> ItemListMap;
//! An APE tag implementation
@@ -66,7 +69,7 @@ namespace TagLib {
* Create an APE tag and parse the data in \a file with APE footer at
* \a tagOffset.
*/
Tag(TagLib::File *file, long footerLocation);
Tag(TagLib::File *file, long long footerLocation);
/*!
* Destroys this Tag instance.
@@ -95,6 +98,15 @@ namespace TagLib {
virtual unsigned int year() const;
virtual unsigned int track() const;
/**
* @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);
@@ -102,6 +114,7 @@ namespace TagLib {
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.

View File

@@ -1,4 +1,4 @@
/**************************************************************************
/**************************************************************************
copyright : (C) 2005-2007 by Lukáš Lalinský
email : lalinsky@gmail.com
**************************************************************************/
@@ -25,7 +25,7 @@
#include <taglib.h>
#include <tdebug.h>
#include <trefcounter.h>
#include <tsmartptr.h>
#include "asfattribute.h"
#include "asffile.h"
@@ -33,25 +33,35 @@
using namespace TagLib;
class ASF::Attribute::AttributePrivate : public RefCounter
namespace
{
public:
AttributePrivate()
: pictureValue(ASF::Picture::fromInvalid()),
struct AttributeData
{
AttributeData() :
numericValue(0),
stream(0),
language(0) {}
AttributeTypes type;
String stringValue;
ByteVector byteVectorValue;
ASF::Picture pictureValue;
union {
unsigned int intValue;
unsigned short shortValue;
unsigned long long longLongValue;
bool boolValue;
ASF::Attribute::AttributeTypes type;
String stringValue;
ByteVector byteVectorValue;
ASF::Picture pictureValue;
unsigned long long numericValue;
int stream;
int language;
};
int stream;
int language;
}
class ASF::Attribute::AttributePrivate
{
public:
AttributePrivate() :
data(new AttributeData())
{
data->pictureValue = ASF::Picture::fromInvalid();
}
SHARED_PTR<AttributeData> data;
};
////////////////////////////////////////////////////////////////////////////////
@@ -61,62 +71,61 @@ public:
ASF::Attribute::Attribute() :
d(new AttributePrivate())
{
d->type = UnicodeType;
d->data->type = UnicodeType;
}
ASF::Attribute::Attribute(const ASF::Attribute &other) :
d(other.d)
d(new AttributePrivate(*other.d))
{
d->ref();
}
ASF::Attribute::Attribute(const String &value) :
d(new AttributePrivate())
{
d->type = UnicodeType;
d->stringValue = value;
d->data->type = UnicodeType;
d->data->stringValue = value;
}
ASF::Attribute::Attribute(const ByteVector &value) :
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(new AttributePrivate())
{
d->type = BytesType;
d->pictureValue = value;
d->data->type = BytesType;
d->data->pictureValue = value;
}
ASF::Attribute::Attribute(unsigned int value) :
d(new AttributePrivate())
{
d->type = DWordType;
d->intValue = value;
d->data->type = DWordType;
d->data->numericValue = value;
}
ASF::Attribute::Attribute(unsigned long long value) :
d(new AttributePrivate())
{
d->type = QWordType;
d->longLongValue = value;
d->data->type = QWordType;
d->data->numericValue = value;
}
ASF::Attribute::Attribute(unsigned short value) :
d(new AttributePrivate())
{
d->type = WordType;
d->shortValue = value;
d->data->type = WordType;
d->data->numericValue = value;
}
ASF::Attribute::Attribute(bool value) :
d(new AttributePrivate())
{
d->type = BoolType;
d->boolValue = value;
d->data->type = BoolType;
d->data->numericValue = value;
}
ASF::Attribute &ASF::Attribute::operator=(const ASF::Attribute &other)
@@ -134,62 +143,62 @@ void ASF::Attribute::swap(Attribute &other)
ASF::Attribute::~Attribute()
{
if(d->deref())
delete d;
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->shortValue;
return d->data->numericValue ? 1 : 0;
}
unsigned short ASF::Attribute::toUShort() const
{
return d->shortValue;
return static_cast<unsigned short>(d->data->numericValue);
}
unsigned int ASF::Attribute::toUInt() const
{
return d->intValue;
return static_cast<unsigned int>(d->data->numericValue);
}
unsigned long long ASF::Attribute::toULongLong() const
{
return d->longLongValue;
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 = ASF::Attribute::AttributeTypes(readWORD(&f));
d->data->type = ASF::Attribute::AttributeTypes(readWORD(&f));
size = readWORD(&f);
}
// metadata & metadata library
@@ -197,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 = ASF::Attribute::AttributeTypes(readWORD(&f));
d->data->type = ASF::Attribute::AttributeTypes(readWORD(&f));
size = readDWORD(&f);
name = readString(&f, nameLength);
}
@@ -210,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->shortValue = readWORD(&f);
d->data->numericValue = readWORD(&f);
break;
case BoolType:
if(kind == 0) {
d->boolValue = (readDWORD(&f) == 1);
d->data->numericValue = (readDWORD(&f) != 0);
}
else {
d->boolValue = (readWORD(&f) == 1);
d->data->numericValue = (readWORD(&f) != 0);
}
break;
case DWordType:
d->intValue = readDWORD(&f);
d->data->numericValue = readDWORD(&f);
break;
case QWordType:
d->longLongValue = 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();
}
}
@@ -254,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:
@@ -264,12 +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();
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;
}
@@ -278,55 +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(d->shortValue, false));
data.append(ByteVector::fromUInt16LE(toUShort()));
break;
case BoolType:
if(kind == 0) {
data.append(ByteVector::fromUInt(d->boolValue ? 1 : 0, false));
data.append(ByteVector::fromUInt32LE(toBool()));
}
else {
data.append(ByteVector::fromShort(d->boolValue ? 1 : 0, false));
data.append(ByteVector::fromUInt16LE(toBool()));
}
break;
case DWordType:
data.append(ByteVector::fromUInt(d->intValue, false));
data.append(ByteVector::fromUInt32LE(toUInt()));
break;
case QWordType:
data.append(ByteVector::fromLongLong(d->longLongValue, 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;
}
case GuidType:
data.append(d->byteVectorValue);
data.append(d->data->byteVectorValue);
break;
}
if(kind == 0) {
data = renderString(name, true) +
ByteVector::fromShort((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((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;
}
@@ -336,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

@@ -36,7 +36,6 @@ namespace TagLib
namespace ASF
{
class File;
class Picture;
@@ -113,7 +112,7 @@ namespace TagLib
/*!
* Copies the contents of \a other into this item.
*/
ASF::Attribute &operator=(const Attribute &other);
Attribute &operator=(const Attribute &other);
/*!
* Exchanges the content of the Attribute by the content of \a other.
@@ -185,17 +184,13 @@ 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;

View File

@@ -27,6 +27,8 @@
#include <tbytevectorlist.h>
#include <tpropertymap.h>
#include <tstring.h>
#include <tagutils.h>
#include <tsmartptr.h>
#include "asffile.h"
#include "asftag.h"
@@ -49,37 +51,24 @@ public:
class MetadataObject;
class MetadataLibraryObject;
FilePrivate():
headerSize(0),
tag(0),
properties(0),
contentDescriptionObject(0),
extendedContentDescriptionObject(0),
headerExtensionObject(0),
metadataObject(0),
metadataLibraryObject(0)
{
objects.setAutoDelete(true);
}
typedef List<SHARED_PTR<BaseObject> > ObjectList;
typedef ObjectList::ConstIterator ObjectConstIterator;
~FilePrivate()
{
delete tag;
delete properties;
}
FilePrivate():
headerSize(0) {}
unsigned long long headerSize;
ASF::Tag *tag;
ASF::Properties *properties;
SCOPED_PTR<ASF::Tag> tag;
SCOPED_PTR<ASF::AudioProperties> properties;
List<BaseObject *> objects;
ObjectList objects;
ContentDescriptionObject *contentDescriptionObject;
ExtendedContentDescriptionObject *extendedContentDescriptionObject;
HeaderExtensionObject *headerExtensionObject;
MetadataObject *metadataObject;
MetadataLibraryObject *metadataLibraryObject;
SHARED_PTR<ContentDescriptionObject> contentDescriptionObject;
SHARED_PTR<ExtendedContentDescriptionObject> extendedContentDescriptionObject;
SHARED_PTR<HeaderExtensionObject> headerExtensionObject;
SHARED_PTR<MetadataObject> metadataObject;
SHARED_PTR<MetadataLibraryObject> metadataLibraryObject;
};
namespace
@@ -112,7 +101,7 @@ class ASF::File::FilePrivate::UnknownObject : public ASF::File::FilePrivate::Bas
{
ByteVector myGuid;
public:
UnknownObject(const ByteVector &guid);
explicit UnknownObject(const ByteVector &guid);
ByteVector guid() const;
};
@@ -168,7 +157,7 @@ public:
class ASF::File::FilePrivate::HeaderExtensionObject : public ASF::File::FilePrivate::BaseObject
{
public:
List<ASF::File::FilePrivate::BaseObject *> objects;
ObjectList objects;
HeaderExtensionObject();
ByteVector guid() const;
void parse(ASF::File *file, unsigned int size);
@@ -193,7 +182,7 @@ private:
void ASF::File::FilePrivate::BaseObject::parse(ASF::File *file, unsigned int size)
{
data.clear();
if(size > 24 && size <= (unsigned int)(file->length()))
if(size > 24 && static_cast<long long>(size) <= file->length())
data = file->readBlock(size - 24);
else
data = ByteVector();
@@ -201,7 +190,7 @@ void ASF::File::FilePrivate::BaseObject::parse(ASF::File *file, unsigned int siz
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)
@@ -226,8 +215,8 @@ void ASF::File::FilePrivate::FilePropertiesObject::parse(ASF::File *file, unsign
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));
}
@@ -244,11 +233,11 @@ void ASF::File::FilePrivate::StreamPropertiesObject::parse(ASF::File *file, unsi
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
@@ -258,7 +247,6 @@ ByteVector ASF::File::FilePrivate::ContentDescriptionObject::guid() const
void ASF::File::FilePrivate::ContentDescriptionObject::parse(ASF::File *file, unsigned int /*size*/)
{
file->d->contentDescriptionObject = this;
const int titleLength = readWORD(file);
const int artistLength = readWORD(file);
const int copyrightLength = readWORD(file);
@@ -279,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);
@@ -299,7 +287,6 @@ ByteVector ASF::File::FilePrivate::ExtendedContentDescriptionObject::guid() cons
void ASF::File::FilePrivate::ExtendedContentDescriptionObject::parse(ASF::File *file, unsigned int /*size*/)
{
file->d->extendedContentDescriptionObject = this;
int count = readWORD(file);
while(count--) {
ASF::Attribute attribute;
@@ -311,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);
}
@@ -323,7 +310,6 @@ ByteVector ASF::File::FilePrivate::MetadataObject::guid() const
void ASF::File::FilePrivate::MetadataObject::parse(ASF::File *file, unsigned int /*size*/)
{
file->d->metadataObject = this;
int count = readWORD(file);
while(count--) {
ASF::Attribute attribute;
@@ -335,7 +321,7 @@ void ASF::File::FilePrivate::MetadataObject::parse(ASF::File *file, unsigned int
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);
}
@@ -347,7 +333,6 @@ ByteVector ASF::File::FilePrivate::MetadataLibraryObject::guid() const
void ASF::File::FilePrivate::MetadataLibraryObject::parse(ASF::File *file, unsigned int /*size*/)
{
file->d->metadataLibraryObject = this;
int count = readWORD(file);
while(count--) {
ASF::Attribute attribute;
@@ -359,14 +344,13 @@ void ASF::File::FilePrivate::MetadataLibraryObject::parse(ASF::File *file, unsig
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
@@ -376,7 +360,6 @@ ByteVector ASF::File::FilePrivate::HeaderExtensionObject::guid() const
void ASF::File::FilePrivate::HeaderExtensionObject::parse(ASF::File *file, unsigned int /*size*/)
{
file->d->headerExtensionObject = this;
file->seek(18, File::Current);
long long dataSize = readDWORD(file);
long long dataPos = 0;
@@ -392,15 +375,17 @@ void ASF::File::FilePrivate::HeaderExtensionObject::parse(ASF::File *file, unsig
file->setValid(false);
break;
}
BaseObject *obj;
SHARED_PTR<BaseObject> obj;
if(guid == metadataGuid) {
obj = new MetadataObject();
file->d->metadataObject.reset(new MetadataObject());
obj = file->d->metadataObject;
}
else if(guid == metadataLibraryGuid) {
obj = new MetadataLibraryObject();
file->d->metadataLibraryObject.reset(new MetadataLibraryObject());
obj = file->d->metadataLibraryObject;
}
else {
obj = new UnknownObject(guid);
obj.reset(new UnknownObject(guid));
}
obj->parse(file, (unsigned int)size);
objects.append(obj);
@@ -411,10 +396,10 @@ void ASF::File::FilePrivate::HeaderExtensionObject::parse(ASF::File *file, unsig
ByteVector ASF::File::FilePrivate::HeaderExtensionObject::render(ASF::File *file)
{
data.clear();
for(List<BaseObject *>::ConstIterator it = objects.begin(); it != objects.end(); ++it) {
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);
}
@@ -433,7 +418,7 @@ void ASF::File::FilePrivate::CodecListObject::parse(ASF::File *file, unsigned in
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) {
@@ -441,22 +426,22 @@ void ASF::File::FilePrivate::CodecListObject::parse(ASF::File *file, unsigned in
if(pos >= data.size())
break;
const CodecType 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) {
@@ -473,11 +458,23 @@ void ASF::File::FilePrivate::CodecListObject::parse(ASF::File *file, unsigned in
}
}
////////////////////////////////////////////////////////////////////////////////
// static members
////////////////////////////////////////////////////////////////////////////////
bool ASF::File::isSupported(IOStream *stream)
{
// An ASF file has to start with the designated GUID.
const ByteVector id = Utils::readHeader(stream, 16, false);
return (id == headerGuid);
}
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
ASF::File::File(FileName file, bool, Properties::ReadStyle) :
ASF::File::File(FileName file, bool, AudioProperties::ReadStyle) :
TagLib::File(file),
d(new FilePrivate())
{
@@ -485,7 +482,7 @@ ASF::File::File(FileName file, bool, Properties::ReadStyle) :
read();
}
ASF::File::File(IOStream *stream, bool, Properties::ReadStyle) :
ASF::File::File(IOStream *stream, bool, AudioProperties::ReadStyle) :
TagLib::File(stream),
d(new FilePrivate())
{
@@ -500,27 +497,12 @@ ASF::File::~File()
ASF::Tag *ASF::File::tag() const
{
return d->tag;
return d->tag.get();
}
PropertyMap ASF::File::properties() const
ASF::AudioProperties *ASF::File::audioProperties() const
{
return d->tag->properties();
}
void ASF::File::removeUnsupportedProperties(const StringList &properties)
{
d->tag->removeUnsupportedProperties(properties);
}
PropertyMap ASF::File::setProperties(const PropertyMap &properties)
{
return d->tag->setProperties(properties);
}
ASF::Properties *ASF::File::audioProperties() const
{
return d->properties;
return d->properties.get();
}
bool ASF::File::save()
@@ -536,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);
}
@@ -591,16 +573,16 @@ bool ASF::File::save()
}
ByteVector data;
for(List<FilePrivate::BaseObject *>::ConstIterator it = d->objects.begin(); it != d->objects.end(); ++it) {
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;
@@ -616,15 +598,14 @@ void ASF::File::read()
if(!isValid())
return;
ByteVector guid = readBlock(16);
if(guid != headerGuid) {
debug("ASF: Not an ASF file.");
if(readBlock(16) != headerGuid) {
debug("ASF::File::read(): Not an ASF file.");
setValid(false);
return;
}
d->tag = new ASF::Tag();
d->properties = new ASF::Properties();
d->tag.reset(new ASF::Tag());
d->properties.reset(new ASF::AudioProperties());
bool ok;
d->headerSize = readQWORD(this, &ok);
@@ -639,8 +620,10 @@ void ASF::File::read()
}
seek(2, Current);
SHARED_PTR<FilePrivate::FilePropertiesObject> filePropertiesObject;
SHARED_PTR<FilePrivate::StreamPropertiesObject> streamPropertiesObject;
for(int i = 0; i < numObjects; i++) {
guid = readBlock(16);
const ByteVector guid = readBlock(16);
if(guid.size() != 16) {
setValid(false);
break;
@@ -650,24 +633,29 @@ void ASF::File::read()
setValid(false);
break;
}
FilePrivate::BaseObject *obj;
SHARED_PTR<FilePrivate::BaseObject> obj;
if(guid == filePropertiesGuid) {
obj = new FilePrivate::FilePropertiesObject();
filePropertiesObject.reset(new FilePrivate::FilePropertiesObject());
obj = filePropertiesObject;
}
else if(guid == streamPropertiesGuid) {
obj = new FilePrivate::StreamPropertiesObject();
streamPropertiesObject.reset(new FilePrivate::StreamPropertiesObject());
obj = streamPropertiesObject;
}
else if(guid == contentDescriptionGuid) {
obj = new FilePrivate::ContentDescriptionObject();
d->contentDescriptionObject.reset(new FilePrivate::ContentDescriptionObject());
obj = d->contentDescriptionObject;
}
else if(guid == extendedContentDescriptionGuid) {
obj = new FilePrivate::ExtendedContentDescriptionObject();
d->extendedContentDescriptionObject.reset(new FilePrivate::ExtendedContentDescriptionObject());
obj = d->extendedContentDescriptionObject;
}
else if(guid == headerExtensionGuid) {
obj = 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 ||
@@ -675,9 +663,15 @@ 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);
}
if(!filePropertiesObject || !streamPropertiesObject) {
debug("ASF::File::read(): Missing mandatory header objects.");
setValid(false);
return;
}
}

View File

@@ -48,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
@@ -68,7 +72,7 @@ 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.
@@ -87,26 +91,10 @@ namespace TagLib {
*/
virtual Tag *tag() const;
/*!
* Implements the unified property interface -- export function.
*/
PropertyMap properties() const;
/*!
* Removes unsupported properties. Forwards to the actual Tag's
* removeUnsupportedProperties() function.
*/
void removeUnsupportedProperties(const StringList &properties);
/*!
* Implements the unified property interface -- import function.
*/
PropertyMap setProperties(const PropertyMap &);
/*!
* Returns the ASF audio properties for this file.
*/
virtual Properties *audioProperties() const;
virtual AudioProperties *audioProperties() const;
/*!
* Save the file.
@@ -115,6 +103,15 @@ namespace TagLib {
*/
virtual bool save();
/*!
* Returns whether or not the given \a stream can be opened as an ASF
* file.
*
* \note This method is designed to do a quick check. The result may
* not necessarily be correct.
*/
static bool isSupported(IOStream *stream);
private:
void read();

View File

@@ -25,7 +25,7 @@
#include <taglib.h>
#include <tdebug.h>
#include <trefcounter.h>
#include <tsmartptr.h>
#include "asfattribute.h"
#include "asffile.h"
@@ -34,14 +34,25 @@
using namespace TagLib;
class ASF::Picture::PicturePrivate : public RefCounter
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;
};
////////////////////////////////////////////////////////////////////////////////
@@ -51,71 +62,69 @@ public:
ASF::Picture::Picture() :
d(new PicturePrivate())
{
d->valid = true;
d->data->valid = true;
}
ASF::Picture::Picture(const Picture& other) :
d(other.d)
d(new PicturePrivate(*other.d))
{
d->ref();
}
ASF::Picture::~Picture()
{
if(d->deref())
delete d;
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& other)
@@ -137,47 +146,47 @@ ByteVector ASF::Picture::render() const
return ByteVector();
return
ByteVector((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 = (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

@@ -35,6 +35,7 @@ namespace TagLib
{
namespace ASF
{
class Attribute;
//! An ASF attached picture interface implementation
@@ -46,7 +47,8 @@ namespace TagLib
* \see Attribute::toPicture()
* \see Attribute::Attribute(const Picture& picture)
*/
class TAGLIB_EXPORT Picture {
class TAGLIB_EXPORT Picture
{
public:
/*!
@@ -103,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);
@@ -206,16 +208,15 @@ 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;
PicturePrivate *d;
};
void parse(const ByteVector &);
static Picture fromInvalid();
class PicturePrivate;
PicturePrivate *d;
};
}
}

View File

@@ -29,7 +29,7 @@
using namespace TagLib;
class ASF::Properties::PropertiesPrivate
class ASF::AudioProperties::PropertiesPrivate
{
public:
PropertiesPrivate() :
@@ -38,7 +38,7 @@ public:
sampleRate(0),
channels(0),
bitsPerSample(0),
codec(ASF::Properties::Unknown),
codec(ASF::AudioProperties::Unknown),
encrypted(false) {}
int length;
@@ -46,7 +46,7 @@ public:
int sampleRate;
int channels;
int bitsPerSample;
ASF::Properties::Codec codec;
ASF::AudioProperties::Codec codec;
String codecName;
String codecDescription;
bool encrypted;
@@ -56,68 +56,68 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
ASF::Properties::Properties() :
AudioProperties(AudioProperties::Average),
ASF::AudioProperties::AudioProperties() :
TagLib::AudioProperties(),
d(new PropertiesPrivate())
{
}
ASF::Properties::~Properties()
ASF::AudioProperties::~AudioProperties()
{
delete d;
}
int ASF::Properties::length() const
int ASF::AudioProperties::length() const
{
return lengthInSeconds();
}
int ASF::Properties::lengthInSeconds() const
int ASF::AudioProperties::lengthInSeconds() const
{
return d->length / 1000;
}
int ASF::Properties::lengthInMilliseconds() const
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;
}
@@ -126,37 +126,32 @@ bool ASF::Properties::isEncrypted() const
// private members
////////////////////////////////////////////////////////////////////////////////
void ASF::Properties::setLength(int /*length*/)
{
debug("ASF::Properties::setLength() -- This method is deprecated. Do not use.");
}
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)
{
@@ -178,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

@@ -34,11 +34,14 @@ namespace TagLib {
namespace ASF {
//! An implementation of ASF audio properties
class TAGLIB_EXPORT Properties : public AudioProperties
{
public:
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.
*/
@@ -71,14 +74,14 @@ 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.
*/
virtual ~Properties();
virtual ~AudioProperties();
/*!
* Returns the length of the file in seconds. The length is rounded down to
@@ -96,16 +99,14 @@ namespace TagLib {
*
* \see lengthInMilliseconds()
*/
// BIC: make virtual
int lengthInSeconds() const;
virtual int lengthInSeconds() const;
/*!
* Returns the length of the file in milliseconds.
*
* \see lengthInSeconds()
*/
// BIC: make virtual
int lengthInMilliseconds() const;
virtual int lengthInMilliseconds() const;
/*!
* Returns the average bit rate of the file in kb/s.
@@ -159,10 +160,7 @@ namespace TagLib {
*/
bool isEncrypted() const;
#ifndef DO_NOT_DOCUMENT
// deprecated
void setLength(int value);
private:
void setLengthInMilliseconds(int value);
void setBitrate(int value);
void setSampleRate(int value);
@@ -172,9 +170,7 @@ namespace TagLib {
void setCodecName(const String &value);
void setCodecDescription(const String &value);
void setEncrypted(bool value);
#endif
private:
class PropertiesPrivate;
PropertiesPrivate *d;
};

View File

@@ -23,6 +23,7 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <tpicturemap.h>
#include <tpropertymap.h>
#include "asftag.h"
@@ -39,10 +40,10 @@ public:
AttributeListMap attributeListMap;
};
ASF::Tag::Tag()
: TagLib::Tag()
ASF::Tag::Tag() :
TagLib::Tag(),
d(new TagPrivate())
{
d = new TagPrivate;
}
ASF::Tag::~Tag()
@@ -110,6 +111,91 @@ String ASF::Tag::genre() const
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;
@@ -155,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;

View File

@@ -98,6 +98,8 @@ namespace TagLib {
*/
virtual unsigned int track() const;
virtual PictureMap pictures() const;
/*!
* Sets the title to \a s.
*/
@@ -144,6 +146,8 @@ namespace TagLib {
*/
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

View File

@@ -45,7 +45,7 @@ namespace TagLib
return 0;
}
if(ok) *ok = true;
return v.toUShort(false);
return v.toUInt16LE(0);
}
inline unsigned int readDWORD(File *file, bool *ok = 0)
@@ -56,7 +56,7 @@ namespace TagLib
return 0;
}
if(ok) *ok = true;
return v.toUInt(false);
return v.toUInt32LE(0);
}
inline long long readQWORD(File *file, bool *ok = 0)
@@ -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,9 +88,9 @@ 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;
}

View File

@@ -23,142 +23,34 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <tbytevector.h>
#include "aiffproperties.h"
#include "apeproperties.h"
#include "asfproperties.h"
#include "flacproperties.h"
#include "mp4properties.h"
#include "mpcproperties.h"
#include "mpegproperties.h"
#include "opusproperties.h"
#include "speexproperties.h"
#include "trueaudioproperties.h"
#include "vorbisproperties.h"
#include "wavproperties.h"
#include "wavpackproperties.h"
#include <tstringlist.h>
#include "audioproperties.h"
using namespace TagLib;
class AudioProperties::AudioPropertiesPrivate
{
};
////////////////////////////////////////////////////////////////////////////////
// public methods
////////////////////////////////////////////////////////////////////////////////
AudioProperties::~AudioProperties()
{
}
int AudioProperties::lengthInSeconds() const
String AudioProperties::toString() const
{
// This is an ugly workaround but we can't add a virtual function.
// Should be virtual in taglib2.
if(dynamic_cast<const APE::Properties*>(this))
return dynamic_cast<const APE::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const ASF::Properties*>(this))
return dynamic_cast<const ASF::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const FLAC::Properties*>(this))
return dynamic_cast<const FLAC::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const MP4::Properties*>(this))
return dynamic_cast<const MP4::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const MPC::Properties*>(this))
return dynamic_cast<const MPC::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const MPEG::Properties*>(this))
return dynamic_cast<const MPEG::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const Ogg::Opus::Properties*>(this))
return dynamic_cast<const Ogg::Opus::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const Ogg::Speex::Properties*>(this))
return dynamic_cast<const Ogg::Speex::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const TrueAudio::Properties*>(this))
return dynamic_cast<const TrueAudio::Properties*>(this)->lengthInSeconds();
else if (dynamic_cast<const RIFF::AIFF::Properties*>(this))
return dynamic_cast<const RIFF::AIFF::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const RIFF::WAV::Properties*>(this))
return dynamic_cast<const RIFF::WAV::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const Vorbis::Properties*>(this))
return dynamic_cast<const Vorbis::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const WavPack::Properties*>(this))
return dynamic_cast<const WavPack::Properties*>(this)->lengthInSeconds();
else
return 0;
}
int AudioProperties::lengthInMilliseconds() const
{
// This is an ugly workaround but we can't add a virtual function.
// Should be virtual in taglib2.
if(dynamic_cast<const APE::Properties*>(this))
return dynamic_cast<const APE::Properties*>(this)->lengthInMilliseconds();
else if(dynamic_cast<const ASF::Properties*>(this))
return dynamic_cast<const ASF::Properties*>(this)->lengthInMilliseconds();
else if(dynamic_cast<const FLAC::Properties*>(this))
return dynamic_cast<const FLAC::Properties*>(this)->lengthInMilliseconds();
else if(dynamic_cast<const MP4::Properties*>(this))
return dynamic_cast<const MP4::Properties*>(this)->lengthInMilliseconds();
else if(dynamic_cast<const MPC::Properties*>(this))
return dynamic_cast<const MPC::Properties*>(this)->lengthInMilliseconds();
else if(dynamic_cast<const MPEG::Properties*>(this))
return dynamic_cast<const MPEG::Properties*>(this)->lengthInMilliseconds();
else if(dynamic_cast<const Ogg::Opus::Properties*>(this))
return dynamic_cast<const Ogg::Opus::Properties*>(this)->lengthInMilliseconds();
else if(dynamic_cast<const Ogg::Speex::Properties*>(this))
return dynamic_cast<const Ogg::Speex::Properties*>(this)->lengthInMilliseconds();
else if(dynamic_cast<const TrueAudio::Properties*>(this))
return dynamic_cast<const TrueAudio::Properties*>(this)->lengthInMilliseconds();
else if(dynamic_cast<const RIFF::AIFF::Properties*>(this))
return dynamic_cast<const RIFF::AIFF::Properties*>(this)->lengthInMilliseconds();
else if(dynamic_cast<const RIFF::WAV::Properties*>(this))
return dynamic_cast<const RIFF::WAV::Properties*>(this)->lengthInMilliseconds();
else if(dynamic_cast<const Vorbis::Properties*>(this))
return dynamic_cast<const Vorbis::Properties*>(this)->lengthInMilliseconds();
else if(dynamic_cast<const WavPack::Properties*>(this))
return dynamic_cast<const WavPack::Properties*>(this)->lengthInMilliseconds();
else
return 0;
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

@@ -27,6 +27,7 @@
#define TAGLIB_AUDIOPROPERTIES_H
#include "taglib_export.h"
#include "tstring.h"
namespace TagLib {
@@ -75,16 +76,14 @@ namespace TagLib {
*
* \see lengthInMilliseconds()
*/
// BIC: make virtual
int lengthInSeconds() const;
virtual int lengthInSeconds() const = 0;
/*!
* Returns the length of the file in milliseconds.
*
* \see lengthInSeconds()
*/
// BIC: make virtual
int lengthInMilliseconds() const;
virtual int lengthInMilliseconds() const = 0;
/*!
* Returns the most appropriate bit rate for the file in kb/s. For constant
@@ -103,23 +102,27 @@ namespace TagLib {
*/
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:
// Noncopyable. Derived classes as well.
AudioProperties(const AudioProperties &);
AudioProperties &operator=(const AudioProperties &);
class AudioPropertiesPrivate;
AudioPropertiesPrivate *d;
class PropertiesPrivate;
PropertiesPrivate *d;
};
}

View File

@@ -0,0 +1,166 @@
/***************************************************************************
copyright : (C) 2016 by Damien Plisson, Audirvana
email : damien78@audirvana.com
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include "dsdiffdiintag.h"
#include "tstringlist.h"
#include "tpropertymap.h"
#include "tpicturemap.h"
using namespace TagLib;
using namespace DSDIFF::DIIN;
class DSDIFF::DIIN::Tag::TagPrivate
{
public:
TagPrivate()
{
}
String title;
String artist;
};
DSDIFF::DIIN::Tag::Tag() : TagLib::Tag()
{
d = new TagPrivate;
}
DSDIFF::DIIN::Tag::~Tag()
{
delete d;
}
String DSDIFF::DIIN::Tag::title() const
{
return d->title;
}
String DSDIFF::DIIN::Tag::artist() const
{
return d->artist;
}
String DSDIFF::DIIN::Tag::album() const
{
return String();
}
String DSDIFF::DIIN::Tag::comment() const
{
return String();
}
String DSDIFF::DIIN::Tag::genre() const
{
return String();
}
unsigned int DSDIFF::DIIN::Tag::year() const
{
return 0;
}
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;
}
void DSDIFF::DIIN::Tag::setArtist(const String &artist)
{
d->artist = artist;
}
void DSDIFF::DIIN::Tag::setAlbum(const String &)
{
}
void DSDIFF::DIIN::Tag::setComment(const String &)
{
}
void DSDIFF::DIIN::Tag::setGenre(const String &)
{
}
void DSDIFF::DIIN::Tag::setYear(unsigned int)
{
}
void DSDIFF::DIIN::Tag::setTrack(unsigned int)
{
}
void DSDIFF::DIIN::Tag::setPictures( const PictureMap& l )
{
}
PropertyMap DSDIFF::DIIN::Tag::properties() const
{
PropertyMap properties;
properties["TITLE"] = d->title;
properties["ARTIST"] = d->artist;
return properties;
}
PropertyMap DSDIFF::DIIN::Tag::setProperties(const PropertyMap &origProps)
{
PropertyMap properties(origProps);
properties.removeEmpty();
StringList oneValueSet;
if(properties.contains("TITLE")) {
d->title = properties["TITLE"].front();
oneValueSet.append("TITLE");
} else
d->title = String();
if(properties.contains("ARTIST")) {
d->artist = properties["ARTIST"].front();
oneValueSet.append("ARTIST");
} else
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(StringList::Iterator it = oneValueSet.begin(); it != oneValueSet.end(); ++it) {
if(properties[*it].size() == 1)
properties.erase(*it);
else
properties[*it].erase(properties[*it].begin());
}
return properties;
}

View File

@@ -0,0 +1,160 @@
/***************************************************************************
copyright : (C) 2016 by Damien Plisson, Audirvana
email : damien78@audirvana.com
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifndef TAGLIB_DSDIFFDIINTAG_H
#define TAGLIB_DSDIFFDIINTAG_H
#include "tag.h"
namespace TagLib {
namespace DSDIFF {
namespace DIIN {
/*!
* Tags from the Edited Master Chunk Info
*
* Only Title and Artist tags are supported
*/
class TAGLIB_EXPORT Tag : public TagLib::Tag
{
public:
Tag();
virtual ~Tag();
/*!
* Returns the track name; if no track name is present in the tag
* String() will be returned.
*/
virtual String title() const;
/*!
* Returns the artist name; if no artist name is present in the tag
* String() will be returned.
*/
virtual String artist() const;
/*!
* Not supported. Therefore always returns String().
*/
virtual String album() const;
/*!
* Not supported. Therefore always returns String().
*/
virtual String comment() const;
/*!
* Not supported. Therefore always returns String().
*/
virtual String genre() const;
/*!
* Not supported. Therefore always returns 0.
*/
virtual unsigned int year() const;
/*!
* Not supported. Therefore always returns 0.
*/
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.
*/
virtual void setTitle(const String &title);
/*!
* Sets the artist to \a artist. If \a artist is String() then this
* value will be cleared.
*/
virtual void setArtist(const String &artist);
/*!
* Not supported and therefore ignored.
*/
virtual void setAlbum(const String &album);
/*!
* Not supported and therefore ignored.
*/
virtual void setComment(const String &comment);
/*!
* Not supported and therefore ignored.
*/
virtual void setGenre(const String &genre);
/*!
* Not supported and therefore ignored.
*/
virtual void setYear(unsigned int year);
/*!
* Not supported and therefore ignored.
*/
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;
/*!
* Implements the unified property interface -- import function.
* Because of the limitations of the DIIN file tag, any tags besides
* TITLE and ARTIST, will be
* returned. Additionally, if the map contains tags with multiple values,
* all but the first will be contained in the returned map of unsupported
* properties.
*/
PropertyMap setProperties(const PropertyMap &);
private:
Tag(const Tag &);
Tag &operator=(const Tag &);
class TagPrivate;
TagPrivate *d;
};
}
}
}
#endif

View File

@@ -0,0 +1,844 @@
/***************************************************************************
copyright : (C) 2016 by Damien Plisson, Audirvana
email : damien78@audirvana.com
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <tbytevector.h>
#include <tdebug.h>
#include <id3v2tag.h>
#include <tstringlist.h>
#include <tpropertymap.h>
#include <tagutils.h>
#include <tsmartptr.h>
#include "tagunion.h"
#include "dsdifffile.h"
using namespace TagLib;
struct Chunk64
{
ByteVector name;
unsigned long long offset;
unsigned long long size;
char padding;
};
namespace
{
enum {
ID3v2Index = 0,
DIINIndex = 1
};
enum {
PROPChunk = 0,
DIINChunk = 1
};
}
class DSDIFF::File::FilePrivate
{
public:
FilePrivate() :
endianness(BigEndian),
size(0),
isID3InPropChunk(false),
duplicateID3V2chunkIndex(-1),
id3v2TagChunkID("ID3 "),
hasID3v2(false),
hasDiin(false)
{
childChunkIndex[ID3v2Index] = -1;
childChunkIndex[DIINIndex] = -1;
}
Endianness endianness;
ByteVector type;
unsigned long long size;
ByteVector format;
std::vector<Chunk64> chunks;
std::vector<Chunk64> childChunks[2];
int childChunkIndex[2];
bool isID3InPropChunk; // Two possibilities can be found: ID3V2 chunk inside PROP chunk or at root level
int duplicateID3V2chunkIndex; // 2 ID3 chunks are present. This is then the index of the one in
// PROP chunk that will be removed upon next save to remove duplicates.
SCOPED_PTR<AudioProperties> properties;
DoubleTagUnion tag;
ByteVector id3v2TagChunkID;
bool hasID3v2;
bool hasDiin;
};
////////////////////////////////////////////////////////////////////////////////
// static members
////////////////////////////////////////////////////////////////////////////////
bool DSDIFF::File::isSupported(IOStream *stream)
{
// A DSDIFF file has to start with "FRM8????????DSD ".
const ByteVector id = Utils::readHeader(stream, 16, false);
return (id.startsWith("FRM8") && id.containsAt("DSD ", 12));
}
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
DSDIFF::File::File(FileName file, bool readProperties,
AudioProperties::ReadStyle propertiesStyle) : TagLib::File(file)
{
d = new FilePrivate;
d->endianness = BigEndian;
if(isOpen())
read(readProperties, propertiesStyle);
}
DSDIFF::File::File(IOStream *stream, bool readProperties,
AudioProperties::ReadStyle propertiesStyle) : TagLib::File(stream)
{
d = new FilePrivate;
d->endianness = BigEndian;
if(isOpen())
read(readProperties, propertiesStyle);
}
DSDIFF::File::~File()
{
delete d;
}
TagLib::Tag *DSDIFF::File::tag() const
{
return &d->tag;
}
ID3v2::Tag *DSDIFF::File::ID3v2Tag() const
{
return d->tag.access<ID3v2::Tag>(ID3v2Index, false);
}
bool DSDIFF::File::hasID3v2Tag() const
{
return d->hasID3v2;
}
DSDIFF::DIIN::Tag *DSDIFF::File::DIINTag() const
{
return d->tag.access<DSDIFF::DIIN::Tag>(DIINIndex, false);
}
bool DSDIFF::File::hasDIINTag() const
{
return d->hasDiin;
}
PropertyMap DSDIFF::File::properties() const
{
if(d->hasID3v2)
return d->tag.access<ID3v2::Tag>(ID3v2Index, false)->properties();
return PropertyMap();
}
void DSDIFF::File::removeUnsupportedProperties(const StringList &unsupported)
{
if(d->hasID3v2)
d->tag.access<ID3v2::Tag>(ID3v2Index, false)->removeUnsupportedProperties(unsupported);
if(d->hasDiin)
d->tag.access<DSDIFF::DIIN::Tag>(DIINIndex, false)->removeUnsupportedProperties(unsupported);
}
PropertyMap DSDIFF::File::setProperties(const PropertyMap &properties)
{
return d->tag.access<ID3v2::Tag>(ID3v2Index, true)->setProperties(properties);
}
DSDIFF::AudioProperties *DSDIFF::File::audioProperties() const
{
return d->properties.get();
}
bool DSDIFF::File::save()
{
if(readOnly()) {
debug("DSDIFF::File::save() -- File is read only.");
return false;
}
if(!isValid()) {
debug("DSDIFF::File::save() -- Trying to save invalid file.");
return false;
}
// First: save ID3V2 chunk
ID3v2::Tag *id3v2Tag = d->tag.access<ID3v2::Tag>(ID3v2Index, false);
if(d->isID3InPropChunk) {
if(id3v2Tag != NULL && !id3v2Tag->isEmpty()) {
setChildChunkData(d->id3v2TagChunkID, id3v2Tag->render(), PROPChunk);
d->hasID3v2 = true;
}
else {
// Empty tag: remove it
setChildChunkData(d->id3v2TagChunkID, ByteVector(), PROPChunk);
d->hasID3v2 = false;
}
}
else {
if(id3v2Tag != NULL && !id3v2Tag->isEmpty()) {
setRootChunkData(d->id3v2TagChunkID, id3v2Tag->render());
d->hasID3v2 = true;
}
else {
// Empty tag: remove it
setRootChunkData(d->id3v2TagChunkID, ByteVector());
d->hasID3v2 = false;
}
}
// Second: save the DIIN chunk
if(d->hasDiin) {
DSDIFF::DIIN::Tag *diinTag = d->tag.access<DSDIFF::DIIN::Tag>(DIINIndex, false);
if(!diinTag->title().isEmpty()) {
ByteVector diinTitle;
if(d->endianness == BigEndian)
diinTitle.append(ByteVector::fromUInt32BE(diinTag->title().size()));
else
diinTitle.append(ByteVector::fromUInt32LE(diinTag->title().size()));
diinTitle.append(ByteVector::fromCString(diinTag->title().toCString()));
setChildChunkData("DITI", diinTitle, DIINChunk);
}
else
setChildChunkData("DITI", ByteVector(), DIINChunk);
if(!diinTag->artist().isEmpty()) {
ByteVector diinArtist;
if(d->endianness == BigEndian)
diinArtist.append(ByteVector::fromUInt32BE(diinTag->artist().size()));
else
diinArtist.append(ByteVector::fromUInt32LE(diinTag->artist().size()));
diinArtist.append(ByteVector::fromCString(diinTag->artist().toCString()));
setChildChunkData("DIAR", diinArtist, DIINChunk);
}
else
setChildChunkData("DIAR", ByteVector(), DIINChunk);
}
// Third: remove the duplicate ID3V2 chunk (inside PROP chunk) if any
if(d->duplicateID3V2chunkIndex>=0) {
setChildChunkData(d->duplicateID3V2chunkIndex, ByteVector(), PROPChunk);
d->duplicateID3V2chunkIndex = -1;
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void DSDIFF::File::setRootChunkData(unsigned int i, const ByteVector &data)
{
if(data.isEmpty()) {
// Null data: remove chunk
// Update global size
unsigned long long removedChunkTotalSize = d->chunks[i].size + d->chunks[i].padding + 12;
d->size -= removedChunkTotalSize;
if(d->endianness == BigEndian)
insert(ByteVector::fromUInt64BE(d->size), 4, 8);
else
insert(ByteVector::fromUInt64LE(d->size), 4, 8);
removeBlock(d->chunks[i].offset - 12, removedChunkTotalSize);
// Update the internal offsets
for(unsigned long r = i + 1; r < d->chunks.size(); r++)
d->chunks[r].offset = d->chunks[r - 1].offset + 12
+ d->chunks[r - 1].size + d->chunks[r - 1].padding;
d->chunks.erase(d->chunks.begin() + i);
}
else {
// Non null data: update chunk
// First we update the global size
d->size += ((data.size() + 1) & ~1) - (d->chunks[i].size + d->chunks[i].padding);
if(d->endianness == BigEndian)
insert(ByteVector::fromUInt64BE(d->size), 4, 8);
else
insert(ByteVector::fromUInt64LE(d->size), 4, 8);
// Now update the specific chunk
writeChunk(d->chunks[i].name,
data,
d->chunks[i].offset - 12,
d->chunks[i].size + d->chunks[i].padding + 12);
d->chunks[i].size = data.size();
d->chunks[i].padding = (data.size() & 0x01) ? 1 : 0;
// Finally update the internal offsets
updateRootChunksStructure(i + 1);
}
}
void DSDIFF::File::setRootChunkData(const ByteVector &name, const ByteVector &data)
{
if(d->chunks.size() == 0) {
debug("DSDIFF::File::setPropChunkData - No valid chunks found.");
return;
}
for(unsigned int i = 0; i < d->chunks.size(); i++) {
if(d->chunks[i].name == name) {
setRootChunkData(i, data);
return;
}
}
// Couldn't find an existing chunk, so let's create a new one.
unsigned int i = d->chunks.size() - 1;
unsigned long offset = d->chunks[i].offset + d->chunks[i].size + d->chunks[i].padding;
// First we update the global size
d->size += (offset & 1) + ((data.size() + 1) & ~1) + 12;
if(d->endianness == BigEndian)
insert(ByteVector::fromUInt64BE(d->size), 4, 8);
else
insert(ByteVector::fromUInt64LE(d->size), 4, 8);
// Now add the chunk to the file
writeChunk(name,
data,
offset,
std::max<unsigned long long>(0, length() - offset),
(offset & 1) ? 1 : 0);
Chunk64 chunk;
chunk.name = name;
chunk.size = data.size();
chunk.offset = offset + 12;
chunk.padding = (data.size() & 0x01) ? 1 : 0;
d->chunks.push_back(chunk);
}
void DSDIFF::File::setChildChunkData(unsigned int i,
const ByteVector &data,
unsigned int childChunkNum)
{
std::vector<Chunk64> &childChunks = d->childChunks[childChunkNum];
if(data.isEmpty()) {
// Null data: remove chunk
// Update global size
unsigned long long removedChunkTotalSize = childChunks[i].size + childChunks[i].padding + 12;
d->size -= removedChunkTotalSize;
if(d->endianness == BigEndian)
insert(ByteVector::fromUInt64BE(d->size), 4, 8);
else
insert(ByteVector::fromUInt64LE(d->size), 4, 8);
// Update child chunk size
d->chunks[d->childChunkIndex[childChunkNum]].size -= removedChunkTotalSize;
if(d->endianness == BigEndian)
insert(ByteVector::fromUInt64BE(d->chunks[d->childChunkIndex[childChunkNum]].size),
d->chunks[d->childChunkIndex[childChunkNum]].offset - 8, 8);
else
insert(ByteVector::fromUInt64LE(d->chunks[d->childChunkIndex[childChunkNum]].size),
d->chunks[d->childChunkIndex[childChunkNum]].offset - 8, 8);
// Remove the chunk
removeBlock(childChunks[i].offset - 12, removedChunkTotalSize);
// Update the internal offsets
// For child chunks
if((i + 1) < childChunks.size()) {
childChunks[i + 1].offset = childChunks[i].offset;
i++;
for(i++; i < childChunks.size(); i++)
childChunks[i].offset = childChunks[i - 1].offset + 12
+ childChunks[i - 1].size + childChunks[i - 1].padding;
}
// And for root chunks
for(i = d->childChunkIndex[childChunkNum] + 1; i < d->chunks.size(); i++)
d->chunks[i].offset = d->chunks[i - 1].offset + 12
+ d->chunks[i - 1].size + d->chunks[i - 1].padding;
childChunks.erase(childChunks.begin() + i);
}
else {
// Non null data: update chunk
// First we update the global size
d->size += ((data.size() + 1) & ~1) - (childChunks[i].size + childChunks[i].padding);
if(d->endianness == BigEndian)
insert(ByteVector::fromUInt64BE(d->size), 4, 8);
else
insert(ByteVector::fromUInt64LE(d->size), 4, 8);
// And the PROP chunk size
d->chunks[d->childChunkIndex[childChunkNum]].size += ((data.size() + 1) & ~1)
- (childChunks[i].size + childChunks[i].padding);
if(d->endianness == BigEndian)
insert(ByteVector::fromUInt64BE(d->chunks[d->childChunkIndex[childChunkNum]].size),
d->chunks[d->childChunkIndex[childChunkNum]].offset - 8, 8);
else
insert(ByteVector::fromUInt64LE(d->chunks[d->childChunkIndex[childChunkNum]].size),
d->chunks[d->childChunkIndex[childChunkNum]].offset - 8, 8);
// Now update the specific chunk
writeChunk(childChunks[i].name,
data,
childChunks[i].offset - 12,
childChunks[i].size + childChunks[i].padding + 12);
childChunks[i].size = data.size();
childChunks[i].padding = (data.size() & 0x01) ? 1 : 0;
// Now update the internal offsets
// For child Chunks
for(i++; i < childChunks.size(); i++)
childChunks[i].offset = childChunks[i - 1].offset + 12
+ childChunks[i - 1].size + childChunks[i - 1].padding;
// And for root chunks
updateRootChunksStructure(d->childChunkIndex[childChunkNum] + 1);
}
}
void DSDIFF::File::setChildChunkData(const ByteVector &name,
const ByteVector &data,
unsigned int childChunkNum)
{
std::vector<Chunk64> &childChunks = d->childChunks[childChunkNum];
if(childChunks.size() == 0) {
debug("DSDIFF::File::setPropChunkData - No valid chunks found.");
return;
}
for(unsigned int i = 0; i < childChunks.size(); i++) {
if(childChunks[i].name == name) {
setChildChunkData(i, data, childChunkNum);
return;
}
}
// Do not attempt to remove a non existing chunk
if(data.isEmpty())
return;
// Couldn't find an existing chunk, so let's create a new one.
unsigned int i = childChunks.size() - 1;
unsigned long offset = childChunks[i].offset + childChunks[i].size + childChunks[i].padding;
// First we update the global size
d->size += (offset & 1) + ((data.size() + 1) & ~1) + 12;
if(d->endianness == BigEndian)
insert(ByteVector::fromUInt64BE(d->size), 4, 8);
else
insert(ByteVector::fromUInt64LE(d->size), 4, 8);
// And the child chunk size
d->chunks[d->childChunkIndex[childChunkNum]].size += (offset & 1)
+ ((data.size() + 1) & ~1) + 12;
if(d->endianness == BigEndian)
insert(ByteVector::fromUInt64BE(d->chunks[d->childChunkIndex[childChunkNum]].size),
d->chunks[d->childChunkIndex[childChunkNum]].offset - 8, 8);
else
insert(ByteVector::fromUInt64LE(d->chunks[d->childChunkIndex[childChunkNum]].size),
d->chunks[d->childChunkIndex[childChunkNum]].offset - 8, 8);
// Now add the chunk to the file
unsigned long long nextRootChunkIdx = length();
if((d->childChunkIndex[childChunkNum] + 1) < static_cast<int>(d->chunks.size()))
nextRootChunkIdx = d->chunks[d->childChunkIndex[childChunkNum] + 1].offset - 12;
writeChunk(name, data, offset,
std::max<unsigned long long>(0, nextRootChunkIdx - offset),
(offset & 1) ? 1 : 0);
// For root chunks
updateRootChunksStructure(d->childChunkIndex[childChunkNum] + 1);
Chunk64 chunk;
chunk.name = name;
chunk.size = data.size();
chunk.offset = offset + 12;
chunk.padding = (data.size() & 0x01) ? 1 : 0;
childChunks.push_back(chunk);
}
static bool isValidChunkID(const ByteVector &name)
{
if(name.size() != 4)
return false;
for(int i = 0; i < 4; i++) {
if(name[i] < 32 || name[i] > 127)
return false;
}
return true;
}
void DSDIFF::File::updateRootChunksStructure(unsigned int startingChunk)
{
for(unsigned int i = startingChunk; i < d->chunks.size(); i++)
d->chunks[i].offset = d->chunks[i - 1].offset + 12
+ d->chunks[i - 1].size + d->chunks[i - 1].padding;
// Update childchunks structure as well
if(d->childChunkIndex[PROPChunk] >= static_cast<int>(startingChunk)) {
std::vector<Chunk64> &childChunksToUpdate = d->childChunks[PROPChunk];
if(childChunksToUpdate.size() > 0) {
childChunksToUpdate[0].offset = d->chunks[d->childChunkIndex[PROPChunk]].offset + 12;
for(unsigned int i = 1; i < childChunksToUpdate.size(); i++)
childChunksToUpdate[i].offset = childChunksToUpdate[i - 1].offset + 12
+ childChunksToUpdate[i - 1].size + childChunksToUpdate[i - 1].padding;
}
}
if(d->childChunkIndex[DIINChunk] >= static_cast<int>(startingChunk)) {
std::vector<Chunk64> &childChunksToUpdate = d->childChunks[DIINChunk];
if(childChunksToUpdate.size() > 0) {
childChunksToUpdate[0].offset = d->chunks[d->childChunkIndex[DIINChunk]].offset + 12;
for(unsigned int i = 1; i < childChunksToUpdate.size(); i++)
childChunksToUpdate[i].offset = childChunksToUpdate[i - 1].offset + 12
+ childChunksToUpdate[i - 1].size + childChunksToUpdate[i - 1].padding;
}
}
}
void DSDIFF::File::read(bool readProperties, AudioProperties::ReadStyle propertiesStyle)
{
bool bigEndian = (d->endianness == BigEndian);
d->type = readBlock(4);
d->size = bigEndian ? readBlock(8).toInt64BE(0) : readBlock(8).toInt64LE(0);
d->format = readBlock(4);
// + 12: chunk header at least, fix for additional junk bytes
while(tell() + 12 <= length()) {
ByteVector chunkName = readBlock(4);
unsigned long long chunkSize = bigEndian ? readBlock(8).toInt64BE(0) : readBlock(8).toInt64LE(0);
if(!isValidChunkID(chunkName)) {
debug("DSDIFF::File::read() -- Chunk '" + chunkName + "' has invalid ID");
setValid(false);
break;
}
if(static_cast<unsigned long long>(tell()) + chunkSize > static_cast<unsigned long long>(length())) {
debug("DSDIFF::File::read() -- Chunk '" + chunkName
+ "' has invalid size (larger than the file size)");
setValid(false);
break;
}
Chunk64 chunk;
chunk.name = chunkName;
chunk.size = chunkSize;
chunk.offset = tell();
seek(chunk.size, Current);
// Check padding
chunk.padding = 0;
long uPosNotPadded = tell();
if((uPosNotPadded & 0x01) != 0) {
ByteVector iByte = readBlock(1);
if((iByte.size() != 1) || (iByte[0] != 0))
// Not well formed, re-seek
seek(uPosNotPadded, Beginning);
else
chunk.padding = 1;
}
d->chunks.push_back(chunk);
}
unsigned long long lengthDSDSamplesTimeChannels = 0; // For DSD uncompressed
unsigned long long audioDataSizeinBytes = 0; // For computing bitrate
unsigned long dstNumFrames = 0; // For DST compressed frames
unsigned short dstFrameRate = 0; // For DST compressed frames
for(unsigned int i = 0; i < d->chunks.size(); i++) {
if(d->chunks[i].name == "DSD ") {
lengthDSDSamplesTimeChannels = d->chunks[i].size * 8;
audioDataSizeinBytes = d->chunks[i].size;
}
else if(d->chunks[i].name == "DST ") {
// Now decode the chunks inside the DST chunk to read the DST Frame Information one
long long dstChunkEnd = d->chunks[i].offset + d->chunks[i].size;
seek(d->chunks[i].offset);
audioDataSizeinBytes = d->chunks[i].size;
while(tell() + 12 <= dstChunkEnd) {
ByteVector dstChunkName = readBlock(4);
long long dstChunkSize = bigEndian ? readBlock(8).toInt64BE(0) : readBlock(8).toInt64LE(0);
if(!isValidChunkID(dstChunkName)) {
debug("DSDIFF::File::read() -- DST Chunk '" + dstChunkName + "' has invalid ID");
setValid(false);
break;
}
if(static_cast<long long>(tell()) + dstChunkSize > dstChunkEnd) {
debug("DSDIFF::File::read() -- DST Chunk '" + dstChunkName
+ "' has invalid size (larger than the DST chunk)");
setValid(false);
break;
}
if(dstChunkName == "FRTE") {
// Found the DST frame information chunk
dstNumFrames = bigEndian ? readBlock(4).toUInt32BE(0) : readBlock(4).toUInt32LE(0);
dstFrameRate = bigEndian ? readBlock(2).toUInt16BE(0) : readBlock(2).toUInt16LE(0);
break; // Found the wanted one, no need to look at the others
}
seek(dstChunkSize, Current);
// Check padding
long uPosNotPadded = tell();
if((uPosNotPadded & 0x01) != 0) {
ByteVector iByte = readBlock(1);
if((iByte.size() != 1) || (iByte[0] != 0))
// Not well formed, re-seek
seek(uPosNotPadded, Beginning);
}
}
}
else if(d->chunks[i].name == "PROP") {
d->childChunkIndex[PROPChunk] = i;
// Now decodes the chunks inside the PROP chunk
long long propChunkEnd = d->chunks[i].offset + d->chunks[i].size;
seek(d->chunks[i].offset + 4); // +4 to remove the 'SND ' marker at beginning of 'PROP' chunk
while(tell() + 12 <= propChunkEnd) {
ByteVector propChunkName = readBlock(4);
long long propChunkSize = bigEndian ? readBlock(8).toInt64BE(0) : readBlock(8).toInt64LE(0);
if(!isValidChunkID(propChunkName)) {
debug("DSDIFF::File::read() -- PROP Chunk '" + propChunkName + "' has invalid ID");
setValid(false);
break;
}
if(static_cast<long long>(tell()) + propChunkSize > propChunkEnd) {
debug("DSDIFF::File::read() -- PROP Chunk '" + propChunkName
+ "' has invalid size (larger than the PROP chunk)");
setValid(false);
break;
}
Chunk64 chunk;
chunk.name = propChunkName;
chunk.size = propChunkSize;
chunk.offset = tell();
seek(chunk.size, Current);
// Check padding
chunk.padding = 0;
long uPosNotPadded = tell();
if((uPosNotPadded & 0x01) != 0) {
ByteVector iByte = readBlock(1);
if((iByte.size() != 1) || (iByte[0] != 0))
// Not well formed, re-seek
seek(uPosNotPadded, Beginning);
else
chunk.padding = 1;
}
d->childChunks[PROPChunk].push_back(chunk);
}
}
else if(d->chunks[i].name == "DIIN") {
d->childChunkIndex[DIINChunk] = i;
d->hasDiin = true;
// Now decode the chunks inside the DIIN chunk
long long diinChunkEnd = d->chunks[i].offset + d->chunks[i].size;
seek(d->chunks[i].offset);
while(tell() + 12 <= diinChunkEnd) {
ByteVector diinChunkName = readBlock(4);
long long diinChunkSize = bigEndian ? readBlock(8).toInt64BE(0) : readBlock(8).toInt64LE(0);
if(!isValidChunkID(diinChunkName)) {
debug("DSDIFF::File::read() -- DIIN Chunk '" + diinChunkName + "' has invalid ID");
setValid(false);
break;
}
if(static_cast<long long>(tell()) + diinChunkSize > diinChunkEnd) {
debug("DSDIFF::File::read() -- DIIN Chunk '" + diinChunkName
+ "' has invalid size (larger than the DIIN chunk)");
setValid(false);
break;
}
Chunk64 chunk;
chunk.name = diinChunkName;
chunk.size = diinChunkSize;
chunk.offset = tell();
seek(chunk.size, Current);
// Check padding
chunk.padding = 0;
long uPosNotPadded = tell();
if((uPosNotPadded & 0x01) != 0) {
ByteVector iByte = readBlock(1);
if((iByte.size() != 1) || (iByte[0] != 0))
// Not well formed, re-seek
seek(uPosNotPadded, Beginning);
else
chunk.padding = 1;
}
d->childChunks[DIINChunk].push_back(chunk);
}
}
else if(d->chunks[i].name == "ID3 " || d->chunks[i].name == "id3 ") {
d->id3v2TagChunkID = d->chunks[i].name;
d->tag.set(ID3v2Index, new ID3v2::Tag(this, d->chunks[i].offset));
d->isID3InPropChunk = false;
d->hasID3v2 = true;
}
}
if(!isValid())
return;
if(d->childChunkIndex[PROPChunk] < 0) {
debug("DSDIFF::File::read() -- no PROP chunk found");
setValid(false);
return;
}
// Read properties
unsigned int sampleRate=0;
unsigned short channels=0;
for(unsigned int i = 0; i < d->childChunks[PROPChunk].size(); i++) {
if(d->childChunks[PROPChunk][i].name == "ID3 " || d->childChunks[PROPChunk][i].name == "id3 ") {
if(d->hasID3v2) {
d->duplicateID3V2chunkIndex = i;
continue; // ID3V2 tag has already been found at root level
}
d->id3v2TagChunkID = d->childChunks[PROPChunk][i].name;
d->tag.set(ID3v2Index, new ID3v2::Tag(this, d->childChunks[PROPChunk][i].offset));
d->isID3InPropChunk = true;
d->hasID3v2 = true;
}
else if(d->childChunks[PROPChunk][i].name == "FS ") {
// Sample rate
seek(d->childChunks[PROPChunk][i].offset);
sampleRate = bigEndian ? readBlock(4).toUInt32BE(0) : readBlock(4).toUInt32LE(0);
}
else if(d->childChunks[PROPChunk][i].name == "CHNL") {
// Channels
seek(d->childChunks[PROPChunk][i].offset);
channels = bigEndian ? readBlock(2).toInt16BE(0) : readBlock(2).toInt16LE(0);
}
}
// Read title & artist from DIIN chunk
d->tag.access<DSDIFF::DIIN::Tag>(DIINIndex, true);
if(d->hasDiin) {
for(unsigned int i = 0; i < d->childChunks[DIINChunk].size(); i++) {
if(d->childChunks[DIINChunk][i].name == "DITI") {
seek(d->childChunks[DIINChunk][i].offset);
unsigned int titleStrLength = bigEndian ? readBlock(4).toUInt32BE(0) : readBlock(4).toUInt32LE(0);
if(titleStrLength <= d->childChunks[DIINChunk][i].size) {
ByteVector titleStr = readBlock(titleStrLength);
d->tag.access<DSDIFF::DIIN::Tag>(DIINIndex, false)->setTitle(titleStr);
}
}
else if(d->childChunks[DIINChunk][i].name == "DIAR") {
seek(d->childChunks[DIINChunk][i].offset);
unsigned int artistStrLength = bigEndian ? readBlock(4).toUInt32BE(0) : readBlock(4).toUInt32LE(0);
if(artistStrLength <= d->childChunks[DIINChunk][i].size) {
ByteVector artistStr = readBlock(artistStrLength);
d->tag.access<DSDIFF::DIIN::Tag>(DIINIndex, false)->setArtist(artistStr);
}
}
}
}
if(readProperties) {
if(lengthDSDSamplesTimeChannels == 0) {
// DST compressed signal : need to compute length of DSD uncompressed frames
if(dstFrameRate > 0)
lengthDSDSamplesTimeChannels = (unsigned long long)dstNumFrames
* (unsigned long long)sampleRate / (unsigned long long)dstFrameRate;
else
lengthDSDSamplesTimeChannels = 0;
}
else {
// In DSD uncompressed files, the read number of samples is the total for each channel
if(channels > 0)
lengthDSDSamplesTimeChannels /= channels;
}
int bitrate = 0;
if(lengthDSDSamplesTimeChannels > 0)
bitrate = (audioDataSizeinBytes*8*sampleRate) / lengthDSDSamplesTimeChannels / 1000;
d->properties.reset(new AudioProperties(sampleRate,
channels,
lengthDSDSamplesTimeChannels,
bitrate,
propertiesStyle));
}
if(!ID3v2Tag()) {
d->tag.access<ID3v2::Tag>(ID3v2Index, true);
d->isID3InPropChunk = false; // By default, ID3 chunk is at root level
d->hasID3v2 = false;
}
}
void DSDIFF::File::writeChunk(const ByteVector &name, const ByteVector &data,
unsigned long long offset, unsigned long replace,
unsigned int leadingPadding)
{
ByteVector combined;
if(leadingPadding)
combined.append(ByteVector(leadingPadding, '\x00'));
combined.append(name);
if(d->endianness == BigEndian)
combined.append(ByteVector::fromUInt64BE(data.size()));
else
combined.append(ByteVector::fromUInt64LE(data.size()));
combined.append(data);
if((data.size() & 0x01) != 0)
combined.append('\x00');
insert(combined, offset, replace);
}

260
taglib/dsdiff/dsdifffile.h Normal file
View File

@@ -0,0 +1,260 @@
/***************************************************************************
copyright : (C) 2016 by Damien Plisson, Audirvana
email : damien78@audirvana.com
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifndef TAGLIB_DSDIFFFILE_H
#define TAGLIB_DSDIFFFILE_H
#include "rifffile.h"
#include "id3v2tag.h"
#include "dsdiffproperties.h"
#include "dsdiffdiintag.h"
namespace TagLib {
//! An implementation of DSDIFF metadata
/*!
* This is implementation of DSDIFF metadata.
*
* This supports an ID3v2 tag as well as reading stream from the ID3 RIFF
* 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 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
*/
namespace DSDIFF {
//! An implementation of TagLib::File with DSDIFF specific methods
/*!
* This implements and provides an interface for DSDIFF 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 DSDIFF files.
*/
class TAGLIB_EXPORT File : public TagLib::File
{
public:
/*!
* 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.
*/
File(FileName file, bool readProperties = true,
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.
*
* \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,
AudioProperties::ReadStyle propertiesStyle = AudioProperties::Average);
/*!
* Destroys this instance of the File.
*/
virtual ~File();
/*!
* Returns a pointer to a tag that is the union of the ID3v2 and DIIN
* tags. The ID3v2 tag is given priority in reading the information -- if
* requested information exists in both the ID3v2 tag and the ID3v1 tag,
* the information from the ID3v2 tag will be returned.
*
* If you would like more granular control over the content of the tags,
* with the concession of generality, use the tag-type specific calls.
*
* \note As this tag is not implemented as an ID3v2 tag or a DIIN tag,
* but a union of the two this pointer may not be cast to the specific
* tag types.
*
* \see ID3v2Tag()
* \see DIINTag()
*/
virtual Tag *tag() const;
/*!
* Returns the ID3V2 Tag for this file.
*
* \note This always returns a valid pointer regardless of whether or not
* the file on disk has an ID3v2 tag. Use hasID3v2Tag() to check if the
* file on disk actually has an ID3v2 tag.
*
* \see hasID3v2Tag()
*/
virtual ID3v2::Tag *ID3v2Tag() const;
/*!
* Returns the DSDIFF DIIN Tag for this file
*
*/
DSDIFF::DIIN::Tag *DIINTag() const;
/*!
* Implements the unified property interface -- export function.
* This method forwards to ID3v2::Tag::properties().
*/
PropertyMap properties() const;
void removeUnsupportedProperties(const StringList &properties);
/*!
* Implements the unified property interface -- import function.
* This method forwards to ID3v2::Tag::setProperties().
*/
PropertyMap setProperties(const PropertyMap &);
/*!
* Returns the DSDIFF::Properties for this file. If no audio properties
* were read then this will return a null pointer.
*/
virtual AudioProperties *audioProperties() const;
/*!
* Save the file. If at least one tag -- ID3v1 or DIIN -- exists this
* will duplicate its content into the other tag. This returns true
* if saving was successful.
*
* If neither exists or if both tags are empty, this will strip the tags
* from the file.
*
* This is the same as calling save(AllTags);
*
* If you would like more granular control over the content of the tags,
* with the concession of generality, use paramaterized save call below.
*
* \see save(int tags)
*/
virtual bool save();
/*!
* Save the file. This will attempt to save all of the tag types that are
* specified by OR-ing together TagTypes values. The save() method above
* uses AllTags. This returns true if saving was successful.
*
* This strips all tags not included in the mask, but does not modify them
* in memory, so later calls to save() which make use of these tags will
* remain valid. This also strips empty tags.
*/
bool save(int tags);
/*!
* Returns whether or not the file on disk actually has an ID3v2 tag.
*
* \see ID3v2Tag()
*/
bool hasID3v2Tag() const;
/*!
* Returns whether or not the file on disk actually has the DSDIFF
* Title & Artist tag.
*
* \see DIINTag()
*/
bool hasDIINTag() const;
/*!
* Returns whether or not the given \a stream can be opened as a DSDIFF
* file.
*
* \note This method is designed to do a quick check. The result may
* not necessarily be correct.
*/
static bool isSupported(IOStream *stream);
protected:
enum Endianness { BigEndian, LittleEndian };
File(FileName file, Endianness endianness);
File(IOStream *stream, Endianness endianness);
private:
File(const File &);
File &operator=(const File &);
/*!
* Sets the data for the the specified chunk at root level to \a data.
*
* \warning This will update the file immediately.
*/
void setRootChunkData(unsigned int i, const ByteVector &data);
/*!
* Sets the data for the root-level chunk \a name to \a data.
* If a root-level chunk with the given name already exists
* it will be overwritten, otherwise it will be
* created after the existing chunks.
*
* \warning This will update the file immediately.
*/
void setRootChunkData(const ByteVector &name, const ByteVector &data);
/*!
* Sets the data for the the specified child chunk to \a data.
*
* If data is null, then remove the chunk
*
* \warning This will update the file immediately.
*/
void setChildChunkData(unsigned int i, const ByteVector &data,
unsigned int childChunkNum);
/*!
* Sets the data for the child chunk \a name to \a data. If a chunk with
* the given name already exists it will be overwritten, otherwise it will
* be created after the existing chunks inside child chunk.
*
* If data is null, then remove the chunks with \a name name
*
* \warning This will update the file immediately.
*/
void setChildChunkData(const ByteVector &name, const ByteVector &data,
unsigned int childChunkNum);
void updateRootChunksStructure(unsigned int startingChunk);
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;
FilePrivate *d;
};
}
}
#endif

View File

@@ -0,0 +1,117 @@
/***************************************************************************
copyright : (C) 2016 by Damien Plisson, Audirvana
email : damien78@audirvana.com
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <tstring.h>
#include <tdebug.h>
#include "dsdiffproperties.h"
using namespace TagLib;
class DSDIFF::AudioProperties::AudioPropertiesPrivate
{
public:
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::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->sampleCount = samplesCount;
d->sampleWidth = 1;
d->sampleRate = sampleRate;
d->bitrate = bitrate;
d->length = d->sampleRate > 0
? static_cast<int>((d->sampleCount * 1000.0) / d->sampleRate + 0.5)
: 0;
}
DSDIFF::AudioProperties::~AudioProperties()
{
delete d;
}
int DSDIFF::AudioProperties::length() const
{
return lengthInSeconds();
}
int DSDIFF::AudioProperties::lengthInSeconds() const
{
return d->length / 1000;
}
int DSDIFF::AudioProperties::lengthInMilliseconds() const
{
return d->length;
}
int DSDIFF::AudioProperties::bitrate() const
{
return d->bitrate;
}
int DSDIFF::AudioProperties::sampleRate() const
{
return d->sampleRate;
}
int DSDIFF::AudioProperties::channels() const
{
return d->channels;
}
int DSDIFF::AudioProperties::bitsPerSample() const
{
return d->sampleWidth;
}
long long DSDIFF::AudioProperties::sampleCount() const
{
return d->sampleCount;
}

View File

@@ -0,0 +1,83 @@
/***************************************************************************
copyright : (C) 2016 by Damien Plisson, Audirvana
email : damien78@audirvana.com
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifndef TAGLIB_DSDIFFPROPERTIES_H
#define TAGLIB_DSDIFFPROPERTIES_H
#include "audioproperties.h"
namespace TagLib {
namespace DSDIFF {
class File;
//! An implementation of audio property reading for DSDIFF
/*!
* This reads the data from an DSDIFF stream found in the AudioProperties
* API.
*/
class TAGLIB_EXPORT AudioProperties : public TagLib::AudioProperties
{
public:
/*!
* Create an instance of DSDIFF::AudioProperties with the data read from the
* ByteVector \a data.
*/
AudioProperties(const unsigned int sampleRate, const unsigned short channels,
const unsigned long long samplesCount, const int bitrate,
ReadStyle style);
/*!
* Destroys this DSDIFF::AudioProperties instance.
*/
virtual ~AudioProperties();
// 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 bitsPerSample() const;
long long sampleCount() const;
private:
AudioProperties(const AudioProperties &);
AudioProperties &operator=(const AudioProperties &);
class AudioPropertiesPrivate;
AudioPropertiesPrivate *d;
};
}
}
#endif

234
taglib/dsf/dsffile.cpp Normal file
View File

@@ -0,0 +1,234 @@
/***************************************************************************
copyright : (C) 2013 - 2018 by Stephen F. Booth
email : me@sbooth.org
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <tbytevector.h>
#include <tdebug.h>
#include <id3v2tag.h>
#include <tstringlist.h>
#include <tpropertymap.h>
#include <tsmartptr.h>
#include <tagutils.h>
#include "dsffile.h"
using namespace TagLib;
// The DSF specification is located at http://dsd-guide.com/sites/default/files/white-papers/DSFFileFormatSpec_E.pdf
class DSF::File::FilePrivate
{
public:
FilePrivate() :
fileSize(0),
metadataOffset(0) {}
long long fileSize;
long long metadataOffset;
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 ");
}
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
DSF::File::File(FileName file, bool readProperties,
AudioProperties::ReadStyle propertiesStyle) :
TagLib::File(file),
d(new FilePrivate())
{
if(isOpen())
read(readProperties, propertiesStyle);
}
DSF::File::File(IOStream *stream, bool readProperties,
AudioProperties::ReadStyle propertiesStyle) :
TagLib::File(stream),
d(new FilePrivate())
{
if(isOpen())
read(readProperties, propertiesStyle);
}
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();
}
PropertyMap DSF::File::setProperties(const PropertyMap &properties)
{
return d->tag->setProperties(properties);
}
bool DSF::File::save()
{
if(readOnly()) {
debug("DSF::File::save() -- File is read only.");
return false;
}
if(!isValid()) {
debug("DSF::File::save() -- Trying to save invalid file.");
return false;
}
// Three things must be updated: the file size, the tag data, and the metadata offset
if(d->tag->isEmpty()) {
long long newFileSize = d->metadataOffset ? d->metadataOffset : d->fileSize;
// Update the file size
if(d->fileSize != newFileSize) {
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::fromUInt64LE(0ULL), 20, 8);
d->metadataOffset = 0;
}
// Delete the old tag
truncate(newFileSize);
}
else {
ByteVector tagData = d->tag->render();
long long newMetadataOffset = d->metadataOffset ? d->metadataOffset : d->fileSize;
long long newFileSize = newMetadataOffset + tagData.size();
long long oldTagSize = d->fileSize - newMetadataOffset;
// Update the file size
if(d->fileSize != newFileSize) {
insert(ByteVector::fromUInt64LE(newFileSize), 12, 8);
d->fileSize = newFileSize;
}
// Update the metadata offset
if(d->metadataOffset != newMetadataOffset) {
insert(ByteVector::fromUInt64LE(newMetadataOffset), 20, 8);
d->metadataOffset = newMetadataOffset;
}
// Delete the old tag and write the new one
insert(tagData, newMetadataOffset, static_cast<size_t>(oldTagSize));
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
// 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
// DSD chunk
ByteVector chunkName = readBlock(4);
if(chunkName != "DSD ") {
debug("DSF::File::read() -- Not a DSF file.");
setValid(false);
return;
}
long long chunkSize = readBlock(8).toInt64LE(0);
// Integrity check
if(28 != chunkSize) {
debug("DSF::File::read() -- File is corrupted.");
setValid(false);
return;
}
d->fileSize = readBlock(8).toInt64LE(0);
// File is malformed or corrupted
if(d->fileSize != length()) {
debug("DSF::File::read() -- File is corrupted.");
setValid(false);
return;
}
d->metadataOffset = readBlock(8).toInt64LE(0);
// File is malformed or corrupted
if(d->metadataOffset > d->fileSize) {
debug("DSF::File::read() -- Invalid metadata offset.");
setValid(false);
return;
}
// Format chunk
chunkName = readBlock(4);
if(chunkName != "fmt ") {
debug("DSF::File::read() -- Missing 'fmt ' chunk.");
setValid(false);
return;
}
chunkSize = readBlock(8).toInt64LE(0);
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(0 == d->metadataOffset)
d->tag.reset(new ID3v2::Tag());
else
d->tag.reset(new ID3v2::Tag(this, d->metadataOffset));
}

127
taglib/dsf/dsffile.h Normal file
View File

@@ -0,0 +1,127 @@
/***************************************************************************
copyright : (C) 2013 - 2018 by Stephen F. Booth
email : me@sbooth.org
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifndef TAGLIB_DSFFILE_H
#define TAGLIB_DSFFILE_H
#include "tfile.h"
#include "id3v2tag.h"
#include "dsfproperties.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 {
//! An implementation of TagLib::File with DSF specific methods
/*!
* 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.
*/
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);
/*!
* 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);
/*!
* Destroys this instance of the File.
*/
virtual ~File();
/*!
* Returns the Tag for this file.
*/
virtual ID3v2::Tag *tag() const;
/*!
* Returns the DSF::AudioProperties for this file. If no audio properties
* were read then this will return a null pointer.
*/
virtual AudioProperties *audioProperties() const;
/*!
* Implements the unified property interface -- export function.
* This method forwards to ID3v2::Tag::properties().
*/
virtual PropertyMap properties() const;
/*!
* Implements the unified property interface -- import function.
* This method forwards to ID3v2::Tag::setProperties().
*/
virtual PropertyMap setProperties(const PropertyMap &);
/*!
* Saves the file.
*/
virtual bool save();
/*!
* 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;
};
}
}
#endif

View File

@@ -0,0 +1,158 @@
/***************************************************************************
copyright : (C) 2013 by Stephen F. Booth
email : me@sbooth.org
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <tstring.h>
#include <tdebug.h>
#include "dsfproperties.h"
using namespace TagLib;
class DSF::AudioProperties::PropertiesPrivate
{
public:
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;
unsigned int formatID;
unsigned int channelType;
unsigned int channelNum;
unsigned int samplingFrequency;
unsigned int bitsPerSample;
long long sampleCount;
unsigned int blockSizePerChannel;
// Computed
int bitrate;
int length;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
DSF::AudioProperties::AudioProperties(const ByteVector &data, ReadStyle style) :
d(new PropertiesPrivate())
{
read(data);
}
DSF::AudioProperties::~AudioProperties()
{
delete d;
}
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::AudioProperties::bitrate() const
{
return d->bitrate;
}
int DSF::AudioProperties::sampleRate() const
{
return d->samplingFrequency;
}
int DSF::AudioProperties::channels() const
{
return d->channelNum;
}
// DSF specific
int DSF::AudioProperties::formatVersion() const
{
return d->formatVersion;
}
int DSF::AudioProperties::formatID() const
{
return d->formatID;
}
int DSF::AudioProperties::channelType() const
{
return d->channelType;
}
int DSF::AudioProperties::bitsPerSample() const
{
return d->bitsPerSample;
}
long long DSF::AudioProperties::sampleCount() const
{
return d->sampleCount;
}
int DSF::AudioProperties::blockSizePerChannel() const
{
return d->blockSizePerChannel;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void DSF::AudioProperties::read(const ByteVector &data)
{
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<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

@@ -0,0 +1,91 @@
/***************************************************************************
copyright : (C) 2013 by Stephen F. Booth
email : me@sbooth.org
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifndef TAGLIB_DSFPROPERTIES_H
#define TAGLIB_DSFPROPERTIES_H
#include "audioproperties.h"
namespace TagLib {
namespace DSF {
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:
/*!
* Create an instance of DSF::AudioProperties with the data read from the
* ByteVector \a data.
*/
AudioProperties(const ByteVector &data, ReadStyle style);
/*!
* Destroys this DSF::AudioProperties instance.
*/
virtual ~AudioProperties();
// 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;
/*!
* Channel type values: 1 = mono, 2 = stereo, 3 = 3 channels,
* 4 = quad, 5 = 4 channels, 6 = 5 channels, 7 = 5.1 channels
*/
int channelType() const;
int bitsPerSample() const;
long long sampleCount() const;
int blockSizePerChannel() const;
private:
AudioProperties(const AudioProperties &);
AudioProperties &operator=(const AudioProperties &);
void read(const ByteVector &data);
class PropertiesPrivate;
PropertiesPrivate *d;
};
}
}
#endif

View File

@@ -0,0 +1,58 @@
/***************************************************************************
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_EBML_CONSTANTS
#define TAGLIB_EBML_CONSTANTS
namespace TagLib {
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;
}
}
}
#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

@@ -28,9 +28,10 @@
***************************************************************************/
#include <tfile.h>
#include <tfilestream.h>
#include <tstring.h>
#include <tdebug.h>
#include <trefcounter.h>
#include <tsmartptr.h>
#include "fileref.h"
#include "asffile.h"
@@ -51,6 +52,9 @@
#include "s3mfile.h"
#include "itfile.h"
#include "xmfile.h"
#include "dsffile.h"
#include "dsdifffile.h"
#include "ebmlmatroskafile.h"
using namespace TagLib;
@@ -59,49 +63,14 @@ namespace
typedef List<const FileRef::FileTypeResolver *> ResolverList;
ResolverList fileTypeResolvers;
// Templatized internal functions. T should be String or IOStream*.
// Detect the file type by user-defined resolvers.
template <typename T>
FileName toFileName(T arg)
{
debug("FileRef::toFileName<T>(): This version should never be called.");
return FileName(L"");
}
template <>
FileName toFileName<IOStream *>(IOStream *arg)
{
return arg->name();
}
template <>
FileName toFileName<FileName>(FileName arg)
{
return arg;
}
template <typename T>
File *resolveFileType(T arg, bool readProperties,
AudioProperties::ReadStyle style)
{
debug("FileRef::resolveFileType<T>(): This version should never be called.");
return 0;
}
template <>
File *resolveFileType<IOStream *>(IOStream *arg, bool readProperties,
AudioProperties::ReadStyle style)
{
return 0;
}
template <>
File *resolveFileType<FileName>(FileName arg, bool readProperties,
AudioProperties::ReadStyle style)
File *detectByResolvers(FileName fileName, bool readAudioProperties,
AudioProperties::ReadStyle audioPropertiesStyle)
{
ResolverList::ConstIterator it = fileTypeResolvers.begin();
for(; it != fileTypeResolvers.end(); ++it) {
File *file = (*it)->createFile(arg, readProperties, style);
File *file = (*it)->createFile(fileName, readAudioProperties, audioPropertiesStyle);
if(file)
return file;
}
@@ -109,23 +78,20 @@ namespace
return 0;
}
template <typename T>
File* createInternal(T arg, bool readAudioProperties,
AudioProperties::ReadStyle audioPropertiesStyle)
{
File *file = resolveFileType(arg, readAudioProperties, audioPropertiesStyle);
if(file)
return file;
// Detect the file type based on the file extension.
File* detectByExtension(IOStream *stream, bool readAudioProperties,
AudioProperties::ReadStyle audioPropertiesStyle)
{
#ifdef _WIN32
const String s = toFileName(arg).toString();
const String s(stream->name().wstr());
#else
const String s(toFileName(arg));
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
@@ -135,66 +101,129 @@ namespace
if(ext.isEmpty())
return 0;
// .oga can be any audio in the Ogg container. So leave it to content-based detection.
if(ext == "MP3")
return new MPEG::File(arg, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle);
return new MPEG::File(stream, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle);
if(ext == "OGG")
return new Ogg::Vorbis::File(arg, readAudioProperties, audioPropertiesStyle);
if(ext == "OGA") {
/* .oga can be any audio in the Ogg container. First try FLAC, then Vorbis. */
File *file = new Ogg::FLAC::File(arg, readAudioProperties, audioPropertiesStyle);
if(file->isValid())
return file;
delete file;
return new Ogg::Vorbis::File(arg, readAudioProperties, audioPropertiesStyle);
}
return new Ogg::Vorbis::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "FLAC")
return new FLAC::File(arg, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle);
return new FLAC::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "MPC")
return new MPC::File(arg, readAudioProperties, audioPropertiesStyle);
return new MPC::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "WV")
return new WavPack::File(arg, readAudioProperties, audioPropertiesStyle);
return new WavPack::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "SPX")
return new Ogg::Speex::File(arg, readAudioProperties, audioPropertiesStyle);
return new Ogg::Speex::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "OPUS")
return new Ogg::Opus::File(arg, readAudioProperties, audioPropertiesStyle);
return new Ogg::Opus::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "TTA")
return new TrueAudio::File(arg, readAudioProperties, audioPropertiesStyle);
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(arg, readAudioProperties, audioPropertiesStyle);
return new MP4::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "WMA" || ext == "ASF")
return new ASF::File(arg, readAudioProperties, audioPropertiesStyle);
return new ASF::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "AIF" || ext == "AIFF" || ext == "AFC" || ext == "AIFC")
return new RIFF::AIFF::File(arg, readAudioProperties, audioPropertiesStyle);
return new RIFF::AIFF::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "WAV")
return new RIFF::WAV::File(arg, readAudioProperties, audioPropertiesStyle);
return new RIFF::WAV::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "APE")
return new APE::File(arg, readAudioProperties, audioPropertiesStyle);
return new APE::File(stream, readAudioProperties, audioPropertiesStyle);
// module, nst and wow are possible but uncommon extensions
if(ext == "MOD" || ext == "MODULE" || ext == "NST" || ext == "WOW")
return new Mod::File(arg, readAudioProperties, audioPropertiesStyle);
return new Mod::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "S3M")
return new S3M::File(arg, readAudioProperties, audioPropertiesStyle);
return new S3M::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "IT")
return new IT::File(arg, readAudioProperties, audioPropertiesStyle);
return new IT::File(stream, readAudioProperties, audioPropertiesStyle);
if(ext == "XM")
return new XM::File(arg, readAudioProperties, audioPropertiesStyle);
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 0;
}
}
class FileRef::FileRefPrivate : public RefCounter
{
public:
FileRefPrivate(File *f) :
RefCounter(),
file(f) {}
// Detect the file type based on the actual content of the stream.
~FileRefPrivate() {
delete file;
File *detectByContent(IOStream *stream, bool readAudioProperties,
AudioProperties::ReadStyle audioPropertiesStyle)
{
File *file = 0;
if(MPEG::File::isSupported(stream))
file = new MPEG::File(stream, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle);
else if(Ogg::Vorbis::File::isSupported(stream))
file = new Ogg::Vorbis::File(stream, readAudioProperties, audioPropertiesStyle);
else if(Ogg::FLAC::File::isSupported(stream))
file = new Ogg::FLAC::File(stream, readAudioProperties, audioPropertiesStyle);
else if(FLAC::File::isSupported(stream))
file = new FLAC::File(stream, readAudioProperties, audioPropertiesStyle);
else if(MPC::File::isSupported(stream))
file = new MPC::File(stream, readAudioProperties, audioPropertiesStyle);
else if(WavPack::File::isSupported(stream))
file = new WavPack::File(stream, readAudioProperties, audioPropertiesStyle);
else if(Ogg::Speex::File::isSupported(stream))
file = new Ogg::Speex::File(stream, readAudioProperties, audioPropertiesStyle);
else if(Ogg::Opus::File::isSupported(stream))
file = new Ogg::Opus::File(stream, readAudioProperties, audioPropertiesStyle);
else if(TrueAudio::File::isSupported(stream))
file = new TrueAudio::File(stream, readAudioProperties, audioPropertiesStyle);
else if(MP4::File::isSupported(stream))
file = new MP4::File(stream, readAudioProperties, audioPropertiesStyle);
else if(ASF::File::isSupported(stream))
file = new ASF::File(stream, readAudioProperties, audioPropertiesStyle);
else if(RIFF::AIFF::File::isSupported(stream))
file = new RIFF::AIFF::File(stream, readAudioProperties, audioPropertiesStyle);
else if(RIFF::WAV::File::isSupported(stream))
file = new RIFF::WAV::File(stream, readAudioProperties, audioPropertiesStyle);
else if(APE::File::isSupported(stream))
file = new APE::File(stream, readAudioProperties, audioPropertiesStyle);
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;
else
delete file;
}
return 0;
}
File *file;
struct FileRefData
{
FileRefData() :
file(0),
stream(0) {}
~FileRefData() {
delete file;
delete stream;
}
File *file;
IOStream *stream;
};
}
class FileRef::FileRefPrivate
{
public:
FileRefPrivate() :
data(new FileRefData()) {}
SHARED_PTR<FileRefData> data;
};
////////////////////////////////////////////////////////////////////////////////
@@ -202,36 +231,37 @@ public:
////////////////////////////////////////////////////////////////////////////////
FileRef::FileRef() :
d(new FileRefPrivate(0))
d(new FileRefPrivate())
{
}
FileRef::FileRef(FileName fileName, bool readAudioProperties,
AudioProperties::ReadStyle audioPropertiesStyle) :
d(new FileRefPrivate(createInternal(fileName, readAudioProperties, audioPropertiesStyle)))
d(new FileRefPrivate())
{
parse(fileName, readAudioProperties, audioPropertiesStyle);
}
FileRef::FileRef(IOStream* stream, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) :
d(new FileRefPrivate(createInternal(stream, readAudioProperties, audioPropertiesStyle)))
d(new FileRefPrivate())
{
parse(stream, readAudioProperties, audioPropertiesStyle);
}
FileRef::FileRef(File *file) :
d(new FileRefPrivate(file))
d(new FileRefPrivate())
{
d->data->file = file;
}
FileRef::FileRef(const FileRef &ref) :
d(ref.d)
d(new FileRefPrivate(*ref.d))
{
d->ref();
}
FileRef::~FileRef()
{
if(d->deref())
delete d;
delete d;
}
Tag *FileRef::tag() const
@@ -240,7 +270,37 @@ Tag *FileRef::tag() const
debug("FileRef::tag() - Called without a valid file.");
return 0;
}
return d->file->tag();
return d->data->file->tag();
}
PropertyMap FileRef::properties() const
{
if(isNull()) {
debug("FileRef::properties() - Called without a valid file.");
return PropertyMap();
}
return d->data->file->properties();
}
void FileRef::removeUnsupportedProperties(const StringList& properties)
{
if(isNull()) {
debug("FileRef::removeUnsupportedProperties() - Called without a valid file.");
return;
}
d->data->file->removeUnsupportedProperties(properties);
}
PropertyMap FileRef::setProperties(const PropertyMap &properties)
{
if(isNull()) {
debug("FileRef::setProperties() - Called without a valid file.");
return PropertyMap();
}
return d->data->file->setProperties(properties);
}
AudioProperties *FileRef::audioProperties() const
@@ -249,12 +309,12 @@ AudioProperties *FileRef::audioProperties() const
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()
@@ -263,7 +323,7 @@ bool FileRef::save()
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
@@ -304,13 +364,23 @@ StringList FileRef::defaultFileExtensions()
l.append("s3m");
l.append("it");
l.append("xm");
l.append("dsf");
l.append("dff");
l.append("dsdiff"); // alias for "dff"
l.append("mka");
l.append("mkv");
return l;
}
bool FileRef::isValid() const
{
return (d->data->file && d->data->file->isValid());
}
bool FileRef::isNull() const
{
return (!d->file || !d->file->isValid());
return !isValid();
}
FileRef &FileRef::operator=(const FileRef &ref)
@@ -328,16 +398,58 @@ void FileRef::swap(FileRef &ref)
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);
}
File *FileRef::create(FileName fileName, bool readAudioProperties,
AudioProperties::ReadStyle audioPropertiesStyle) // static
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void FileRef::parse(FileName fileName, bool readAudioProperties,
AudioProperties::ReadStyle audioPropertiesStyle)
{
return createInternal(fileName, readAudioProperties, audioPropertiesStyle);
// Try user-defined resolvers.
d->data->file = detectByResolvers(fileName, readAudioProperties, audioPropertiesStyle);
if(d->data->file)
return;
// Try to resolve file types based on the file extension.
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->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->data->stream;
d->data->stream = 0;
}
void FileRef::parse(IOStream *stream, bool readAudioProperties,
AudioProperties::ReadStyle audioPropertiesStyle)
{
// User-defined resolvers won't work with a stream.
// Try to resolve file types based on the file extension.
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->data->file = detectByContent(stream, readAudioProperties, audioPropertiesStyle);
}

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 {
@@ -91,8 +91,9 @@ namespace TagLib {
class TAGLIB_EXPORT FileTypeResolver
{
TAGLIB_IGNORE_MISSING_DESTRUCTOR
public:
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
@@ -173,6 +174,41 @@ namespace TagLib {
*/
Tag *tag() const;
/*!
* Exports the tags of the file as dictionary mapping (human readable) tag
* names (uppercase Strings) to StringLists of tag values. Calls the according
* specialization in the File subclasses.
* For each metadata object of the file that could not be parsed into the PropertyMap
* format, the returend map's unsupportedData() list will contain one entry identifying
* that object (e.g. the frame type for ID3v2 tags). Use removeUnsupportedProperties()
* to remove (a subset of) them.
* For files that contain more than one tag (e.g. an MP3 with both an ID3v1 and an ID3v2
* tag) only the most "modern" one will be exported (ID3v2 in this case).
*/
PropertyMap properties() const;
/*!
* Removes unsupported properties, or a subset of them, from the file's metadata.
* The parameter \a properties must contain only entries from
* properties().unsupportedData().
*/
void removeUnsupportedProperties(const StringList& properties);
/*!
* Sets the tags of this File to those specified in \a properties. Calls the
* according specialization method in the subclasses of File to do the translation
* into the format-specific details.
* If some value(s) could not be written imported to the specific metadata format,
* the returned PropertyMap will contain those value(s). Otherwise it will be empty,
* indicating that no problems occured.
* With file types that support several tag formats (for instance, MP3 files can have
* ID3v1, ID3v2, and APEv2 tags), this function will create the most appropriate one
* (ID3v2 for MP3 files). Older formats will be updated as well, if they exist, but won't
* be taken into account for the return value of this function.
* See the documentation of the subclass implementations for detailed descriptions.
*/
PropertyMap setProperties(const PropertyMap &properties);
/*!
* Returns the audio properties for this FileRef. If no audio properties
* were read then this will returns a null pointer.
@@ -233,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;
@@ -259,23 +304,10 @@ namespace TagLib {
*/
bool operator!=(const FileRef &ref) const;
/*!
* A simple implementation of file type guessing. If \a readAudioProperties
* is true then the audio properties will be read using
* \a audioPropertiesStyle. If \a readAudioProperties is false then
* \a audioPropertiesStyle will be ignored.
*
* \note You generally shouldn't use this method, but instead the constructor
* directly.
*
* \deprecated
*/
static File *create(FileName fileName,
bool readAudioProperties = true,
AudioProperties::ReadStyle audioPropertiesStyle = AudioProperties::Average);
private:
void parse(FileName fileName, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle);
void parse(IOStream *stream, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle);
class FileRefPrivate;
FileRefPrivate *d;
};

View File

@@ -30,6 +30,7 @@
#include <tagunion.h>
#include <tpropertymap.h>
#include <tagutils.h>
#include <tsmartptr.h>
#include <id3v2header.h>
#include <id3v2tag.h>
@@ -45,70 +46,82 @@ using namespace TagLib;
namespace
{
typedef List<FLAC::MetadataBlock *> BlockList;
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 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),
properties(0),
flacStart(0),
streamStart(0),
scanned(false)
{
blocks.setAutoDelete(true);
}
~FilePrivate()
{
delete properties;
if(frameFactory)
ID3v2FrameFactory = frameFactory;
}
const ID3v2::FrameFactory *ID3v2FrameFactory;
long ID3v2Location;
long ID3v2OriginalSize;
long long ID3v2Location;
long long ID3v2OriginalSize;
long ID3v1Location;
long long ID3v1Location;
TagUnion tag;
TripleTagUnion tag;
Properties *properties;
SCOPED_PTR<AudioProperties> properties;
ByteVector xiphCommentData;
BlockList blocks;
long flacStart;
long streamStart;
long long flacStart;
long long streamStart;
bool scanned;
};
////////////////////////////////////////////////////////////////////////////////
// static members
////////////////////////////////////////////////////////////////////////////////
bool FLAC::File::isSupported(IOStream *stream)
{
// A FLAC file has an ID "fLaC" somewhere. An ID3v2 tag may precede.
const ByteVector buffer = Utils::readHeader(stream, bufferSize(), true);
return (buffer.find("fLaC") != ByteVector::npos());
}
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
FLAC::File::File(FileName file, bool readProperties, Properties::ReadStyle) :
TagLib::File(file),
d(new FilePrivate())
{
if(isOpen())
read(readProperties);
}
FLAC::File::File(FileName file, ID3v2::FrameFactory *frameFactory,
bool readProperties, Properties::ReadStyle) :
FLAC::File::File(FileName file, bool readProperties, AudioProperties::ReadStyle,
ID3v2::FrameFactory *frameFactory) :
TagLib::File(file),
d(new FilePrivate(frameFactory))
{
@@ -116,8 +129,8 @@ FLAC::File::File(FileName file, ID3v2::FrameFactory *frameFactory,
read(readProperties);
}
FLAC::File::File(IOStream *stream, ID3v2::FrameFactory *frameFactory,
bool readProperties, Properties::ReadStyle) :
FLAC::File::File(IOStream *stream, bool readProperties, AudioProperties::ReadStyle,
ID3v2::FrameFactory *frameFactory) :
TagLib::File(stream),
d(new FilePrivate(frameFactory))
{
@@ -135,24 +148,14 @@ 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);
}
FLAC::Properties *FLAC::File::audioProperties() const
FLAC::AudioProperties *FLAC::File::audioProperties() const
{
return d->properties;
return d->properties.get();
}
bool FLAC::File::save()
@@ -168,8 +171,8 @@ bool FLAC::File::save()
}
// Create new vorbis comments
Tag::duplicate(&d->tag, xiphComment(true), false);
if(!hasXiphComment())
Tag::duplicate(&d->tag, xiphComment(true), false);
d->xiphCommentData = xiphComment()->render(false);
@@ -178,30 +181,29 @@ bool FLAC::File::save()
for(BlockIterator it = d->blocks.begin(); it != d->blocks.end(); ++it) {
if((*it)->code() == MetadataBlock::VorbisComment) {
// Set the new Vorbis Comment block
delete *it;
d->blocks.erase(it);
break;
}
}
d->blocks.append(new UnknownMetadataBlock(MetadataBlock::VorbisComment, d->xiphCommentData));
d->blocks.append(SHARED_PTR<MetadataBlock>(
new UnknownMetadataBlock(MetadataBlock::VorbisComment, d->xiphCommentData)));
// Render data for the metadata blocks
ByteVector data;
for(BlockConstIterator it = d->blocks.begin(); it != d->blocks.end(); ++it) {
ByteVector blockData = (*it)->render();
ByteVector blockHeader = ByteVector::fromUInt(blockData.size());
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.
// TODO: Should be calculated in offset_t in taglib2.
long originalLength = d->streamStart - d->flacStart;
long paddingLength = originalLength - data.size() - 4;
long long originalLength = d->streamStart - d->flacStart;
long long paddingLength = originalLength - data.size() - 4;
if(paddingLength <= 0) {
paddingLength = MinPaddingLength;
@@ -209,7 +211,7 @@ bool FLAC::File::save()
else {
// Padding won't increase beyond 1% of the file size or 1MB.
long threshold = length() / 100;
long long threshold = length() / 100;
threshold = std::max(threshold, MinPaddingLength);
threshold = std::min(threshold, MaxPaddingLegnth);
@@ -217,14 +219,14 @@ bool FLAC::File::save()
paddingLength = MinPaddingLength;
}
ByteVector paddingHeader = ByteVector::fromUInt(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);
@@ -241,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);
@@ -256,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;
@@ -298,11 +300,7 @@ bool FLAC::File::save()
ID3v2::Tag *FLAC::File::ID3v2Tag(bool create)
{
if(!create || d->tag[FlacID3v2Index])
return static_cast<ID3v2::Tag *>(d->tag[FlacID3v2Index]);
d->tag.set(FlacID3v2Index, new ID3v2::Tag);
return static_cast<ID3v2::Tag *>(d->tag[FlacID3v2Index]);
return d->tag.access<ID3v2::Tag>(FlacID3v2Index, create);
}
ID3v1::Tag *FLAC::File::ID3v1Tag(bool create)
@@ -315,28 +313,11 @@ Ogg::XiphComment *FLAC::File::xiphComment(bool create)
return d->tag.access<Ogg::XiphComment>(FlacXiphIndex, create);
}
void FLAC::File::setID3v2FrameFactory(const ID3v2::FrameFactory *factory)
{
d->ID3v2FrameFactory = factory;
}
ByteVector FLAC::File::streamInfoData()
{
debug("FLAC::File::streamInfoData() -- This function is obsolete. Returning an empty ByteVector.");
return ByteVector();
}
long FLAC::File::streamLength()
{
debug("FLAC::File::streamLength() -- This function is obsolete. Returning zero.");
return 0;
}
List<FLAC::Picture *> FLAC::File::pictureList()
{
List<Picture *> pictures;
for(BlockConstIterator it = d->blocks.begin(); it != d->blocks.end(); ++it) {
Picture *picture = dynamic_cast<Picture *>(*it);
Picture *picture = dynamic_cast<Picture *>(it->get());
if(picture) {
pictures.append(picture);
}
@@ -346,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)
{
BlockIterator it = d->blocks.find(picture);
if(it != d->blocks.end())
d->blocks.erase(it);
if(del)
delete picture;
}
void FLAC::File::removePictures()
{
for(BlockIterator it = d->blocks.begin(); it != d->blocks.end(); ) {
if(dynamic_cast<Picture *>(*it)) {
delete *it;
if(dynamic_cast<Picture *>(it->get())) {
it = d->blocks.erase(it);
}
else {
@@ -441,14 +418,14 @@ void FLAC::File::read(bool readProperties)
const ByteVector infoData = d->blocks.front()->render();
long streamLength;
long long streamLength;
if(d->ID3v1Location >= 0)
streamLength = d->ID3v1Location - d->streamStart;
else
streamLength = length() - d->streamStart;
d->properties = new Properties(infoData, streamLength);
d->properties.reset(new AudioProperties(infoData, streamLength));
}
}
@@ -462,7 +439,7 @@ void FLAC::File::scan()
if(!isValid())
return;
long nextBlockOffset;
long long nextBlockOffset;
if(d->ID3v2Location >= 0)
nextBlockOffset = find("fLaC", d->ID3v2Location + d->ID3v2OriginalSize);
@@ -497,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
@@ -507,7 +484,9 @@ void FLAC::File::scan()
return;
}
if(blockLength == 0 && blockType != MetadataBlock::Padding) {
if(blockLength == 0
&& blockType != MetadataBlock::Padding && blockType != MetadataBlock::SeekTable)
{
debug("FLAC::File::scan() -- Zero-sized metadata block found");
setValid(false);
return;
@@ -520,33 +499,32 @@ void FLAC::File::scan()
return;
}
MetadataBlock *block = 0;
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) {
FLAC::Picture *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

@@ -83,18 +83,6 @@ 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.
*
* \deprecated This constructor will be dropped in favor of the one below
* in a future version.
*/
File(FileName file, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
/*!
* Constructs an FLAC file from \a file. If \a readProperties is true the
* file's audio properties will also be read.
@@ -104,27 +92,27 @@ namespace TagLib {
*
* \note In the current implementation, \a propertiesStyle is ignored.
*/
// BIC: merge with the above constructor
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 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.
*/
// BIC: merge with the above constructor
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.
@@ -141,16 +129,6 @@ namespace TagLib {
*/
virtual TagLib::Tag *tag() const;
/*!
* Implements the unified property interface -- export function.
* If the file contains more than one tag (e.g. XiphComment and ID3v1),
* only the first one (in the order XiphComment, ID3v2, ID3v1) will be
* converted to the PropertyMap.
*/
PropertyMap properties() const;
void removeUnsupportedProperties(const StringList &);
/*!
* Implements the unified property interface -- import function.
* This always creates a Xiph comment, if none exists. The return value
@@ -158,13 +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 &);
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.
*/
virtual Properties *audioProperties() const;
virtual AudioProperties *audioProperties() const;
/*!
* Save the file. This will primarily save the XiphComment, but
@@ -232,42 +210,15 @@ namespace TagLib {
*/
Ogg::XiphComment *xiphComment(bool create = false);
/*!
* Set the ID3v2::FrameFactory to something other than the default. This
* can be used to specify the way that ID3v2 frames will be interpreted
* when
*
* \see ID3v2FrameFactory
* \deprecated This value should be passed in via the constructor
*/
void setID3v2FrameFactory(const ID3v2::FrameFactory *factory);
/*!
* Returns the block of data used by FLAC::Properties for parsing the
* stream properties.
*
* \deprecated Always returns an empty vector.
*/
ByteVector streamInfoData(); // BIC: remove
/*!
* Returns the length of the audio-stream, used by FLAC::Properties for
* calculating the bitrate.
*
* \deprecated Always returns zero.
*/
long streamLength(); // BIC: remove
/*!
* Returns a list of pictures attached to the FLAC file.
*/
List<Picture *> pictureList();
/*!
* Removes an attached picture. If \a del is true the picture's memory
* will be freed; if it is false, it must be deleted by the user.
* 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.
@@ -318,6 +269,15 @@ namespace TagLib {
*/
bool hasID3v2Tag() const;
/*!
* Returns whether or not the given \a stream can be opened as a FLAC
* file.
*
* \note This method is designed to do a quick check. The result may
* not necessarily be correct.
*/
static bool isSupported(IOStream *stream);
private:
File(const File &);
File &operator=(const File &);

View File

@@ -50,14 +50,14 @@ public:
ByteVector data;
};
FLAC::Picture::Picture()
FLAC::Picture::Picture() :
d(new PicturePrivate())
{
d = new PicturePrivate;
}
FLAC::Picture::Picture(const ByteVector &data)
FLAC::Picture::Picture(const ByteVector &data) :
d(new PicturePrivate())
{
d = new PicturePrivate;
parse(data);
}
@@ -78,10 +78,10 @@ bool FLAC::Picture::parse(const ByteVector &data)
return false;
}
unsigned int pos = 0;
d->type = 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.");
@@ -89,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.");
@@ -97,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.");
@@ -119,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;
}

View File

@@ -89,7 +89,7 @@ namespace TagLib {
};
Picture();
Picture(const ByteVector &data);
explicit Picture(const ByteVector &data);
~Picture();
/*!
@@ -199,8 +199,6 @@ namespace TagLib {
PicturePrivate *d;
};
typedef List<Picture> PictureList;
}
}

View File

@@ -31,7 +31,7 @@
using namespace TagLib;
class FLAC::Properties::PropertiesPrivate
class FLAC::AudioProperties::PropertiesPrivate
{
public:
PropertiesPrivate() :
@@ -55,71 +55,64 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
FLAC::Properties::Properties(ByteVector data, long streamLength, ReadStyle style) :
AudioProperties(style),
FLAC::AudioProperties::AudioProperties(const ByteVector &data, long long streamLength, ReadStyle) :
TagLib::AudioProperties(),
d(new PropertiesPrivate())
{
read(data, streamLength);
}
FLAC::Properties::Properties(File *, ReadStyle style) :
AudioProperties(style),
d(new PropertiesPrivate())
{
debug("FLAC::Properties::Properties() - This constructor is no longer used.");
}
FLAC::Properties::~Properties()
FLAC::AudioProperties::~AudioProperties()
{
delete d;
}
int FLAC::Properties::length() const
int FLAC::AudioProperties::length() const
{
return lengthInSeconds();
}
int FLAC::Properties::lengthInSeconds() const
int FLAC::AudioProperties::lengthInSeconds() const
{
return d->length / 1000;
}
int FLAC::Properties::lengthInMilliseconds() const
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::sampleWidth() const
int FLAC::AudioProperties::sampleWidth() const
{
return bitsPerSample();
}
int FLAC::Properties::channels() const
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;
}
@@ -128,14 +121,14 @@ ByteVector FLAC::Properties::signature() const
// private members
////////////////////////////////////////////////////////////////////////////////
void FLAC::Properties::read(const ByteVector &data, long 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;
@@ -149,7 +142,7 @@ void FLAC::Properties::read(const ByteVector &data, long 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;
@@ -160,7 +153,7 @@ void FLAC::Properties::read(const ByteVector &data, long 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

@@ -42,27 +42,19 @@ 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.
*/
// BIC: switch to const reference
Properties(ByteVector data, long streamLength, ReadStyle style = Average);
AudioProperties(const ByteVector &data, long long streamLength, ReadStyle style = Average);
/*!
* Create an instance of FLAC::Properties with the data read from the
* FLAC::File \a file.
* Destroys this FLAC::AudioProperties instance.
*/
// BIC: remove
Properties(File *file, ReadStyle style = Average);
/*!
* Destroys this FLAC::Properties instance.
*/
virtual ~Properties();
virtual ~AudioProperties();
/*!
* Returns the length of the file in seconds. The length is rounded down to
@@ -80,16 +72,14 @@ namespace TagLib {
*
* \see lengthInMilliseconds()
*/
// BIC: make virtual
int lengthInSeconds() const;
virtual int lengthInSeconds() const;
/*!
* Returns the length of the file in milliseconds.
*
* \see lengthInSeconds()
*/
// BIC: make virtual
int lengthInMilliseconds() const;
virtual int lengthInMilliseconds() const;
/*!
* Returns the average bit rate of the file in kb/s.
@@ -134,10 +124,7 @@ namespace TagLib {
ByteVector signature() const;
private:
Properties(const Properties &);
Properties &operator=(const Properties &);
void read(const ByteVector &data, long streamLength);
void read(const ByteVector &data, long long streamLength);
class PropertiesPrivate;
PropertiesPrivate *d;

View File

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

View File

@@ -36,13 +36,13 @@ using namespace IT;
class IT::File::FilePrivate
{
public:
FilePrivate(AudioProperties::ReadStyle 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,
@@ -73,17 +73,7 @@ Mod::Tag *IT::File::tag() const
return &d->tag;
}
PropertyMap IT::File::properties() const
{
return d->tag.properties();
}
PropertyMap IT::File::setProperties(const PropertyMap &properties)
{
return d->tag.setProperties(properties);
}
IT::Properties *IT::File::audioProperties() const
IT::AudioProperties *IT::File::audioProperties() const
{
return &d->properties;
}
@@ -114,7 +104,7 @@ bool IT::File::save()
StringList lines = d->tag.comment().split("\n");
for(unsigned short i = 0; i < instrumentCount; ++ i) {
seek(192L + length + ((long)i << 2));
unsigned long instrumentOffset = 0;
unsigned int instrumentOffset = 0;
if(!readU32L(instrumentOffset))
return false;
@@ -129,7 +119,7 @@ bool IT::File::save()
for(unsigned short i = 0; i < sampleCount; ++ i) {
seek(192L + length + ((long)instrumentCount << 2) + ((long)i << 2));
unsigned long sampleOffset = 0;
unsigned int sampleOffset = 0;
if(!readU32L(sampleOffset))
return false;
@@ -156,14 +146,14 @@ bool IT::File::save()
unsigned short special = 0;
unsigned short messageLength = 0;
unsigned long messageOffset = 0;
unsigned int messageOffset = 0;
seek(46);
if(!readU16L(special))
return false;
unsigned long fileSize = 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;
@@ -181,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);
@@ -233,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((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;

View File

@@ -67,23 +67,11 @@ namespace TagLib {
Mod::Tag *tag() const;
/*!
* Forwards to Mod::Tag::properties().
* BIC: will be removed once File::toDict() is made virtual
*/
PropertyMap properties() const;
/*!
* Forwards to Mod::Tag::setProperties().
* BIC: will be removed once File::setProperties() is made virtual
*/
PropertyMap setProperties(const PropertyMap &);
/*!
* Returns the IT::Properties for this file. If no audio properties
* were read then this will return a null pointer.
*/
IT::Properties *audioProperties() const;
IT::AudioProperties *audioProperties() const;
/*!
* Save the file.

View File

@@ -1,4 +1,4 @@
/***************************************************************************
/***************************************************************************
copyright :(C) 2011 by Mathias Panzenböck
email : grosser.meister.morti@gmx.net
***************************************************************************/
@@ -29,7 +29,7 @@
using namespace TagLib;
using namespace IT;
class IT::Properties::PropertiesPrivate
class IT::AudioProperties::PropertiesPrivate
{
public:
PropertiesPrivate() :
@@ -47,9 +47,7 @@ public:
tempo(0),
bpmSpeed(0),
panningSeparation(0),
pitchWheelDepth(0)
{
}
pitchWheelDepth(0) {}
int channels;
unsigned short lengthInPatterns;
@@ -68,193 +66,201 @@ public:
unsigned char pitchWheelDepth;
};
IT::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) :
AudioProperties(propertiesStyle),
d(new PropertiesPrivate)
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
IT::AudioProperties::AudioProperties(AudioProperties::ReadStyle) :
TagLib::AudioProperties(),
d(new PropertiesPrivate())
{
}
IT::Properties::~Properties()
IT::AudioProperties::~AudioProperties()
{
delete d;
}
int IT::Properties::length() const
int IT::AudioProperties::length() const
{
return 0;
}
int IT::Properties::lengthInSeconds() const
int IT::AudioProperties::lengthInSeconds() const
{
return 0;
}
int IT::Properties::lengthInMilliseconds() const
int IT::AudioProperties::lengthInMilliseconds() const
{
return 0;
}
int IT::Properties::bitrate() const
int IT::AudioProperties::bitrate() const
{
return 0;
}
int IT::Properties::sampleRate() const
int IT::AudioProperties::sampleRate() const
{
return 0;
}
int IT::Properties::channels() const
int IT::AudioProperties::channels() const
{
return d->channels;
}
unsigned short IT::Properties::lengthInPatterns() const
unsigned short IT::AudioProperties::lengthInPatterns() const
{
return d->lengthInPatterns;
}
bool IT::Properties::stereo() const
bool IT::AudioProperties::stereo() const
{
return d->flags & Stereo;
}
unsigned short IT::Properties::instrumentCount() const
unsigned short IT::AudioProperties::instrumentCount() const
{
return d->instrumentCount;
}
unsigned short IT::Properties::sampleCount() const
unsigned short IT::AudioProperties::sampleCount() const
{
return d->sampleCount;
}
unsigned short IT::Properties::patternCount() const
unsigned short IT::AudioProperties::patternCount() const
{
return d->patternCount;
}
unsigned short IT::Properties::version() const
unsigned short IT::AudioProperties::version() const
{
return d->version;
}
unsigned short IT::Properties::compatibleVersion() const
unsigned short IT::AudioProperties::compatibleVersion() const
{
return d->compatibleVersion;
}
unsigned short IT::Properties::flags() const
unsigned short IT::AudioProperties::flags() const
{
return d->flags;
}
unsigned short IT::Properties::special() const
unsigned short IT::AudioProperties::special() const
{
return d->special;
}
unsigned char IT::Properties::globalVolume() const
unsigned char IT::AudioProperties::globalVolume() const
{
return d->globalVolume;
}
unsigned char IT::Properties::mixVolume() const
unsigned char IT::AudioProperties::mixVolume() const
{
return d->mixVolume;
}
unsigned char IT::Properties::tempo() const
unsigned char IT::AudioProperties::tempo() const
{
return d->tempo;
}
unsigned char IT::Properties::bpmSpeed() const
unsigned char IT::AudioProperties::bpmSpeed() const
{
return d->bpmSpeed;
}
unsigned char IT::Properties::panningSeparation() const
unsigned char IT::AudioProperties::panningSeparation() const
{
return d->panningSeparation;
}
unsigned char IT::Properties::pitchWheelDepth() const
unsigned char IT::AudioProperties::pitchWheelDepth() const
{
return d->pitchWheelDepth;
}
void IT::Properties::setChannels(int channels)
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void IT::AudioProperties::setChannels(int channels)
{
d->channels = channels;
}
void IT::Properties::setLengthInPatterns(unsigned short lengthInPatterns)
void IT::AudioProperties::setLengthInPatterns(unsigned short lengthInPatterns)
{
d->lengthInPatterns = lengthInPatterns;
}
void IT::Properties::setInstrumentCount(unsigned short instrumentCount)
void IT::AudioProperties::setInstrumentCount(unsigned short instrumentCount)
{
d->instrumentCount = instrumentCount;
}
void IT::Properties::setSampleCount(unsigned short sampleCount)
void IT::AudioProperties::setSampleCount(unsigned short sampleCount)
{
d->sampleCount = sampleCount;
}
void IT::Properties::setPatternCount(unsigned short patternCount)
void IT::AudioProperties::setPatternCount(unsigned short patternCount)
{
d->patternCount = patternCount;
}
void IT::Properties::setFlags(unsigned short flags)
void IT::AudioProperties::setFlags(unsigned short flags)
{
d->flags = flags;
}
void IT::Properties::setSpecial(unsigned short special)
void IT::AudioProperties::setSpecial(unsigned short special)
{
d->special = special;
}
void IT::Properties::setCompatibleVersion(unsigned short compatibleVersion)
void IT::AudioProperties::setCompatibleVersion(unsigned short compatibleVersion)
{
d->compatibleVersion = compatibleVersion;
}
void IT::Properties::setVersion(unsigned short version)
void IT::AudioProperties::setVersion(unsigned short version)
{
d->version = version;
}
void IT::Properties::setGlobalVolume(unsigned char globalVolume)
void IT::AudioProperties::setGlobalVolume(unsigned char globalVolume)
{
d->globalVolume = globalVolume;
}
void IT::Properties::setMixVolume(unsigned char mixVolume)
void IT::AudioProperties::setMixVolume(unsigned char mixVolume)
{
d->mixVolume = mixVolume;
}
void IT::Properties::setTempo(unsigned char tempo)
void IT::AudioProperties::setTempo(unsigned char tempo)
{
d->tempo = tempo;
}
void IT::Properties::setBpmSpeed(unsigned char bpmSpeed)
void IT::AudioProperties::setBpmSpeed(unsigned char bpmSpeed)
{
d->bpmSpeed = bpmSpeed;
}
void IT::Properties::setPanningSeparation(unsigned char panningSeparation)
void IT::AudioProperties::setPanningSeparation(unsigned char panningSeparation)
{
d->panningSeparation = panningSeparation;
}
void IT::Properties::setPitchWheelDepth(unsigned char pitchWheelDepth)
void IT::AudioProperties::setPitchWheelDepth(unsigned char pitchWheelDepth)
{
d->pitchWheelDepth = pitchWheelDepth;
}

View File

@@ -30,9 +30,15 @@
#include "audioproperties.h"
namespace TagLib {
namespace IT {
class TAGLIB_EXPORT Properties : public AudioProperties {
class File;
class TAGLIB_EXPORT AudioProperties : public TagLib::AudioProperties
{
friend class File;
public:
/*! Flag bits. */
enum {
@@ -52,8 +58,8 @@ namespace TagLib {
MidiConfEmbedded = 8
};
Properties(AudioProperties::ReadStyle propertiesStyle);
virtual ~Properties();
explicit AudioProperties(AudioProperties::ReadStyle propertiesStyle);
virtual ~AudioProperties();
int length() const;
int lengthInSeconds() const;
@@ -78,6 +84,7 @@ namespace TagLib {
unsigned char panningSeparation() const;
unsigned char pitchWheelDepth() const;
private:
void setChannels(int channels);
void setLengthInPatterns(unsigned short lengthInPatterns);
void setInstrumentCount(unsigned short instrumentCount);
@@ -94,10 +101,6 @@ namespace TagLib {
void setPanningSeparation(unsigned char panningSeparation);
void setPitchWheelDepth (unsigned char pitchWheelDepth);
private:
Properties(const Properties&);
Properties &operator=(const Properties&);
class PropertiesPrivate;
PropertiesPrivate *d;
};

View File

@@ -36,13 +36,13 @@ using namespace Mod;
class Mod::File::FilePrivate
{
public:
FilePrivate(AudioProperties::ReadStyle propertiesStyle)
explicit FilePrivate(AudioProperties::ReadStyle propertiesStyle)
: properties(propertiesStyle)
{
}
Mod::Tag tag;
Mod::Properties properties;
Mod::AudioProperties properties;
};
Mod::File::File(FileName file, bool readProperties,
@@ -73,21 +73,11 @@ Mod::Tag *Mod::File::tag() const
return &d->tag;
}
Mod::Properties *Mod::File::audioProperties() const
Mod::AudioProperties *Mod::File::audioProperties() const
{
return &d->properties;
}
PropertyMap Mod::File::properties() const
{
return d->tag.properties();
}
PropertyMap Mod::File::setProperties(const PropertyMap &properties)
{
return d->tag.setProperties(properties);
}
bool Mod::File::save()
{
if(readOnly()) {
@@ -97,13 +87,13 @@ bool Mod::File::save()
seek(0);
writeString(d->tag.title(), 20);
StringList lines = d->tag.comment().split("\n");
unsigned int n = std::min(lines.size(), d->properties.instrumentCount());
for(unsigned int i = 0; i < n; ++ i) {
size_t n = std::min<size_t>(lines.size(), d->properties.instrumentCount());
for(size_t i = 0; i < n; ++ i) {
writeString(lines[i], 22);
seek(8, Current);
}
for(unsigned int i = n; i < d->properties.instrumentCount(); ++ i) {
for(size_t i = n; i < d->properties.instrumentCount(); ++ i) {
writeString(String(), 22);
seek(8, Current);
}

View File

@@ -72,22 +72,11 @@ namespace TagLib {
Mod::Tag *tag() const;
/*!
* Implements the unified property interface -- export function.
* Forwards to Mod::Tag::properties().
*/
PropertyMap properties() const;
/*!
* Implements the unified property interface -- import function.
* Forwards to Mod::Tag::setProperties().
*/
PropertyMap setProperties(const PropertyMap &);
/*!
* Returns the Mod::Properties for this file. If no audio properties
* were read then this will return a null pointer.
*/
Mod::Properties *audioProperties() const;
Mod::AudioProperties *audioProperties() const;
/*!
* Save the file.

View File

@@ -38,20 +38,19 @@ Mod::FileBase::FileBase(IOStream *stream) : TagLib::File(stream)
{
}
void Mod::FileBase::writeString(const String &s, unsigned long size, char padding)
void Mod::FileBase::writeString(const String &s, unsigned int size, char padding)
{
ByteVector data(s.data(String::Latin1));
data.resize(size, padding);
writeBlock(data);
}
bool Mod::FileBase::readString(String &s, unsigned long size)
bool Mod::FileBase::readString(String &s, unsigned int size)
{
ByteVector data(readBlock(size));
if(data.size() < size) return false;
int index = data.find((char) 0);
if(index > -1)
{
const size_t index = data.find((char) 0);
if(index != ByteVector::npos()) {
data.resize(index);
}
data.replace('\xff', ' ');
@@ -68,22 +67,22 @@ void Mod::FileBase::writeByte(unsigned char byte)
void Mod::FileBase::writeU16L(unsigned short number)
{
writeBlock(ByteVector::fromShort(number, false));
writeBlock(ByteVector::fromUInt16LE(number));
}
void Mod::FileBase::writeU32L(unsigned long number)
void Mod::FileBase::writeU32L(unsigned int number)
{
writeBlock(ByteVector::fromUInt(number, false));
writeBlock(ByteVector::fromUInt32LE(number));
}
void Mod::FileBase::writeU16B(unsigned short number)
{
writeBlock(ByteVector::fromShort(number, true));
writeBlock(ByteVector::fromUInt16BE(number));
}
void Mod::FileBase::writeU32B(unsigned long number)
void Mod::FileBase::writeU32B(unsigned int number)
{
writeBlock(ByteVector::fromUInt(number, true));
writeBlock(ByteVector::fromUInt32BE(number));
}
bool Mod::FileBase::readByte(unsigned char &byte)
@@ -98,14 +97,14 @@ bool Mod::FileBase::readU16L(unsigned short &number)
{
ByteVector data(readBlock(2));
if(data.size() < 2) return false;
number = data.toUShort(false);
number = data.toUInt16LE(0);
return true;
}
bool Mod::FileBase::readU32L(unsigned long &number) {
bool Mod::FileBase::readU32L(unsigned int &number) {
ByteVector data(readBlock(4));
if(data.size() < 4) return false;
number = data.toUInt(false);
number = data.toUInt32LE(0);
return true;
}
@@ -113,13 +112,13 @@ bool Mod::FileBase::readU16B(unsigned short &number)
{
ByteVector data(readBlock(2));
if(data.size() < 2) return false;
number = data.toUShort(true);
number = data.toUInt16BE(0);
return true;
}
bool Mod::FileBase::readU32B(unsigned long &number) {
bool Mod::FileBase::readU32B(unsigned int &number) {
ByteVector data(readBlock(4));
if(data.size() < 4) return false;
number = data.toUInt(true);
number = data.toUInt32BE(0);
return true;
}

View File

@@ -41,22 +41,22 @@ namespace TagLib {
class TAGLIB_EXPORT FileBase : public TagLib::File
{
protected:
FileBase(FileName file);
FileBase(IOStream *stream);
explicit FileBase(FileName file);
explicit FileBase(IOStream *stream);
void writeString(const String &s, unsigned long size, char padding = 0);
void writeString(const String &s, unsigned int size, char padding = 0);
void writeByte(unsigned char byte);
void writeU16L(unsigned short number);
void writeU32L(unsigned long number);
void writeU32L(unsigned int number);
void writeU16B(unsigned short number);
void writeU32B(unsigned long number);
void writeU32B(unsigned int number);
bool readString(String &s, unsigned long size);
bool readString(String &s, unsigned int size);
bool readByte(unsigned char &byte);
bool readU16L(unsigned short &number);
bool readU32L(unsigned long &number);
bool readU32L(unsigned int &number);
bool readU16B(unsigned short &number);
bool readU32B(unsigned long &number);
bool readU32B(unsigned int &number);
};
}

View File

@@ -39,9 +39,9 @@
#define READ_BYTE(setter) READ(setter,unsigned char,readByte)
#define READ_U16L(setter) READ(setter,unsigned short,readU16L)
#define READ_U32L(setter) READ(setter,unsigned long,readU32L)
#define READ_U32L(setter) READ(setter,unsigned int,readU32L)
#define READ_U16B(setter) READ(setter,unsigned short,readU16B)
#define READ_U32B(setter) READ(setter,unsigned long,readU32B)
#define READ_U32B(setter) READ(setter,unsigned int,readU32B)
#define READ_STRING(setter,size) \
{ \
@@ -56,9 +56,9 @@
#define READ_BYTE_AS(name) READ_AS(unsigned char,name,readByte)
#define READ_U16L_AS(name) READ_AS(unsigned short,name,readU16L)
#define READ_U32L_AS(name) READ_AS(unsigned long,name,readU32L)
#define READ_U32L_AS(name) READ_AS(unsigned int,name,readU32L)
#define READ_U16B_AS(name) READ_AS(unsigned short,name,readU16B)
#define READ_U32B_AS(name) READ_AS(unsigned long,name,readU32B)
#define READ_U32B_AS(name) READ_AS(unsigned int,name,readU32B)
#define READ_STRING_AS(name,size) \
String name; \

View File

@@ -1,4 +1,4 @@
/***************************************************************************
/***************************************************************************
copyright : (C) 2011 by Mathias Panzenböck
email : grosser.meister.morti@gmx.net
***************************************************************************/
@@ -29,83 +29,89 @@
using namespace TagLib;
using namespace Mod;
class Mod::Properties::PropertiesPrivate
class Mod::AudioProperties::PropertiesPrivate
{
public:
PropertiesPrivate() :
channels(0),
instrumentCount(0),
lengthInPatterns(0)
{
}
lengthInPatterns(0) {}
int channels;
unsigned int instrumentCount;
unsigned char lengthInPatterns;
};
Mod::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) :
AudioProperties(propertiesStyle),
d(new PropertiesPrivate)
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
Mod::AudioProperties::AudioProperties(AudioProperties::ReadStyle) :
TagLib::AudioProperties(),
d(new PropertiesPrivate())
{
}
Mod::Properties::~Properties()
Mod::AudioProperties::~AudioProperties()
{
delete d;
}
int Mod::Properties::length() const
int Mod::AudioProperties::length() const
{
return 0;
}
int Mod::Properties::lengthInSeconds() const
int Mod::AudioProperties::lengthInSeconds() const
{
return 0;
}
int Mod::Properties::lengthInMilliseconds() const
int Mod::AudioProperties::lengthInMilliseconds() const
{
return 0;
}
int Mod::Properties::bitrate() const
int Mod::AudioProperties::bitrate() const
{
return 0;
}
int Mod::Properties::sampleRate() const
int Mod::AudioProperties::sampleRate() const
{
return 0;
}
int Mod::Properties::channels() const
int Mod::AudioProperties::channels() const
{
return d->channels;
}
unsigned int Mod::Properties::instrumentCount() const
unsigned int Mod::AudioProperties::instrumentCount() const
{
return d->instrumentCount;
}
unsigned char Mod::Properties::lengthInPatterns() const
unsigned char Mod::AudioProperties::lengthInPatterns() const
{
return d->lengthInPatterns;
}
void Mod::Properties::setChannels(int channels)
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void Mod::AudioProperties::setChannels(int channels)
{
d->channels = channels;
}
void Mod::Properties::setInstrumentCount(unsigned int instrumentCount)
void Mod::AudioProperties::setInstrumentCount(unsigned int instrumentCount)
{
d->instrumentCount = instrumentCount;
}
void Mod::Properties::setLengthInPatterns(unsigned char lengthInPatterns)
void Mod::AudioProperties::setLengthInPatterns(unsigned char lengthInPatterns)
{
d->lengthInPatterns = lengthInPatterns;
}

View File

@@ -33,11 +33,15 @@ namespace TagLib {
namespace Mod {
class TAGLIB_EXPORT Properties : public AudioProperties
class File;
class TAGLIB_EXPORT AudioProperties : public TagLib::AudioProperties
{
friend class File;
public:
Properties(AudioProperties::ReadStyle propertiesStyle);
virtual ~Properties();
explicit AudioProperties(AudioProperties::ReadStyle propertiesStyle);
virtual ~AudioProperties();
int length() const;
int lengthInSeconds() const;
@@ -49,17 +53,12 @@ namespace TagLib {
unsigned int instrumentCount() const;
unsigned char lengthInPatterns() const;
private:
void setChannels(int channels);
void setInstrumentCount(unsigned int sampleCount);
void setLengthInPatterns(unsigned char lengthInPatterns);
private:
friend class File;
Properties(const Properties&);
Properties &operator=(const Properties&);
class PropertiesPrivate;
PropertiesPrivate *d;
};

View File

@@ -27,6 +27,7 @@
#include "modtag.h"
#include "tstringlist.h"
#include "tpropertymap.h"
#include "tpicturemap.h"
using namespace TagLib;
using namespace Mod;
@@ -43,9 +44,10 @@ public:
String trackerName;
};
Mod::Tag::Tag() : TagLib::Tag()
Mod::Tag::Tag() :
TagLib::Tag(),
d(new TagPrivate())
{
d = new TagPrivate;
}
Mod::Tag::~Tag()
@@ -88,6 +90,11 @@ unsigned int Mod::Tag::track() const
return 0;
}
TagLib::PictureMap Mod::Tag::pictures() const
{
return PictureMap();
}
String Mod::Tag::trackerName() const
{
return d->trackerName;
@@ -123,6 +130,10 @@ void Mod::Tag::setTrack(unsigned int)
{
}
void Mod::Tag::setPictures(const PictureMap &l)
{
}
void Mod::Tag::setTrackerName(const String &trackerName)
{
d->trackerName = trackerName;

View File

@@ -88,6 +88,8 @@ namespace TagLib {
*/
virtual unsigned int track() const;
PictureMap pictures() const;
/*!
* Returns the name of the tracker used to create/edit the module file.
* Only XM files store this tag to the file as such, for other formats
@@ -151,6 +153,8 @@ namespace TagLib {
*/
virtual void setTrack(unsigned int track);
void setPictures(const PictureMap &l);
/*!
* Sets the tracker name to \a trackerName. If \a trackerName is
* String::null then this value will be cleared.

View File

@@ -23,18 +23,17 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <climits>
#include <tdebug.h>
#include <tstring.h>
#include "mp4atom.h"
using namespace TagLib;
const char *MP4::Atom::containers[11] = {
"moov", "udta", "mdia", "meta", "ilst",
"stbl", "minf", "moof", "traf", "trak",
"stsd"
"moov", "udta", "mdia", "meta", "ilst",
"stbl", "minf", "moof", "traf", "trak",
"stsd"
};
MP4::Atom::Atom(File *file)
@@ -52,26 +51,17 @@ MP4::Atom::Atom(File *file)
return;
}
length = header.toUInt();
length = header.toUInt32BE(0);
if(length == 1) {
const long long longLength = file->readBlock(8).toLongLong();
if(sizeof(long) == sizeof(long long)) {
length = static_cast<long>(longLength);
}
else {
if(longLength <= LONG_MAX) {
// The atom has a 64-bit length, but it's actually a 31-bit value
length = static_cast<long>(longLength);
}
else {
debug("MP4: 64-bit atoms are not supported");
length = 0;
file->seek(0, File::End);
return;
}
}
if(length == 0) {
// The last atom which extends to the end of the file.
length = file->length() - offset;
}
else if(length == 1) {
// The atom has a 64-bit length.
length = file->readBlock(8).toInt64BE(0);
}
if(length < 8) {
debug("MP4: Invalid atom size");
length = 0;
@@ -155,7 +145,7 @@ MP4::Atoms::Atoms(File *file)
atoms.setAutoDelete(true);
file->seek(0, File::End);
long end = file->tell();
long long end = file->tell();
file->seek(0);
while(file->tell() + 8 <= end) {
MP4::Atom *atom = new MP4::Atom(file);

View File

@@ -77,13 +77,13 @@ namespace TagLib {
class Atom
{
public:
Atom(File *file);
explicit Atom(File *file);
~Atom();
Atom *find(const char *name1, const char *name2 = 0, const char *name3 = 0, const char *name4 = 0);
bool path(AtomList &path, const char *name1, const char *name2 = 0, const char *name3 = 0);
AtomList findall(const char *name, bool recursive = false);
long offset;
long length;
long long offset;
long long length;
TagLib::ByteVector name;
AtomList children;
private:
@@ -95,7 +95,7 @@ namespace TagLib {
class Atoms
{
public:
Atoms(File *file);
explicit Atoms(File *file);
~Atoms();
Atom *find(const char *name1, const char *name2 = 0, const char *name3 = 0, const char *name4 = 0);
AtomList path(const char *name1, const char *name2 = 0, const char *name3 = 0, const char *name4 = 0);

View File

@@ -23,22 +23,33 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <taglib.h>
#include <tdebug.h>
#include "trefcounter.h"
#include "taglib.h"
#include "tdebug.h"
#include "tsmartptr.h"
#include "mp4coverart.h"
using namespace TagLib;
class MP4::CoverArt::CoverArtPrivate : public RefCounter
namespace
{
struct CoverArtData
{
MP4::CoverArt::Format format;
ByteVector data;
};
}
class MP4::CoverArt::CoverArtPrivate
{
public:
CoverArtPrivate() :
RefCounter(),
format(MP4::CoverArt::JPEG) {}
CoverArtPrivate(Format f, const ByteVector &v) :
data(new CoverArtData())
{
data->format = f;
data->data = v;
}
Format format;
ByteVector data;
SHARED_PTR<CoverArtData> data;
};
////////////////////////////////////////////////////////////////////////////////
@@ -46,16 +57,13 @@ public:
////////////////////////////////////////////////////////////////////////////////
MP4::CoverArt::CoverArt(Format format, const ByteVector &data) :
d(new CoverArtPrivate())
d(new CoverArtPrivate(format, data))
{
d->format = format;
d->data = data;
}
MP4::CoverArt::CoverArt(const CoverArt &item) :
d(item.d)
d(new CoverArtPrivate(*item.d))
{
d->ref();
}
MP4::CoverArt &
@@ -75,19 +83,17 @@ MP4::CoverArt::swap(CoverArt &item)
MP4::CoverArt::~CoverArt()
{
if(d->deref()) {
delete d;
}
delete d;
}
MP4::CoverArt::Format
MP4::CoverArt::format() const
{
return d->format;
return d->data->format;
}
ByteVector
MP4::CoverArt::data() const
{
return d->data;
return d->data->data;
}

View File

@@ -76,9 +76,7 @@ namespace TagLib {
};
typedef List<CoverArt> CoverArtList;
}
}
#endif

View File

@@ -26,6 +26,8 @@
#include <tdebug.h>
#include <tstring.h>
#include <tpropertymap.h>
#include <tagutils.h>
#include "mp4atom.h"
#include "mp4tag.h"
#include "mp4file.h"
@@ -64,11 +66,27 @@ public:
delete properties;
}
MP4::Tag *tag;
MP4::Atoms *atoms;
MP4::Properties *properties;
MP4::Tag *tag;
MP4::Atoms *atoms;
MP4::AudioProperties *properties;
};
////////////////////////////////////////////////////////////////////////////////
// static members
////////////////////////////////////////////////////////////////////////////////
bool MP4::File::isSupported(IOStream *stream)
{
// An MP4 file has to have an "ftyp" box first.
const ByteVector id = Utils::readHeader(stream, 8, false);
return id.containsAt("ftyp", 4);
}
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
MP4::File::File(FileName file, bool readProperties, AudioProperties::ReadStyle) :
TagLib::File(file),
d(new FilePrivate())
@@ -96,22 +114,7 @@ MP4::File::tag() const
return d->tag;
}
PropertyMap MP4::File::properties() const
{
return d->tag->properties();
}
void MP4::File::removeUnsupportedProperties(const StringList &properties)
{
d->tag->removeUnsupportedProperties(properties);
}
PropertyMap MP4::File::setProperties(const PropertyMap &properties)
{
return d->tag->setProperties(properties);
}
MP4::Properties *
MP4::AudioProperties *
MP4::File::audioProperties() const
{
return d->properties;
@@ -137,7 +140,7 @@ MP4::File::read(bool readProperties)
d->tag = new Tag(this, d->atoms);
if(readProperties) {
d->properties = new Properties(this, d->atoms);
d->properties = new AudioProperties(this, d->atoms);
}
}

View File

@@ -55,19 +55,19 @@ namespace TagLib {
* \note In the current implementation, \a propertiesStyle is ignored.
*/
File(FileName file, bool readProperties = true,
Properties::ReadStyle audioPropertiesStyle = Properties::Average);
AudioProperties::ReadStyle audioPropertiesStyle = AudioProperties::Average);
/*!
* Constructs an MP4 file from \a stream. If \a readProperties is true the
* Constructs an MP4 file from \a file. If \a readProperties is true the
* file's audio properties will also be read.
*
* \note In the current implementation, \a propertiesStyle is ignored.
*
* \note TagLib will *not* take ownership of the stream, the caller is
* responsible for deleting it after the File object.
*
* \note In the current implementation, \a propertiesStyle is ignored.
*/
File(IOStream *stream, bool readProperties = true,
Properties::ReadStyle audioPropertiesStyle = Properties::Average);
AudioProperties::ReadStyle audioPropertiesStyle = AudioProperties::Average);
/*!
* Destroys this instance of the File.
@@ -86,26 +86,10 @@ namespace TagLib {
*/
Tag *tag() const;
/*!
* Implements the unified property interface -- export function.
*/
PropertyMap properties() const;
/*!
* Removes unsupported properties. Forwards to the actual Tag's
* removeUnsupportedProperties() function.
*/
void removeUnsupportedProperties(const StringList &properties);
/*!
* Implements the unified property interface -- import function.
*/
PropertyMap setProperties(const PropertyMap &);
/*!
* Returns the MP4 audio properties for this file.
*/
Properties *audioProperties() const;
AudioProperties *audioProperties() const;
/*!
* Save the file.
@@ -120,6 +104,15 @@ namespace TagLib {
*/
bool hasMP4Tag() const;
/*!
* Returns whether or not the given \a stream can be opened as an ASF
* file.
*
* \note This method is designed to do a quick check. The result may
* not necessarily be correct.
*/
static bool isSupported(IOStream *stream);
private:
void read(bool readProperties);

View File

@@ -23,46 +23,58 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <taglib.h>
#include <tdebug.h>
#include "trefcounter.h"
#include "taglib.h"
#include "tdebug.h"
#include "tsmartptr.h"
#include "mp4item.h"
#include "tutils.h"
using namespace TagLib;
class MP4::Item::ItemPrivate : public RefCounter
namespace
{
struct ItemData
{
bool valid;
MP4::AtomDataType atomDataType;
MP4::Item::ItemType type;
union {
bool m_bool;
int m_int;
MP4::Item::IntPair m_intPair;
unsigned char m_byte;
unsigned int m_uint;
long long m_longlong;
};
StringList m_stringList;
ByteVectorList m_byteVectorList;
MP4::CoverArtList m_coverArtList;
};
}
class MP4::Item::ItemPrivate
{
public:
ItemPrivate() :
RefCounter(),
valid(true),
atomDataType(TypeUndefined) {}
data(new ItemData())
{
data->valid = true;
data->atomDataType = MP4::TypeUndefined;
data->type = MP4::Item::TypeUndefined;
}
bool valid;
AtomDataType atomDataType;
union {
bool m_bool;
int m_int;
IntPair m_intPair;
unsigned char m_byte;
unsigned int m_uint;
long long m_longlong;
};
StringList m_stringList;
ByteVectorList m_byteVectorList;
MP4::CoverArtList m_coverArtList;
SHARED_PTR<ItemData> data;
};
MP4::Item::Item() :
d(new ItemPrivate())
{
d->valid = false;
d->data->valid = false;
}
MP4::Item::Item(const Item &item) :
d(item.d)
d(new ItemPrivate(*item.d))
{
d->ref();
}
MP4::Item &
@@ -82,131 +94,176 @@ MP4::Item::swap(Item &item)
MP4::Item::~Item()
{
if(d->deref())
delete d;
delete d;
}
MP4::Item::Item(bool value) :
d(new ItemPrivate())
{
d->m_bool = value;
d->data->m_bool = value;
d->data->type = TypeBool;
}
MP4::Item::Item(int value) :
d(new ItemPrivate())
{
d->m_int = value;
d->data->m_int = value;
d->data->type = TypeInt;
}
MP4::Item::Item(unsigned char value) :
d(new ItemPrivate())
{
d->m_byte = value;
d->data->m_byte = value;
d->data->type = TypeByte;
}
MP4::Item::Item(unsigned int value) :
d(new ItemPrivate())
{
d->m_uint = value;
d->data->m_uint = value;
d->data->type = TypeUInt;
}
MP4::Item::Item(long long value) :
d(new ItemPrivate())
{
d->m_longlong = value;
d->data->m_longlong = value;
d->data->type = TypeLongLong;
}
MP4::Item::Item(int value1, int value2) :
d(new ItemPrivate())
{
d->m_intPair.first = value1;
d->m_intPair.second = value2;
d->data->m_intPair.first = value1;
d->data->m_intPair.second = value2;
d->data->type = TypeIntPair;
}
MP4::Item::Item(const ByteVectorList &value) :
d(new ItemPrivate())
{
d->m_byteVectorList = value;
d->data->m_byteVectorList = value;
d->data->type = TypeByteVectorList;
}
MP4::Item::Item(const StringList &value) :
d(new ItemPrivate())
{
d->m_stringList = value;
d->data->m_stringList = value;
d->data->type = TypeStringList;
}
MP4::Item::Item(const MP4::CoverArtList &value) :
d(new ItemPrivate())
{
d->m_coverArtList = value;
d->data->m_coverArtList = value;
d->data->type = TypeCoverArtList;
}
void MP4::Item::setAtomDataType(MP4::AtomDataType type)
{
d->atomDataType = type;
d->data->atomDataType = type;
}
MP4::AtomDataType MP4::Item::atomDataType() const
{
return d->atomDataType;
return d->data->atomDataType;
}
bool
MP4::Item::toBool() const
{
return d->m_bool;
return d->data->m_bool;
}
int
MP4::Item::toInt() const
{
return d->m_int;
return d->data->m_int;
}
unsigned char
MP4::Item::toByte() const
{
return d->m_byte;
return d->data->m_byte;
}
unsigned int
MP4::Item::toUInt() const
{
return d->m_uint;
return d->data->m_uint;
}
long long
MP4::Item::toLongLong() const
{
return d->m_longlong;
return d->data->m_longlong;
}
MP4::Item::IntPair
MP4::Item::toIntPair() const
{
return d->m_intPair;
return d->data->m_intPair;
}
StringList
MP4::Item::toStringList() const
{
return d->m_stringList;
return d->data->m_stringList;
}
ByteVectorList
MP4::Item::toByteVectorList() const
{
return d->m_byteVectorList;
return d->data->m_byteVectorList;
}
MP4::CoverArtList
MP4::Item::toCoverArtList() const
{
return d->m_coverArtList;
return d->data->m_coverArtList;
}
bool
MP4::Item::isValid() const
{
return d->valid;
return d->data->valid;
}
String
MP4::Item::toString() const
{
StringList desc;
switch (d->data->type) {
case TypeBool:
return d->data->m_bool ? "true" : "false";
case TypeInt:
return Utils::formatString("%d", d->data->m_int);
case TypeIntPair:
return Utils::formatString("%d/%d", d->data->m_intPair.first, d->data->m_intPair.second);
case TypeByte:
return Utils::formatString("%d", d->data->m_byte);
case TypeUInt:
return Utils::formatString("%u", d->data->m_uint);
case TypeLongLong:
return Utils::formatString("%lld", d->data->m_longlong);
case TypeStringList:
return d->data->m_stringList.toString(" / ");
case TypeByteVectorList:
for(size_t i = 0; i < d->data->m_byteVectorList.size(); i++) {
desc.append(Utils::formatString(
"[%d bytes of data]", static_cast<int>(d->data->m_byteVectorList[i].size())));
}
return desc.toString(", ");
case TypeCoverArtList:
for(size_t i = 0; i < d->data->m_coverArtList.size(); i++) {
desc.append(Utils::formatString(
"[%d bytes of data]", static_cast<int>(d->data->m_coverArtList[i].data().size())));
}
return desc.toString(", ");
case TypeUndefined:
return "[unknown]";
}
return String();
}

View File

@@ -41,6 +41,19 @@ namespace TagLib {
int first, second;
};
enum ItemType {
TypeUndefined = 0,
TypeBool,
TypeInt,
TypeIntPair,
TypeByte,
TypeUInt,
TypeLongLong,
TypeStringList,
TypeByteVectorList,
TypeCoverArtList,
};
Item();
Item(const Item &item);
@@ -79,8 +92,12 @@ namespace TagLib {
ByteVectorList toByteVectorList() const;
CoverArtList toCoverArtList() const;
ItemType type() const;
bool isValid() const;
String toString() const;
private:
class ItemPrivate;
ItemPrivate *d;

View File

@@ -31,7 +31,7 @@
using namespace TagLib;
class MP4::Properties::PropertiesPrivate
class MP4::AudioProperties::PropertiesPrivate
{
public:
PropertiesPrivate() :
@@ -41,7 +41,7 @@ public:
channels(0),
bitsPerSample(0),
encrypted(false),
codec(MP4::Properties::Unknown) {}
codec(MP4::AudioProperties::Unknown) {}
int length;
int bitrate;
@@ -56,78 +56,98 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
MP4::Properties::Properties(File *file, MP4::Atoms *atoms, ReadStyle style) :
AudioProperties(style),
MP4::AudioProperties::AudioProperties(File *file, MP4::Atoms *atoms, ReadStyle) :
TagLib::AudioProperties(),
d(new PropertiesPrivate())
{
read(file, atoms);
}
MP4::Properties::~Properties()
MP4::AudioProperties::~AudioProperties()
{
delete d;
}
int
MP4::Properties::channels() const
MP4::AudioProperties::channels() const
{
return d->channels;
}
int
MP4::Properties::sampleRate() const
MP4::AudioProperties::sampleRate() const
{
return d->sampleRate;
}
int
MP4::Properties::length() const
MP4::AudioProperties::length() const
{
return lengthInSeconds();
}
int
MP4::Properties::lengthInSeconds() const
MP4::AudioProperties::lengthInSeconds() const
{
return d->length / 1000;
}
int
MP4::Properties::lengthInMilliseconds() const
MP4::AudioProperties::lengthInMilliseconds() const
{
return d->length;
}
int
MP4::Properties::bitrate() const
MP4::AudioProperties::bitrate() const
{
return d->bitrate;
}
int
MP4::Properties::bitsPerSample() const
MP4::AudioProperties::bitsPerSample() const
{
return d->bitsPerSample;
}
bool
MP4::Properties::isEncrypted() const
MP4::AudioProperties::isEncrypted() const
{
return d->encrypted;
}
MP4::Properties::Codec
MP4::Properties::codec() const
MP4::AudioProperties::Codec
MP4::AudioProperties::codec() const
{
return d->codec;
}
String
MP4::AudioProperties::toString() const
{
String format;
if(d->codec == AAC) {
format = "AAC";
}
else if(d->codec == ALAC) {
format = "ALAC";
}
else {
format = "Unknown";
}
StringList desc;
desc.append("MPEG-4 audio (" + format + ")");
desc.append(String::number(length()) + " seconds");
desc.append(String::number(bitrate()) + " kbps");
return desc.toString(", ");
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void
MP4::Properties::read(File *file, Atoms *atoms)
MP4::AudioProperties::read(File *file, Atoms *atoms)
{
MP4::Atom *moov = atoms->find("moov");
if(!moov) {
@@ -147,7 +167,7 @@ MP4::Properties::read(File *file, Atoms *atoms)
return;
}
file->seek(hdlr->offset);
data = file->readBlock(hdlr->length);
data = file->readBlock(static_cast<size_t>(hdlr->length));
if(data.containsAt("soun", 16)) {
break;
}
@@ -165,7 +185,7 @@ MP4::Properties::read(File *file, Atoms *atoms)
}
file->seek(mdhd->offset);
data = file->readBlock(mdhd->length);
data = file->readBlock(static_cast<size_t>(mdhd->length));
const unsigned int version = data[8];
long long unit;
@@ -175,16 +195,16 @@ MP4::Properties::read(File *file, Atoms *atoms)
debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected");
return;
}
unit = data.toLongLong(28U);
length = data.toLongLong(36U);
unit = data.toUInt32BE(28);
length = data.toInt64BE(32);
}
else {
if(data.size() < 24 + 4) {
if(data.size() < 24 + 8) {
debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected");
return;
}
unit = data.toUInt(20U);
length = data.toUInt(24U);
unit = data.toUInt32BE(20);
length = data.toUInt32BE(24);
}
if(unit > 0 && length > 0)
d->length = static_cast<int>(length * 1000.0 / unit + 0.5);
@@ -195,12 +215,12 @@ MP4::Properties::read(File *file, Atoms *atoms)
}
file->seek(atom->offset);
data = file->readBlock(atom->length);
data = file->readBlock(static_cast<size_t>(atom->length));
if(data.containsAt("mp4a", 20)) {
d->codec = AAC;
d->channels = data.toShort(40U);
d->bitsPerSample = data.toShort(42U);
d->sampleRate = data.toUInt(46U);
d->channels = data.toUInt16BE(40);
d->bitsPerSample = data.toUInt16BE(42);
d->sampleRate = data.toUInt32BE(46);
if(data.containsAt("esds", 56) && data[64] == 0x03) {
unsigned int pos = 65;
if(data.containsAt("\x80\x80\x80", pos)) {
@@ -213,7 +233,7 @@ MP4::Properties::read(File *file, Atoms *atoms)
pos += 3;
}
pos += 10;
d->bitrate = static_cast<int>((data.toUInt(pos) + 500) / 1000.0 + 0.5);
d->bitrate = static_cast<int>((data.toUInt32BE(pos) + 500) / 1000.0 + 0.5);
}
}
}
@@ -222,8 +242,8 @@ MP4::Properties::read(File *file, Atoms *atoms)
d->codec = ALAC;
d->bitsPerSample = data.at(69);
d->channels = data.at(73);
d->bitrate = static_cast<int>(data.toUInt(80U) / 1000.0 + 0.5);
d->sampleRate = data.toUInt(84U);
d->bitrate = static_cast<int>(data.toUInt32BE(80) / 1000.0 + 0.5);
d->sampleRate = data.toUInt32BE(84);
}
}

View File

@@ -37,7 +37,7 @@ namespace TagLib {
class File;
//! An implementation of MP4 audio properties
class TAGLIB_EXPORT Properties : public AudioProperties
class TAGLIB_EXPORT AudioProperties : public TagLib::AudioProperties
{
public:
enum Codec {
@@ -46,8 +46,8 @@ namespace TagLib {
ALAC
};
Properties(File *file, Atoms *atoms, ReadStyle style = Average);
virtual ~Properties();
AudioProperties(File *file, Atoms *atoms, ReadStyle style = Average);
virtual ~AudioProperties();
/*!
* Returns the length of the file in seconds. The length is rounded down to
@@ -65,16 +65,14 @@ namespace TagLib {
*
* \see lengthInMilliseconds()
*/
// BIC: make virtual
int lengthInSeconds() const;
virtual int lengthInSeconds() const;
/*!
* Returns the length of the file in milliseconds.
*
* \see lengthInSeconds()
*/
// BIC: make virtual
int lengthInMilliseconds() const;
virtual int lengthInMilliseconds() const;
/*!
* Returns the average bit rate of the file in kb/s.
@@ -106,6 +104,8 @@ namespace TagLib {
*/
Codec codec() const;
String toString() const;
private:
void read(File *file, Atoms *atoms);

View File

@@ -22,9 +22,10 @@
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <cstring>
#include <tdebug.h>
#include <tstring.h>
#include <tpicturemap.h>
#include <tpropertymap.h>
#include "mp4atom.h"
#include "mp4tag.h"
@@ -71,14 +72,15 @@ MP4::Tag::Tag(TagLib::File *file, MP4::Atoms *atoms) :
parseIntPair(atom);
}
else if(atom->name == "cpil" || atom->name == "pgap" || atom->name == "pcst" ||
atom->name == "hdvd") {
atom->name == "hdvd" || atom->name == "shwm") {
parseBool(atom);
}
else if(atom->name == "tmpo") {
else if(atom->name == "tmpo" || atom->name == "rate" || atom->name == "\251mvi" || atom->name == "\251mvc") {
parseInt(atom);
}
else if(atom->name == "tvsn" || atom->name == "tves" || atom->name == "cnID" ||
atom->name == "sfID" || atom->name == "atID" || atom->name == "geID") {
atom->name == "sfID" || atom->name == "atID" || atom->name == "geID" ||
atom->name == "cmID") {
parseUInt(atom);
}
else if(atom->name == "plID") {
@@ -93,6 +95,9 @@ MP4::Tag::Tag(TagLib::File *file, MP4::Atoms *atoms) :
else if(atom->name == "covr") {
parseCovr(atom);
}
else if(atom->name == "purl" || atom->name == "egid") {
parseText(atom, -1);
}
else {
parseText(atom);
}
@@ -108,18 +113,18 @@ MP4::AtomDataList
MP4::Tag::parseData2(const MP4::Atom *atom, int expectedFlags, bool freeForm)
{
AtomDataList result;
ByteVector data = d->file->readBlock(atom->length - 8);
ByteVector data = d->file->readBlock(static_cast<size_t>(atom->length - 8));
int i = 0;
unsigned int pos = 0;
size_t pos = 0;
while(pos < data.size()) {
const int length = static_cast<int>(data.toUInt(pos));
const int length = static_cast<int>(data.toUInt32BE(pos));
if(length < 12) {
debug("MP4: Too short atom");
return result;
}
const ByteVector name = data.mid(pos + 4, 4);
const int flags = static_cast<int>(data.toUInt(pos + 8));
const int flags = static_cast<int>(data.toUInt32BE(pos + 8));
if(freeForm && i < 2) {
if(i == 0 && name != "mean") {
debug("MP4: Unexpected atom \"" + name + "\", expecting \"mean\"");
@@ -162,7 +167,7 @@ MP4::Tag::parseInt(const MP4::Atom *atom)
{
ByteVectorList data = parseData(atom);
if(!data.isEmpty()) {
addItem(atom->name, (int)data[0].toShort());
addItem(atom->name, (int)data[0].toInt16BE(0));
}
}
@@ -171,7 +176,7 @@ MP4::Tag::parseUInt(const MP4::Atom *atom)
{
ByteVectorList data = parseData(atom);
if(!data.isEmpty()) {
addItem(atom->name, data[0].toUInt());
addItem(atom->name, data[0].toUInt32BE(0));
}
}
@@ -180,7 +185,7 @@ MP4::Tag::parseLongLong(const MP4::Atom *atom)
{
ByteVectorList data = parseData(atom);
if(!data.isEmpty()) {
addItem(atom->name, data[0].toLongLong());
addItem(atom->name, data[0].toInt64BE(0));
}
}
@@ -198,7 +203,7 @@ MP4::Tag::parseGnre(const MP4::Atom *atom)
{
ByteVectorList data = parseData(atom);
if(!data.isEmpty()) {
int idx = (int)data[0].toShort();
int idx = (int)data[0].toInt16BE(0);
if(idx > 0) {
addItem("\251gen", StringList(ID3v1::genre(idx - 1)));
}
@@ -210,8 +215,8 @@ MP4::Tag::parseIntPair(const MP4::Atom *atom)
{
ByteVectorList data = parseData(atom);
if(!data.isEmpty()) {
const int a = data[0].toShort(2U);
const int b = data[0].toShort(4U);
const int a = data[0].toInt16BE(2);
const int b = data[0].toInt16BE(4);
addItem(atom->name, MP4::Item(a, b));
}
}
@@ -284,17 +289,17 @@ void
MP4::Tag::parseCovr(const MP4::Atom *atom)
{
MP4::CoverArtList value;
ByteVector data = d->file->readBlock(atom->length - 8);
ByteVector data = d->file->readBlock(static_cast<size_t>(atom->length - 8));
unsigned int pos = 0;
while(pos < data.size()) {
const int length = static_cast<int>(data.toUInt(pos));
const int length = static_cast<int>(data.toUInt32BE(pos));
if(length < 12) {
debug("MP4: Too short atom");
break;;
}
const ByteVector name = data.mid(pos + 4, 4);
const int flags = static_cast<int>(data.toUInt(pos + 8));
const int flags = static_cast<int>(data.toUInt32BE(pos + 8));
if(name != "data") {
debug("MP4: Unexpected atom \"" + name + "\", expecting \"data\"");
break;
@@ -317,7 +322,7 @@ ByteVector
MP4::Tag::padIlst(const ByteVector &data, int length) const
{
if(length == -1) {
length = ((data.size() + 1023) & ~1023) - data.size();
length = static_cast<int>(((data.size() + 1023) & ~1023) - data.size());
}
return renderAtom("free", ByteVector(length, '\1'));
}
@@ -325,7 +330,7 @@ MP4::Tag::padIlst(const ByteVector &data, int length) const
ByteVector
MP4::Tag::renderAtom(const ByteVector &name, const ByteVector &data) const
{
return ByteVector::fromUInt(data.size() + 8) + name + data;
return ByteVector::fromUInt32BE(data.size() + 8) + name + data;
}
ByteVector
@@ -333,7 +338,7 @@ MP4::Tag::renderData(const ByteVector &name, int flags, const ByteVectorList &da
{
ByteVector result;
for(ByteVectorList::ConstIterator it = data.begin(); it != data.end(); ++it) {
result.append(renderAtom("data", ByteVector::fromUInt(flags) + ByteVector(4, '\0') + *it));
result.append(renderAtom("data", ByteVector::fromUInt32BE(flags) + ByteVector(4, '\0') + *it));
}
return renderAtom(name, result);
}
@@ -350,7 +355,7 @@ ByteVector
MP4::Tag::renderInt(const ByteVector &name, const MP4::Item &item) const
{
ByteVectorList data;
data.append(ByteVector::fromShort(item.toInt()));
data.append(ByteVector::fromUInt16BE(item.toInt()));
return renderData(name, TypeInteger, data);
}
@@ -358,7 +363,7 @@ ByteVector
MP4::Tag::renderUInt(const ByteVector &name, const MP4::Item &item) const
{
ByteVectorList data;
data.append(ByteVector::fromUInt(item.toUInt()));
data.append(ByteVector::fromUInt32BE(item.toUInt()));
return renderData(name, TypeInteger, data);
}
@@ -366,7 +371,7 @@ ByteVector
MP4::Tag::renderLongLong(const ByteVector &name, const MP4::Item &item) const
{
ByteVectorList data;
data.append(ByteVector::fromLongLong(item.toLongLong()));
data.append(ByteVector::fromUInt64BE(item.toLongLong()));
return renderData(name, TypeInteger, data);
}
@@ -383,8 +388,8 @@ MP4::Tag::renderIntPair(const ByteVector &name, const MP4::Item &item) const
{
ByteVectorList data;
data.append(ByteVector(2, '\0') +
ByteVector::fromShort(item.toIntPair().first) +
ByteVector::fromShort(item.toIntPair().second) +
ByteVector::fromUInt16BE(item.toIntPair().first) +
ByteVector::fromUInt16BE(item.toIntPair().second) +
ByteVector(2, '\0'));
return renderData(name, TypeImplicit, data);
}
@@ -394,8 +399,8 @@ MP4::Tag::renderIntPairNoTrailing(const ByteVector &name, const MP4::Item &item)
{
ByteVectorList data;
data.append(ByteVector(2, '\0') +
ByteVector::fromShort(item.toIntPair().first) +
ByteVector::fromShort(item.toIntPair().second));
ByteVector::fromUInt16BE(item.toIntPair().first) +
ByteVector::fromUInt16BE(item.toIntPair().second));
return renderData(name, TypeImplicit, data);
}
@@ -416,7 +421,7 @@ MP4::Tag::renderCovr(const ByteVector &name, const MP4::Item &item) const
ByteVector data;
MP4::CoverArtList value = item.toCoverArtList();
for(MP4::CoverArtList::ConstIterator it = value.begin(); it != value.end(); ++it) {
data.append(renderAtom("data", ByteVector::fromUInt(it->format()) +
data.append(renderAtom("data", ByteVector::fromUInt32BE(it->format()) +
ByteVector(4, '\0') + it->data()));
}
return renderAtom(name, data);
@@ -431,8 +436,8 @@ MP4::Tag::renderFreeForm(const String &name, const MP4::Item &item) const
return ByteVector();
}
ByteVector data;
data.append(renderAtom("mean", ByteVector::fromUInt(0) + header[1].data(String::UTF8)));
data.append(renderAtom("name", ByteVector::fromUInt(0) + header[2].data(String::UTF8)));
data.append(renderAtom("mean", ByteVector::fromUInt32BE(0) + header[1].data(String::UTF8)));
data.append(renderAtom("name", ByteVector::fromUInt32BE(0) + header[2].data(String::UTF8)));
AtomDataType type = item.atomDataType();
if(type == TypeUndefined) {
if(!item.toStringList().isEmpty()) {
@@ -445,13 +450,13 @@ MP4::Tag::renderFreeForm(const String &name, const MP4::Item &item) const
if(type == TypeUTF8) {
StringList value = item.toStringList();
for(StringList::ConstIterator it = value.begin(); it != value.end(); ++it) {
data.append(renderAtom("data", ByteVector::fromUInt(type) + ByteVector(4, '\0') + it->data(String::UTF8)));
data.append(renderAtom("data", ByteVector::fromUInt32BE(type) + ByteVector(4, '\0') + it->data(String::UTF8)));
}
}
else {
ByteVectorList value = item.toByteVectorList();
for(ByteVectorList::ConstIterator it = value.begin(); it != value.end(); ++it) {
data.append(renderAtom("data", ByteVector::fromUInt(type) + ByteVector(4, '\0') + *it));
data.append(renderAtom("data", ByteVector::fromUInt32BE(type) + ByteVector(4, '\0') + *it));
}
}
return renderAtom("----", data);
@@ -472,14 +477,16 @@ MP4::Tag::save()
else if(name == "disk") {
data.append(renderIntPairNoTrailing(name.data(String::Latin1), it->second));
}
else if(name == "cpil" || name == "pgap" || name == "pcst" || name == "hdvd") {
else if(name == "cpil" || name == "pgap" || name == "pcst" || name == "hdvd" ||
name == "shwm") {
data.append(renderBool(name.data(String::Latin1), it->second));
}
else if(name == "tmpo") {
else if(name == "tmpo" || name == "rate" || name == "\251mvi" || name == "\251mvc") {
data.append(renderInt(name.data(String::Latin1), it->second));
}
else if(name == "tvsn" || name == "tves" || name == "cnID" ||
name == "sfID" || name == "atID" || name == "geID") {
name == "sfID" || name == "atID" || name == "geID" ||
name == "cmID") {
data.append(renderUInt(name.data(String::Latin1), it->second));
}
else if(name == "plID") {
@@ -491,6 +498,9 @@ MP4::Tag::save()
else if(name == "covr") {
data.append(renderCovr(name.data(String::Latin1), it->second));
}
else if(name == "purl" || name == "egid") {
data.append(renderText(name.data(String::Latin1), it->second, TypeImplicit));
}
else if(name.size() == 4){
data.append(renderText(name.data(String::Latin1), it->second));
}
@@ -522,25 +532,25 @@ MP4::Tag::updateParents(const AtomList &path, long delta, int ignore)
for(AtomList::ConstIterator it = path.begin(); it != itEnd; ++it) {
d->file->seek((*it)->offset);
long size = d->file->readBlock(4).toUInt();
long size = d->file->readBlock(4).toUInt32BE(0);
// 64-bit
if (size == 1) {
d->file->seek(4, File::Current); // Skip name
long long longSize = d->file->readBlock(8).toLongLong();
long long longSize = d->file->readBlock(8).toInt64BE(0);
// Seek the offset of the 64-bit size
d->file->seek((*it)->offset + 8);
d->file->writeBlock(ByteVector::fromLongLong(longSize + delta));
d->file->writeBlock(ByteVector::fromUInt64BE(longSize + delta));
}
// 32-bit
else {
d->file->seek((*it)->offset);
d->file->writeBlock(ByteVector::fromUInt(size + delta));
d->file->writeBlock(ByteVector::fromUInt32BE(size + delta));
}
}
}
void
MP4::Tag::updateOffsets(long delta, long offset)
MP4::Tag::updateOffsets(long delta, long long offset)
{
MP4::Atom *moov = d->atoms->find("moov");
if(moov) {
@@ -551,16 +561,16 @@ MP4::Tag::updateOffsets(long delta, long offset)
atom->offset += delta;
}
d->file->seek(atom->offset + 12);
ByteVector data = d->file->readBlock(atom->length - 12);
unsigned int count = data.toUInt();
ByteVector data = d->file->readBlock(static_cast<size_t>(atom->length - 12));
unsigned int count = data.toUInt32BE(0);
d->file->seek(atom->offset + 16);
unsigned int pos = 4;
size_t pos = 4;
while(count--) {
long o = static_cast<long>(data.toUInt(pos));
long o = data.toUInt32BE(pos);
if(o > offset) {
o += delta;
}
d->file->writeBlock(ByteVector::fromUInt(o));
d->file->writeBlock(ByteVector::fromUInt32BE(o));
pos += 4;
}
}
@@ -572,16 +582,16 @@ MP4::Tag::updateOffsets(long delta, long offset)
atom->offset += delta;
}
d->file->seek(atom->offset + 12);
ByteVector data = d->file->readBlock(atom->length - 12);
unsigned int count = data.toUInt();
ByteVector data = d->file->readBlock(static_cast<size_t>(atom->length - 12));
unsigned int count = data.toUInt32BE(0);
d->file->seek(atom->offset + 16);
unsigned int pos = 4;
size_t pos = 4;
while(count--) {
long long o = data.toLongLong(pos);
long long o = data.toInt64BE(pos);
if(o > offset) {
o += delta;
}
d->file->writeBlock(ByteVector::fromLongLong(o));
d->file->writeBlock(ByteVector::fromUInt64BE(o));
pos += 8;
}
}
@@ -596,15 +606,15 @@ MP4::Tag::updateOffsets(long delta, long offset)
atom->offset += delta;
}
d->file->seek(atom->offset + 9);
ByteVector data = d->file->readBlock(atom->length - 9);
const unsigned int flags = data.toUInt(0, 3, true);
ByteVector data = d->file->readBlock(static_cast<size_t>(atom->length - 9));
const unsigned int flags = data.toUInt24BE(0);
if(flags & 1) {
long long o = data.toLongLong(7U);
long long o = data.toInt64BE(7);
if(o > offset) {
o += delta;
}
d->file->seek(atom->offset + 16);
d->file->writeBlock(ByteVector::fromLongLong(o));
d->file->writeBlock(ByteVector::fromUInt64BE(o));
}
}
}
@@ -624,11 +634,11 @@ MP4::Tag::saveNew(ByteVector data)
data = renderAtom("udta", data);
}
long offset = path.back()->offset + 8;
long long offset = path.back()->offset + 8;
d->file->insert(data, offset, 0);
updateParents(path, data.size());
updateOffsets(data.size(), offset);
updateParents(path, static_cast<long>(data.size()));
updateOffsets(static_cast<long>(data.size()), offset);
// Insert the newly created atoms into the tree to keep it up-to-date.
@@ -642,8 +652,8 @@ MP4::Tag::saveExisting(ByteVector data, const AtomList &path)
AtomList::ConstIterator it = path.end();
MP4::Atom *ilst = *(--it);
long offset = ilst->offset;
long length = ilst->length;
long long offset = ilst->offset;
long long length = ilst->length;
MP4::Atom *meta = *(--it);
AtomList::ConstIterator index = meta->children.find(ilst);
@@ -668,17 +678,17 @@ MP4::Tag::saveExisting(ByteVector data, const AtomList &path)
}
}
long delta = data.size() - length;
long delta = static_cast<long>(data.size() - length);
if(delta > 0 || (delta < 0 && delta > -8)) {
data.append(padIlst(data));
delta = data.size() - length;
delta = static_cast<long>(data.size() - length);
}
else if(delta < 0) {
data.append(padIlst(data, -delta - 8));
data.append(padIlst(data, 0 - delta - 8));
delta = 0;
}
d->file->insert(data, offset, length);
d->file->insert(data, offset, static_cast<size_t>(length));
if(delta) {
updateParents(path, delta, 1);
@@ -742,6 +752,42 @@ MP4::Tag::track() const
return 0;
}
PictureMap
MP4::Tag::pictures() const
{
if(!d->items.contains("covr"))
return PictureMap();
CoverArtList list = d->items["covr"].toCoverArtList();
if(list.isEmpty())
return PictureMap();
PictureMap map;
for(CoverArtList::ConstIterator it = list.begin(); it != list.end(); ++it) {
CoverArt art = *it;
String mime = "image/";
switch(art.format()) {
case CoverArt::BMP:
mime.append("bmp");
break;
case CoverArt::JPEG:
mime.append("jpeg");
break;
case CoverArt::GIF:
mime.append("gif");
break;
case CoverArt::PNG:
mime.append("png");
break;
case CoverArt::Unknown:
break;
}
Picture picture(art.data(), Picture::Other, mime);
map.insert(picture);
}
return PictureMap(map);
}
void
MP4::Tag::setTitle(const String &value)
{
@@ -784,6 +830,39 @@ MP4::Tag::setTrack(unsigned int value)
d->items["trkn"] = MP4::Item(value, 0);
}
void
MP4::Tag::setPictures(const PictureMap &l)
{
CoverArtList list;
for(PictureMap::ConstIterator pictureMapIt = l.begin();
pictureMapIt != l.end();
++pictureMapIt) {
PictureList pictures = pictureMapIt->second;
for(PictureList::ConstIterator pictureListIt = pictures.begin();
pictureListIt != pictures.end();
++pictureListIt) {
Picture picture = *pictureListIt;
CoverArt::Format format;
String mime = picture.mime();
if(String("image/") == mime)
format = CoverArt::Unknown;
else if(String("image/bmp") == mime)
format = CoverArt::BMP;
else if(String("image/png") == mime)
format = CoverArt::PNG;
else if(String("image/gif") == mime)
format = CoverArt::GIF;
else if(String("image/jpeg") == mime)
format = CoverArt::JPEG;
else
format = CoverArt::Unknown;
CoverArt art(format, picture.data());
list.append(art);
}
}
d->items["covr"] = list;
}
bool MP4::Tag::isEmpty() const
{
return d->items.isEmpty();
@@ -819,6 +898,16 @@ bool MP4::Tag::contains(const String &key) const
return d->items.contains(key);
}
String
MP4::Tag::toString() const
{
StringList desc;
for(MP4::ItemListMap::Iterator i = d->items.begin(); i != d->items.end(); i++) {
desc.append(i->first + "=" + i->second.toString());
}
return desc.toString("\n");
}
namespace
{
const char *keyTranslation[][2] = {
@@ -844,6 +933,11 @@ namespace
{ "sonm", "TITLESORT" },
{ "soco", "COMPOSERSORT" },
{ "sosn", "SHOWSORT" },
{ "shwm", "SHOWWORKMOVEMENT" },
{ "\251wrk", "WORK" },
{ "\251mvn", "MOVEMENTNAME" },
{ "\251mvi", "MOVEMENTNUMBER" },
{ "\251mvc", "MOVEMENTCOUNT" },
{ "----:com.apple.iTunes:MusicBrainz Track Id", "MUSICBRAINZ_TRACKID" },
{ "----:com.apple.iTunes:MusicBrainz Artist Id", "MUSICBRAINZ_ARTISTID" },
{ "----:com.apple.iTunes:MusicBrainz Album Id", "MUSICBRAINZ_ALBUMID" },
@@ -897,10 +991,10 @@ PropertyMap MP4::Tag::properties() const
}
props[key] = value;
}
else if(key == "BPM") {
else if(key == "BPM" || key == "MOVEMENTNUMBER" || key == "MOVEMENTCOUNT") {
props[key] = String::number(it->second.toInt());
}
else if(key == "COMPILATION") {
else if(key == "COMPILATION" || key == "SHOWWORKMOVEMENT") {
props[key] = String::number(it->second.toBool());
}
else {
@@ -942,21 +1036,21 @@ PropertyMap MP4::Tag::setProperties(const PropertyMap &props)
if(reverseKeyMap.contains(it->first)) {
String name = reverseKeyMap[it->first];
if((it->first == "TRACKNUMBER" || it->first == "DISCNUMBER") && !it->second.isEmpty()) {
int first = 0, second = 0;
StringList parts = StringList::split(it->second.front(), "/");
if(!parts.isEmpty()) {
first = parts[0].toInt();
int first = parts[0].toInt();
int second = 0;
if(parts.size() > 1) {
second = parts[1].toInt();
}
d->items[name] = MP4::Item(first, second);
}
}
else if(it->first == "BPM" && !it->second.isEmpty()) {
else if((it->first == "BPM" || it->first == "MOVEMENTNUMBER" || it->first == "MOVEMENTCOUNT") && !it->second.isEmpty()) {
int value = it->second.front().toInt();
d->items[name] = MP4::Item(value);
}
else if(it->first == "COMPILATION" && !it->second.isEmpty()) {
else if((it->first == "COMPILATION" || it->first == "SHOWWORKMOVEMENT") && !it->second.isEmpty()) {
bool value = (it->second.front().toInt() != 0);
d->items[name] = MP4::Item(value);
}

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