873 Commits

Author SHA1 Message Date
Lukáš Lalinský
35aa6c4e84 Update date in NEWS 2015-08-23 20:09:22 +02:00
Lukáš Lalinský
54cea3edc3 Reorganize NEWS to put new features first 2015-08-23 12:20:25 +02:00
Lukáš Lalinský
0178d47c85 Don't use const ref to an integer in ChapterFrame 2015-08-23 12:20:25 +02:00
Lukáš Lalinský
71bc17b5e6 Lalala 2015-08-23 12:20:25 +02:00
Tsuda Kageyu
ac38f4ade1 Remove an unused private data member. 2015-08-23 18:25:17 +09:00
Tsuda Kageyu
b9f898698d Revert "Remove some private data members not needed to carry."
This reverts commit 7c17d32b3a.
2015-08-23 18:21:51 +09:00
Tsuda Kageyu
bd564546f4 Fix some typos in comments. 2015-08-14 00:10:19 +09:00
Tsuda Kageyu
d90617959b Fix some typos in comments. 2015-08-11 09:45:32 +09:00
Tsuda Kageyu
bc106ad81e Separate two variable initializations. 2015-08-10 00:50:13 +09:00
Tsuda Kageyu
a23f808627 Remove an useless #include. 2015-08-09 13:26:51 +09:00
Tsuda Kageyu
e4cd963b12 Improve a test about splitting OGG pages.
Check for #529.
2015-08-08 15:18:16 +09:00
Tsuda Kageyu
eff92fed98 Improve a test about splitting OGG pages.
Check for #529.
2015-08-07 16:47:13 +09:00
Tsuda Kageyu
80441ff754 Remove a workaround for an older version of GCC.
GLIBC's byte swap functions are a good fallback option.
2015-08-07 08:59:16 +09:00
Tsuda Kageyu
edbafdbd88 Remove some redundant code from trefcounter.cpp. 2015-08-07 02:10:56 +09:00
Tsuda Kageyu
98ac8ba569 Add a comment about unused constants. 2015-08-07 02:03:03 +09:00
Tsuda Kageyu
173c58cf49 Merge pull request #580 from TsudaKageyu/negative-seek
Fix inconsistent negative seek behavior between Linux and Windows.
2015-08-07 01:32:26 +09:00
Tsuda Kageyu
ec3d050adc Merge pull request #644 from petrows/master
Install target should be checked to avoid conflicts
2015-08-07 01:20:03 +09:00
Tsuda Kageyu
19a7e45997 Merge pull request #639 from TsudaKageyu/remove-cmake-check-float
Run-time check for byte order rather than CMake check.
2015-08-07 01:17:27 +09:00
Tsuda Kageyu
49563a9cd0 Merge pull request #640 from TsudaKageyu/cmake-vsprintf
CMake check for vsprintf_s/vsnprintf rather than sprintf_s/snprintf.
2015-08-07 01:14:12 +09:00
Tsuda Kageyu
1abe61640a Merge pull request #645 from FestusHagen/fh1.m_UintAmbiguities_WavePackProperties
Silence uint ambiguity error in wavepackproperties.
2015-08-06 16:35:45 +09:00
Festus Hagen
65a6572299 Silence uint ambiguity errors in wavepackproperties. 2015-08-06 03:22:03 -04:00
Peter Petrovich
46e74c9391 Install target check fix 2015-08-05 08:45:27 +03:00
Tsuda Kageyu
7c17d32b3a Remove some private data members not needed to carry. 2015-08-05 11:54:30 +09:00
Tsuda Kageyu
bfe4ec5df5 Update NEWS.
Added support for reading the encoder information of WMA files.
Added support for reading the codec of WAV files.
Added support for multi channel WavPack files.
Added support for reading the nominal bitrate of Ogg Speex files.
Added support for VBR headers in MPEG files.
2015-08-05 02:58:45 +09:00
Tsuda Kageyu
81b7d0046e Merge branch 'master' of https://github.com/TsudaKageyu/taglib 2015-08-04 23:34:01 +09:00
Tsuda Kageyu
5990c72a01 Fix a typo in NEWS. 2015-08-04 23:27:28 +09:00
Tsuda Kageyu
018e969026 Add warnings about calling File::save() repeatedly. 2015-08-04 15:47:18 +09:00
Tsuda Kageyu
04ec7eae25 Add some supplementary comments. 2015-08-03 22:31:16 +09:00
Tsuda Kageyu
b6e7bb2c84 Update version to 1.10.0. 2015-08-03 16:14:48 +09:00
Tsuda Kageyu
f112d538ea Merge pull request #612 from TsudaKageyu/flac-id3v1
Avoid overwriting the audio stream when adding an ID3v1 tag to a FLAC…
2015-08-03 15:54:16 +09:00
Tsuda Kageyu
ac5ef0291c Update NEWS.
Fixed possible file corruptions when adding an ID3v1 tag to FLAC files.
2015-08-03 15:51:50 +09:00
Tsuda Kageyu
8fa86162c7 Add a test to check if the FLAC audio stream remains intact after adding an ID3v1 tag. 2015-08-03 15:40:30 +09:00
Tsuda Kageyu
fa17b4da6b Avoid overwriting the audio stream when adding an ID3v1 tag to a FLAC file. 2015-08-03 15:39:27 +09:00
Tsuda Kageyu
076e845912 Run-time check for integer byte order rather than CMake check.
It will easily be optimized out.
2015-08-03 13:08:58 +09:00
Tsuda Kageyu
f830177b3b Correct the order of #includes in tests. 2015-08-03 11:41:55 +09:00
Tsuda Kageyu
0650dc77a1 Fix some comments. 2015-08-02 03:24:25 +09:00
Tsuda Kageyu
c0f537a155 Merge pull request #581 from FestusHagen/fh2.m_FixUintAmbiguitiesInTests
Silence uint ambiguity errors in tests.
2015-08-02 02:40:20 +09:00
Tsuda Kageyu
44d9f2bf25 Run-time check for floating point byte order rather than CMake check.
It's safer not to use an unofficial CMake script.
2015-08-01 23:40:23 +09:00
Tsuda Kageyu
89e6ad96a4 Check for vsnprintf first. 2015-08-01 23:38:50 +09:00
Tsuda Kageyu
aa1dd0278d CMake check for vsprintf_s/vsnprintf rather than sprintf_s/snprintf. 2015-08-01 23:38:50 +09:00
Tsuda Kageyu
13dab99af0 Remove unused includes from ConfigureChecks.cmake. 2015-08-01 23:34:36 +09:00
Tsuda Kageyu
03ec83ecca Add AudioProperties::lengthInSeconds() and lengthInMilliseconds() functions to emulate virtual abstract functions. 2015-08-01 02:23:18 +09:00
Tsuda Kageyu
ce02910c6b Update NEWS.
Marked FLAC::File::streamInfoData() deprecated. It returns an empty ByteVector.
Marked FLAC::File::streamLength() deprecated. It returns zero.
2015-08-01 02:06:35 +09:00
Tsuda Kageyu
f25e30d33f Revert "Reorder CMake checks for sprintf() variants."
This reverts commit c69364d831.
2015-08-01 01:59:36 +09:00
Tsuda Kageyu
4dcccfbd6a Update NEWS.
New API for the audio length in milliseconds.
2015-08-01 01:46:35 +09:00
Tsuda Kageyu
7ca1b0c4d3 Merge pull request #575 from TsudaKageyu/chunk-offset
Stop calculating the offset in RIFF::File::chunkData().
2015-08-01 01:31:17 +09:00
Tsuda Kageyu
11f4e4e1ca Merge pull request #567 from TsudaKageyu/audioprop-wv
(wishlist) WavPack: AudioProperties improvements
2015-08-01 01:30:19 +09:00
Tsuda Kageyu
9759bd2dd7 Merge pull request #566 from TsudaKageyu/audioprop-tta
(wishlist) TrueAudio: AudioProperties improvements
2015-08-01 01:30:12 +09:00
Tsuda Kageyu
b28784538a Merge pull request #565 from TsudaKageyu/audioprop-wav
(wishlist) WAV: AudioProperties improvements
2015-08-01 01:30:03 +09:00
Tsuda Kageyu
fdea096c8d Merge pull request #564 from TsudaKageyu/audioprop-aiff
(wishlist) AIFF: AudioProperties improvements
2015-08-01 01:29:46 +09:00
Tsuda Kageyu
a9d030544a Merge pull request #563 from TsudaKageyu/audioprop-vorbis
(wishlist) Ogg Vorbis: AudioProperties improvements
2015-08-01 01:29:35 +09:00
Tsuda Kageyu
8344c4d7f8 Merge pull request #562 from TsudaKageyu/audioprop-speex
(wishlist) Ogg Speex: AudioProperties improvements
2015-08-01 01:29:22 +09:00
Tsuda Kageyu
8b1e872f81 Merge pull request #561 from TsudaKageyu/audioprop-opus
(wishlist) Ogg Opus: AudioProperties improvements
2015-08-01 01:29:13 +09:00
Tsuda Kageyu
6a778751ee Merge pull request #560 from TsudaKageyu/audioprop-mpeg
(wishlist) MPEG: AudioProperties improvements
2015-08-01 01:29:06 +09:00
Tsuda Kageyu
4328a830f9 Merge pull request #559 from TsudaKageyu/audioprop-mpc
(wishlist) MusePak: AudioProperties improvements
2015-08-01 01:27:20 +09:00
Tsuda Kageyu
ae99cbe64e Merge pull request #558 from TsudaKageyu/audioprop-mp4
(wishlist) MP4: AudioProperties improvements
2015-08-01 01:27:15 +09:00
Tsuda Kageyu
692ce897cb Merge pull request #557 from TsudaKageyu/audioprop-flac
(wishlist) FLAC: AudioProperties improvements
2015-08-01 01:27:06 +09:00
Tsuda Kageyu
0ed1c29acc Merge pull request #556 from TsudaKageyu/audioprop-asf
(wishlist) ASF: AudioProperties improvements
2015-08-01 01:26:52 +09:00
Tsuda Kageyu
3c59b7858a Merge pull request #555 from TsudaKageyu/audioprop-ape
(wishlist) APE: AudioProperties improvements
2015-08-01 01:21:59 +09:00
Tsuda Kageyu
2c9f63d9b0 Merge pull request #568 from TsudaKageyu/audioprop-mod
(wishlist) MOD: AudioProperties improvements
2015-08-01 01:04:34 +09:00
Tsuda Kageyu
0b43b7136d FLAC: Remove unused formal parameters. 2015-08-01 00:49:25 +09:00
Tsuda Kageyu
1e752a1e8f FLAC: Add debug messages to tell some functions are obsolete. 2015-08-01 00:49:23 +09:00
Tsuda Kageyu
29a31859ff FLAC: Move some public functions to above private ones. 2015-08-01 00:49:22 +09:00
Tsuda Kageyu
0b01461d50 FLAC: Avoid using deprecated functions. 2015-08-01 00:49:22 +09:00
Tsuda Kageyu
a77abedf63 Remove some more data members not needed to carry. 2015-08-01 00:49:22 +09:00
Tsuda Kageyu
21412e2ba2 FLAC: AudioProperties improvements
Add lengthInSeconds(), lengthInMilliseconds() properties. (#503)
Add bitsPerSample() property besides sampleWidth(). (#360)
Remove some data members which are not needed to carry.
Add some tests for audio properties.
Add some supplementary comments.
2015-08-01 00:49:21 +09:00
Tsuda Kageyu
dbf9644c8d WavPack: Remove unused formal parameters. 2015-08-01 00:44:41 +09:00
Tsuda Kageyu
592e14f950 TrueAudio: Remove unused formal parameters. 2015-08-01 00:41:42 +09:00
Tsuda Kageyu
1fb3727c4c WAV: Remove unused formal parameters. 2015-08-01 00:37:31 +09:00
Tsuda Kageyu
0501fbdd72 AIFF: Remove unused formal parameters. 2015-08-01 00:33:56 +09:00
Tsuda Kageyu
5235abc498 Vorbis: Remove unused formal parameters. 2015-08-01 00:30:13 +09:00
Tsuda Kageyu
d944009904 Speex: Remove unused formal parameters. 2015-08-01 00:22:09 +09:00
Tsuda Kageyu
f729f863cd Opus: Remove unused formal parameters. 2015-08-01 00:19:20 +09:00
Tsuda Kageyu
c715ec09e4 MPEG: Hide an internal function from the public header. 2015-08-01 00:15:51 +09:00
Tsuda Kageyu
4f621140ce MPEG: Remove unused formal parameters. 2015-08-01 00:09:59 +09:00
Tsuda Kageyu
bd251aed37 MusePak: Remove unused formal parameters. 2015-08-01 00:04:27 +09:00
Tsuda Kageyu
34ab65aa57 MP4: Hide an internal function from the public header. 2015-07-31 23:59:22 +09:00
Tsuda Kageyu
7f0c547ba6 MP4: Remove unused formal parameters. 2015-07-31 23:55:30 +09:00
Tsuda Kageyu
0ff38ed52b ASF: Remove unused formal parameters. 2015-07-31 23:39:58 +09:00
Tsuda Kageyu
2b1116cec1 APE: Remove unused formal parameters. 2015-07-31 23:18:50 +09:00
Tsuda Kageyu
88947e7a48 Silence some MSVC specific warnings in tests. 2015-07-31 20:55:23 +09:00
Tsuda Kageyu
5ad69a81dc Silence some MSVC2015 specific warnings. 2015-07-31 12:23:01 +09:00
Tsuda Kageyu
c9963af848 MP4 atom length is limited up to 31 bits.
32-bit value will be negative.
2015-07-31 11:24:36 +09:00
Tsuda Kageyu
f38e32163e Add some comments to tutils.h. 2015-07-31 10:27:16 +09:00
Tsuda Kageyu
c69364d831 Reorder CMake checks for sprintf() variants.
VS2015 has snprintf(), however sprintf_s() is still recommended.
2015-07-31 10:11:01 +09:00
Tsuda Kageyu
3142330bee Remove sudo from .travis.yml.
This allows our tests to run faster on the container-based infrastructure.
2015-07-31 09:06:24 +09:00
Tsuda Kageyu
9b849c5da8 Merge pull request #554 from FestusHagen/fh1.m_FriendlyCppUnitSearch
Don't look for CppUnit unless BUILD_TESTS, general cleanup.
2015-07-30 23:55:16 +09:00
Tsuda Kageyu
a197f45ca8 Merge pull request #595 from TsudaKageyu/gcc-warning-test
Silence a GCC warning about ignoring a return value in test.
2015-07-30 23:39:04 +09:00
Tsuda Kageyu
6dcecf0e71 Fix a typo in a debug message. 2015-07-30 23:36:44 +09:00
Tsuda Kageyu
47800d1000 Merge pull request #625 from TsudaKageyu/checksum-comment
(minor, comment only) Add a supplementary comment to ByteVector::checksum().
2015-07-30 23:30:43 +09:00
Tsuda Kageyu
cc8c3cd1fd Merge pull request #617 from TsudaKageyu/useless-call
Remove an useless function call.
2015-07-30 23:30:18 +09:00
Tsuda Kageyu
58994e330e Update NEWS.
Fixed reading FLAC files with zero-sized padding blocks.
2015-07-30 22:03:02 +09:00
Tsuda Kageyu
572afd437d Merge pull request #638 from TsudaKageyu/update-news
Update NEWS.
2015-07-30 22:00:00 +09:00
Tsuda Kageyu
1eef4177e7 Merge pull request #637 from TsudaKageyu/flac-zero-sized-padding
Make FLAC::File tolerant to zero-sized padding blocks.
2015-07-30 21:58:42 +09:00
Tsuda Kageyu
64fac517ed Update NEWS. 2015-07-30 10:03:47 +09:00
Tsuda Kageyu
f79c766ba4 Avoid creating zero-sized padding blocks. 2015-07-29 23:05:17 +09:00
Tsuda Kageyu
6f944b0291 Make FLAC::File tolerant to zero-sized padding blocks. 2015-07-29 20:52:56 +09:00
Tsuda Kageyu
801c9db810 WAV: Avoid using a magic number. 2015-06-30 15:59:01 +09:00
Tsuda Kageyu
409b135dd5 MPEG: Fix warnings about signed/unsigned mismatch on some compilers. 2015-06-30 11:58:07 +09:00
Tsuda Kageyu
4dd14d4d73 Add a supplementary comment to ByteVector::checksum(). 2015-06-27 01:29:16 +09:00
Tsuda Kageyu
44e6419644 ASF: Hide some internal functions from the public header. 2015-06-23 18:22:31 +09:00
Tsuda Kageyu
467658e463 ASF: Make use of List iterators and setAutoDelete(). 2015-06-23 17:43:50 +09:00
Tsuda Kageyu
3fcb21642c ASF: Hide internal class declarations from the public header. 2015-06-23 17:34:33 +09:00
Tsuda Kageyu
472ce9f42c ASF: Use CodecType enum instead of a magic number. 2015-06-23 11:48:25 +09:00
Tsuda Kageyu
be33340383 Remove an useless function call. 2015-06-22 09:54:17 +09:00
Tsuda Kageyu
91ed3548f1 ASF: Enable ASF::Properties to get the audio codec information. 2015-06-21 02:42:47 +09:00
Tsuda Kageyu
b56f4c4372 APE: Reduce useless File::Find() operations. 2015-06-20 20:41:02 +09:00
Tsuda Kageyu
2155b4fd50 TrueAudio: A bit more accurate calculation of the stream length. 2015-06-20 17:36:00 +09:00
Tsuda Kageyu
e605e96835 MusePak: Avoid seeking a file when not needed. 2015-06-20 17:30:25 +09:00
Tsuda Kageyu
dfee7020da APE: Find an ID3v2 tag and calculate the stream length in APE::File. 2015-06-20 04:34:34 +09:00
Scott Wheeler
e90b5e5f2f Merge pull request #614 from TsudaKageyu/win32-pkg-config
Enable pkg-config on Windows.
2015-06-19 09:12:32 +02:00
Tsuda Kageyu
642baca4ed Fix inconsistent negative seek behavior between Linux and Windows. 2015-06-19 02:42:18 +09:00
Tsuda Kageyu
da01fa5745 Enable pkg-config on Windows. 2015-06-19 01:26:12 +09:00
Tsuda Kageyu
78c70cf5bb MOD: AudioProperties improvements
Add lengthInSeconds(), lengthInMilliseconds() properties. (always return 0)
2015-06-18 18:03:53 +09:00
Tsuda Kageyu
8f6af3f020 WavPack: A bit more accurate calculation of the stream length. 2015-06-18 18:00:03 +09:00
Tsuda Kageyu
22f250eaa4 WavPack: AudioProperties improvements
Add lengthInSeconds(), lengthInMilliseconds() properties. (#503)
Add isLossless() property.
Support multi channel. (#92)
Remove some data members which are not needed to carry.
Add some tests for audio properties.
Add some supplementary comments.
2015-06-18 17:59:06 +09:00
Tsuda Kageyu
eb73612a2b TrueAudio: AudioProperties improvements
Add lengthInSeconds(), lengthInMilliseconds() properties. (#503)
Avoid possible arithmetic overflows. (#520)
Remove some data members which are not needed to carry.
Add some tests for audio properties.
Add some supplementary comments.
2015-06-18 17:52:36 +09:00
Tsuda Kageyu
9c8e36d3be WAV: Move property parsing code to Properties.
Make use of 'fact' chunk to get the number of total samples.
2015-06-18 17:47:39 +09:00
Tsuda Kageyu
ed25204d75 WAV: AudioProperties improvements
Add lengthInSeconds(), lengthInMilliseconds() properties. (#503)
Add bitsPerSample() property besides sampleWidth(). (#360)
Add format() property. (#360)
Add some tests for audio properties.
Add some supplementary comments.
2015-06-18 17:43:09 +09:00
Tsuda Kageyu
03fd0a3ead AIFF: Calculate the actual average bitrate even if a file is compressed.
Move property parsing code to Properties.
2015-06-18 17:38:41 +09:00
Tsuda Kageyu
aede4ac851 AIFF: AudioProperties improvements
Add lengthInSeconds(), lengthInMilliseconds() properties. (#503)
Add bitsPerSample() property besides sampleWidth(). (#360)
Add some tests for audio properties.
Add some supplementary comments.
2015-06-18 17:30:58 +09:00
Tsuda Kageyu
3823afcc87 Ogg Vorbis: AudioProperties improvements
Add lengthInSeconds(), lengthInMilliseconds() properties. (#503)
Remove some data members which are not needed to carry.
Add some tests for audio properties.
Add some supplementary comments.
2015-06-18 17:24:31 +09:00
Tsuda Kageyu
4dba88fa31 Ogg Speex: AudioProperties improvements
Add lengthInSeconds(), lengthInMilliseconds() properties. (#503)
Add bitrateNominal() property.
Remove some data members which are not needed to carry.
Add some tests for audio properties.
Add some supplementary comments.
2015-06-18 17:23:03 +09:00
Tsuda Kageyu
f3d8100c7b Ogg Opus: AudioProperties improvements
Add lengthInSeconds(), lengthInMilliseconds() properties. (#503)
Remove some data members which are not needed to carry.
Add some tests for audio properties.
Add some supplementary comments.
2015-06-18 17:19:23 +09:00
Tsuda Kageyu
b2c79bc084 MPEG: No need to get the length of an ID3v2 tag twice. 2015-06-18 17:14:12 +09:00
Tsuda Kageyu
f82be353b4 MPEG: Properties::xingHeader() should return null if a VBR header is not found. 2015-06-18 17:14:12 +09:00
Tsuda Kageyu
9ec6d28239 MPEG: AudioProperties improvements
Add lengthInSeconds(), lengthInMilliseconds() properties. (#503)
Support VBRI header in addition to Xing. (#136)
Fix MPEG frame seeker functions. (maybe #190)
Calculate MPEG frame length accurately.
Remove some data members which are not needed to carry.
Add some tests for audio properties.
Add some supplementary comments.
2015-06-18 17:14:04 +09:00
Tsuda Kageyu
3a1c784eec MusePak: A bit more accurate calculation of the stream length. 2015-06-18 17:05:58 +09:00
Tsuda Kageyu
4a014c8113 MusePak: AudioProperties improvements
Add lengthInSeconds(), lengthInMilliseconds() properties. (#503)
Remove some data members which are not needed to carry.
Add some tests for audio properties.
Add some supplementary comments.
2015-06-18 17:05:58 +09:00
Tsuda Kageyu
5d77553759 MP4: Remove useless ByteVector::mid() operations. 2015-06-18 17:00:10 +09:00
Tsuda Kageyu
da14f67e2c MP4: Do rounding when calculating the bit rate. 2015-06-18 17:00:10 +09:00
Tsuda Kageyu
9226fa76b3 MP4: AudioProperties improvements
Add lengthInSeconds(), lengthInMilliseconds() properties. (#503)
Add some tests for audio properties.
Add some supplementary comments.
Move parsing code to read() for consistency with other classes.
2015-06-18 17:00:10 +09:00
Tsuda Kageyu
ff36648e92 ASF: AudioProperties improvements
Add lengthInSeconds(), lengthInMilliseconds() properties. (#503)
Add bitsPerSample() property. (#360)
Add some tests for audio properties.
Add some supplementary comments.
2015-06-18 16:33:56 +09:00
Scott Wheeler
447a4739c5 Merge pull request #611 from TsudaKageyu/fix-bufsize
Fix mismatched file I/O buffer sizes.
2015-06-18 08:22:59 +02:00
Tsuda Kageyu
f15fe869a5 Add a test for APE files with an ID3v2 tag. 2015-06-18 14:41:37 +09:00
Tsuda Kageyu
125d887b85 APE: Use the audio stream length in calculating the bit rate. 2015-06-18 14:41:37 +09:00
Tsuda Kageyu
9a8e41b9d6 APE: AudioProperties improvements
Add lengthInSeconds(), lengthInMilliseconds() properties. (#503)
Enable to read bit depth from older version files. (#360)
Remove some data members which are not needed to carry.
Add some tests for audio properties.
Add some supplementary comments.
2015-06-18 14:41:37 +09:00
Tsuda Kageyu
68ef160dbc Fix mismatched file I/O buffer sizes. 2015-06-18 11:23:31 +09:00
Scott Wheeler
6d71bdf8b7 Merge pull request #607 from TsudaKageyu/unused-function
Remove some unused private function prototypes.
2015-06-15 21:15:08 +02:00
Tsuda Kageyu
b37eaace15 Removed an unused data member from MPE::File.
It seems to be related to scan().
2015-06-12 14:07:52 +09:00
Tsuda Kageyu
c1c70edb76 Remove some unused private function prototypes. 2015-06-12 11:50:38 +09:00
Tsuda Kageyu
75159d5d8a Silence a GCC warning about ignoring a return value in test. 2015-06-10 03:44:30 +09:00
Stephen F. Booth
46862bf537 Merge pull request #594 from TsudaKageyu/typos-in-comment
Fix some typos in comments.
2015-06-08 22:19:27 -04:00
Tsuda Kageyu
2b260fd2e8 Fix some typos in comments. 2015-06-09 10:33:32 +09:00
Scott Wheeler
b1a35a8b31 Add const to docs 2015-06-03 01:21:12 +02:00
Stephen F. Booth
88ef556d4e Merge pull request #591 from TsudaKageyu/wmemcpy
Use wmemcpy() rather than memcpy() and sizeof(wchar_t).
2015-06-02 08:19:33 -04:00
Tsuda Kageyu
0c0f123a08 Use wmemcpy() rather than memcpy() and sizeof(wchar_t). 2015-06-01 13:52:55 +09:00
Festus Hagen
48311cca14 Undo comment stacking. 2015-05-31 22:12:18 -04:00
Michael Helmling
db90f4b358 Prefix #ifndef with TAGLIB_ in tpropertymap.h 2015-05-29 19:53:42 +02:00
Festus Hagen
b5d65edab7 Silence uint ambiguity errors in tests. 2015-05-27 14:07:53 -04:00
Scott Wheeler
a06d55ae6f Merge pull request #577 from TsudaKageyu/frameoffset
Fix MPEG::File::firstFrameOffset() and lastFrameOffset(). (#190)
2015-05-26 17:53:24 +02:00
Stephen F. Booth
c5f2e9342d Merge pull request #578 from TsudaKageyu/test-temp
A lot of zero-sized temporary files are left after a test session on …
2015-05-25 08:41:37 -04:00
Tsuda Kageyu
2d778d5a0a A lot of zero-sized temporary files are left after a test session on Windows. 2015-05-25 15:51:19 +09:00
Stephen F. Booth
0aa75b2e8d Merge pull request #574 from TsudaKageyu/skip-dup-chunks
Skip duplicate chunks when reading AIFF/WAV files.
2015-05-24 14:38:50 -04:00
Tsuda Kageyu
618a939c56 Fix MPEG::File::firstFrameOffset() and lastFrameOffset(). (#190) 2015-05-25 02:41:27 +09:00
Tsuda Kageyu
2337fbcfc6 Stop calculating the offset in RIFF::File::chunkData(). 2015-05-25 00:43:36 +09:00
Tsuda Kageyu
9da20a8a52 Skip duplicate chunks when reading AIFF/WAV files.
Similar to #492.
There is no good reason to use the last chunk rather than the first one.
2015-05-25 00:40:13 +09:00
Stephen F. Booth
4129b919c1 Merge pull request #572 from TsudaKageyu/map-erase2
Map::erase() can take a key directly so no need to call find() before…
2015-05-23 08:21:58 -04:00
Tsuda Kageyu
6d6f544010 Map::erase() can take a key directly so no need to call find() beforehand. 2015-05-23 18:12:01 +09:00
Stephen F. Booth
93da3ba6d9 Merge pull request #571 from TsudaKageyu/fuzzed-wv
Avoid an infinite loop when reading fuzzed WavPack files. (#482)
2015-05-22 07:44:41 -04:00
Stephen F. Booth
e064b88049 Merge pull request #570 from TsudaKageyu/audioprop-typo
Fix a typo in comment.
2015-05-22 07:41:46 -04:00
Tsuda Kageyu
3094540a4b Avoid an infinite loop when reading fuzzed WavPack files. (#482) 2015-05-22 14:15:10 +09:00
Tsuda Kageyu
8e21dcc3d4 Fix a typo in comment. 2015-05-22 12:06:01 +09:00
Stephen F. Booth
0ea22348cb Merge pull request #569 from TsudaKageyu/map-erase
std::map::erase() can take a key directly and has no-throw guarantee.
2015-05-21 22:46:15 -04:00
Stephen F. Booth
48ca54de1f Merge pull request #484 from TsudaKageyu/fix-rfind
Fix File::rfind() for small files.
2015-05-21 22:44:10 -04:00
Tsuda Kageyu
54de66f275 std::map::erase() can take a key directly and has no-throw guarantee. 2015-05-22 01:26:56 +09:00
Lukáš Lalinský
d4b0ba2a7a TagLib::XM::Properties is a public class that should be exported 2015-05-20 15:18:01 -07:00
Festus Hagen
abc5743222 Removed missed unnecessary BUILD_TESTS check. 2015-05-20 15:34:05 -04:00
Scott Wheeler
525396d9c2 Merge pull request #550 from TsudaKageyu/fix-test
Fix test code to work on some environments.
2015-05-20 19:24:52 +02:00
Tsuda Kageyu
bb9679b51a Fix test code to work on some environments.
const char * is more preferable than string for ifstream constructor.
2015-05-21 02:03:06 +09:00
Festus Hagen
e44cba56b5 Don't look for CppUnit unless BUILD_TESTS, general cleanup. 2015-05-20 11:11:55 -04:00
Scott Wheeler
e4cf012522 Bring the API more in line with the rest of TagLib
Like in #255, this also makes it possible to read values from the
tag in a const function.
2015-05-20 14:26:53 +02:00
Scott Wheeler
a37d423ea8 Merge pull request #549 from TsudaKageyu/win32-test
Modify the test code to work on MSVC/Windows.
2015-05-20 13:50:49 +02:00
Tsuda Kageyu
88a4cf34b8 Modify the test code to work on MSVC/Windows. 2015-05-20 20:19:20 +09:00
Scott Wheeler
81261dd128 This should also work Windows and has less duplicated code 2015-05-20 11:53:32 +02:00
Scott Wheeler
3bea9f6bee Don't use tempnam on UNIX
This silences the huge stream of warnings when building the tests.

I think I didn't break the Windows version in the process (though
it may make sense to use the built in Windows functions there
instead), but I don't have a Windows build environment here, so
I can't test.
2015-05-20 11:45:32 +02:00
Scott Wheeler
9cc2d7cfee Merge pull request #546 from TsudaKageyu/test-surrogate-pair
Add a test for strings that contains surrogate pairs.
2015-05-19 19:57:47 +02:00
Scott Wheeler
fe1bf015bb Merge pull request #548 from TsudaKageyu/render-twice
No need to call ID3v2::Frame::render() twice when saving an ID3v2 tag.
2015-05-19 11:28:50 +02:00
Tsuda Kageyu
287078566f No need to call ID3v2::Frame::render() twice when saving an ID3v2 tag. 2015-05-19 17:39:37 +09:00
Scott Wheeler
60966518e2 Quote path names including user-provided variables
This should make these work even if the value contains spaces

Closes #344
2015-05-19 10:15:15 +02:00
Tsuda Kageyu
2268efb49e Add a test for strings that contains surrogate pairs. 2015-05-19 09:01:47 +09:00
Scott Wheeler
29f535dc8d Remove *file argument to private members
This is already covered by d->file, so there's no reason to pass a pointer
to the member dozens of times.
2015-05-18 23:11:51 +02:00
Scott Wheeler
592522d34c Moar const fixes 2015-05-18 23:00:16 +02:00
Scott Wheeler
6b9e4e4403 1001 Const fixes (plus iterator rename) 2015-05-18 22:48:55 +02:00
Scott Wheeler
089e44f3db Remove unnecessary checks for null before delete
Closes #343
2015-05-18 21:40:21 +02:00
Scott Wheeler
bd3c4dc1b2 Merge pull request #515 from TsudaKageyu/empty-id3v2-frame
Skip empty ID3v2 frames when saving an ID3v2 tag.
2015-05-18 21:36:37 +02:00
Scott Wheeler
bba562b557 Add accessors to manipulate MP4 tags without modifying the internal structure
This brings the MP4 API in line closer to other tag formats and makes it
possible to access the tag data from const functions.

"ItemListMap" has been renamed to "ItemMap" (with the old version
deprecated).  It seems that the "ListMap" notion was copied probably
from Allan's ApeTag implementation, which incorrectly copied the term
from the XiphTag.  Notably, in XiphTag, because a field can have multiple
values, the "ListMap" is a map of lists.  Calling things a "ListMap" where
there can be only one value doesn't fit.

Closes #255
2015-05-18 21:18:33 +02:00
Scott Wheeler
451d23ca37 Add isEmpty() to MP4
Closes #457
2015-05-18 20:30:19 +02:00
Scott Wheeler
d248f77ab9 Show something useful for ChapterFrame::toString()
Closes #517
2015-05-18 19:51:18 +02:00
Tsuda Kageyu
727a11573a Fix File::rfind() for small files to work just like ByteVector::rfind(). 2015-05-19 01:24:37 +09:00
Scott Wheeler
34da0c0dab Update signature and docs
Specifically this allows the frame to be constructed and then to have
the children and embedded frames set later.
2015-05-18 18:19:43 +02:00
Scott Wheeler
7316cd331d Remove the null termination stuff from the ToC frames too 2015-05-18 18:17:10 +02:00
Scott Wheeler
3a977c55c4 We've moved away from including the null byte in the returned value
This does change previous behavior, but the previous behavior was
particularly stupid and inconsistent with everything else in TagLib.

It should be possible to mitigate this by putting the same safety
guards in the TableOfContents
2015-05-18 17:29:52 +02:00
Scott Wheeler
a094ce7dd2 Don't underflow if there are no embedded frames
Closes #513
2015-05-18 17:11:18 +02:00
Scott Wheeler
941efcba18 This isn't tracked as part of the elementID anymore 2015-05-18 16:53:12 +02:00
Scott Wheeler
ffb543acbb Split chapter data and embedded frame data
This will allow us to test parsing them separately
2015-05-18 16:45:57 +02:00
Scott Wheeler
fc24b3d22b Don't require users to include a padding byte explicitly
This makes it where the natural construction can be used of something
like:

new ChapterFrame("ID", ... )

Closes #514
2015-05-18 16:41:30 +02:00
Scott Wheeler
a9e064c58e Also test second constructor 2015-05-18 16:30:37 +02:00
Scott Wheeler
1a5d89d29e Update signature and docs to be more in-line with TagLib's style 2015-05-18 16:00:47 +02:00
Scott Wheeler
650b581f9e Merge pull request #544 from TsudaKageyu/advance
Use std::advance rather than a loop and increment.
2015-05-18 15:09:28 +02:00
Scott Wheeler
0739dd232a It doesn't make sense to set the factory after construction
Closes #259
2015-05-18 14:21:55 +02:00
Scott Wheeler
41a250a15d Make this macro work with current Qt versions
Closes #499
2015-05-18 12:42:24 +02:00
Tsuda Kageyu
8da0013482 Add a test to check if an empty ID3v2 frame is really skipped. 2015-05-18 19:03:20 +09:00
Scott Wheeler
0288059495 Add astylerc 2015-05-18 11:31:55 +02:00
Tsuda Kageyu
6e40361c0e Use std::advance rather than a loop and increment. 2015-05-18 09:31:43 +09:00
Lukáš Lalinský
c2570fe115 Merge pull request #521 from TsudaKageyu/gcc-warning
Fix a GCC/Clang warning about singed/unsigned comparison.
2015-05-17 10:06:10 -07:00
Lukáš Lalinský
bd91da55ba Merge pull request #542 from TsudaKageyu/comment-typos
Fix some typos in comment.
2015-05-17 10:05:43 -07:00
Tsuda Kageyu
3a3a6a6fda Fix some typos in comment. 2015-05-18 00:31:46 +09:00
Lukáš Lalinský
64c43b0d3f Merge pull request #535 from FestusHagen/fh1.m_UintAmbiguity
Silenced uint ambiguity error.
2015-05-16 17:03:53 -07:00
Lukáš Lalinský
db2dfa9515 Merge pull request #538 from gogglesmm/optimize-mid-to-uint
bytevector.mid(pos,4).toUInt() => bytevector.toUInt(pos)
2015-05-15 20:06:24 -07:00
Lukáš Lalinský
0069debf0c Merge pull request #536 from FestusHagen/fh1.m_CMakeSubProjectFix
Fix for using Taglib as a CMake sub directory project.
2015-05-15 19:48:43 -07:00
Lukáš Lalinský
69563d83a0 Merge pull request #533 from TsudaKageyu/bytevector-resize
Fix the wrong padding of ByteVector::resize().
2015-05-15 19:43:38 -07:00
Sander Jansen
60775306ea Fix code styling 2015-05-15 21:39:34 -05:00
Sander Jansen
4f77420248 replace use of bytevector.mid(pos,4).toUInt() with more optimized bytevector.toUInt(pos) 2015-05-15 21:25:44 -05:00
Tsuda Kageyu
b021ed44e9 Revert the last two commits.
But leave the tests unchanged, and add some comments.
2015-05-16 11:16:00 +09:00
Tsuda Kageyu
1f99c93a61 Reduce redundant memset when resizing ByteVector. 2015-05-16 03:46:34 +09:00
Tsuda Kageyu
a924ca0db7 Expand the internal buffer of ByteVector only if really needed.
Add tests for all execution paths of ByteVector::resize().
2015-05-14 11:20:35 +09:00
Festus Hagen
e43c1a3c09 Fix for using Taglib as a CMake sub directory project. 2015-05-09 20:29:52 -04:00
Festus Hagen
1e9529380d Silenced uint ambiguity error. 2015-05-09 14:19:33 -04:00
Tsuda Kageyu
ff8443f33a Fix the wrong padding of ByteVector::resize().
The expanded area will be filled with garbage instead of correct padding in some corner cases.
2015-05-02 02:43:08 +09:00
Lukáš Lalinský
62ab41fa07 Merge pull request #532 from TsudaKageyu/bytevector-detach-test
A little robuster tests for ByteVector iterators after detaching.
2015-04-29 10:14:16 -07:00
Tsuda Kageyu
00e3504264 A little robuster tests for ByteVector iterators after detaching. 2015-04-29 17:15:13 +09:00
Lukáš Lalinský
852da79899 Merge pull request #531 from TsudaKageyu/bytevector-detach
Fix ByteVector to return correct iterators after detached.
2015-04-28 20:34:53 -07:00
Tsuda Kageyu
ab047f6054 Fix ByteVector to return correct iterators after detached. 2015-04-29 10:28:08 +09:00
Lukáš Lalinský
5bad35c4cb Merge pull request #527 from TsudaKageyu/wma-guid
Fix saving WMA files with some GUID fields.
2015-04-28 10:42:06 -07:00
Tsuda Kageyu
8d708c03e1 Store any GUID fields in Metadata Library Object. 2015-04-28 16:40:24 +09:00
Tsuda Kageyu
f9a0b50830 Fix saving WMA files with some GUID fields. 2015-04-28 12:06:24 +09:00
Tsuda Kageyu
8491266b12 Fix a GCC/Clang warning about singed/unsigned comparison. 2015-04-17 09:38:21 +09:00
Stephen F. Booth
066b5aa57e Merge pull request #492 from TsudaKageyu/duplicate-id3v2-aiff-wav
Check AIFF/WAV files for duplicate tags.
2015-03-25 08:16:41 -04:00
Tsuda Kageyu
5f0a7da481 Take into account the frame header version when skipping an empty frame. 2015-03-24 10:41:39 +09:00
Tsuda Kageyu
d33d684fab Discard empty ID3v2 frames instead of adding a dummy null byte. 2015-03-24 10:31:52 +09:00
Tsuda Kageyu
4c4be0a263 Add a dummy byte to an empty ID3v2 frame to stick to the ID3v2 spec. 2015-03-22 22:14:21 +09:00
Michael Helmling
f476cf2b45 Merge pull request #511 from TsudaKageyu/tag-prop
Fix a bug that Tag::setProperties() clears the date instead of the track number
2015-03-20 10:28:20 +01:00
Tsuda Kageyu
68c0b0591b Fix a bug that Tag::setProperties() clears the date instead of the track number. 2015-03-20 13:33:13 +09:00
Stephen F. Booth
8fccaf30d2 Merge pull request #479 from TsudaKageyu/fuzzed-mp4
Fix an infinite loop when parsing MP4 files.
2015-02-18 08:15:50 -05:00
Tsuda Kageyu
b69973bcf2 Fix infinite loops when parsing MP4 files. 2015-02-18 11:33:10 +09:00
Tsuda Kageyu
30eac7569f Check AIFF/WAV files for duplicate tags.
AIFF/WAV files can have duplicate tags and it leads to memory leak.
2015-02-18 11:31:55 +09:00
Lukáš Lalinský
f6081ed32e Merge pull request #505 from TsudaKageyu/fuzzed-ape-tests
Separate the tests for fuzzed APE files.
2015-02-17 09:22:35 +01:00
Tsuda Kageyu
0839a23902 Separate the tests for fuzzed APE files. 2015-02-17 12:36:57 +09:00
Lukáš Lalinský
f35a279dd1 Merge pull request #496 from TsudaKageyu/fuzzed-mpc
Some fixes for fuzzed MPC files.
2015-02-16 19:26:57 +01:00
Tsuda Kageyu
e463d14f2e Check for EOF to fix a segfault while parsing fuzzed MPC files. 2015-02-17 01:22:39 +09:00
Tsuda Kageyu
829ae2112a Check the packet size to fix a segfault error while parsing fuzzed MPC files. 2015-02-17 01:22:39 +09:00
Tsuda Kageyu
65664e6855 Check for EOF to fix an infinite loop while parsing fuzzed MPC files. 2015-02-17 01:22:39 +09:00
Tsuda Kageyu
2193d6dd84 Fix an out-of-bounds access and consequent errors while parsing fuzzed MPC files.
Consequent errors may vary: segfault, zerodiv and so forth.
2015-02-17 01:22:38 +09:00
Stephen F. Booth
ef786188ad Merge pull request #502 from TsudaKageyu/fix-save-wav
Fix saving ID3v2/INFO tags of WAV files.
2015-01-31 14:12:18 -05:00
Tsuda Kageyu
2b5ee8deb9 Fix saving ID3v2/INFO tags of WAV files.
The old tag won't be removed when the new tag is empty.
2015-01-30 14:51:28 +09:00
Scott Wheeler
ed09c9cf87 Merge pull request #494 from TsudaKageyu/fix-zlib
Fix a wrong parameter for zlib.
2015-01-06 17:06:10 +01:00
Tsuda Kageyu
9d91610fc0 Fix a wrong parameter for zlib.
z_stream.avail_in has to be the length of the input buffer.
It will fail when frameDataLength is smaller than the actual compressed data size.
2015-01-06 18:45:42 +09:00
Stephen F. Booth
aed689c145 Merge pull request #491 from TsudaKageyu/aiff-hasid3v2
Implement missing AIFF::File::hasID3v2Tag().
2015-01-05 08:17:21 -05:00
Tsuda Kageyu
c6a63a3a2f Implement missing AIFF::File::hasID3v2Tag(). 2015-01-05 18:20:31 +09:00
Stephen F. Booth
2b0a540228 Merge pull request #490 from TsudaKageyu/remove-uncompr
Remove an unused file from taglib/CMakeLists.txt.
2015-01-04 22:31:42 -05:00
Tsuda Kageyu
2685ec1842 Remove an unused file from taglib/CMakeLists.txt.
uncompr.c is no longer used since caa53e8
2015-01-05 11:00:47 +09:00
Scott Wheeler
fdea6dcd40 Merge pull request #489 from TsudaKageyu/frame-flag-tests
Add some tests for huge memory allocation due to bad ID3v2 frame header ...
2015-01-05 02:03:06 +01:00
Tsuda Kageyu
ed253d3691 Add some tests for huge memory allocation due to bad ID3v2 frame header flags.
The tests covers #466 and #486.
Also fixes a compilation error on some compilers.
2015-01-05 09:34:30 +09:00
Scott Wheeler
57729b834a Show a debugging message when we have an error reading 2015-01-04 20:13:24 +01:00
Scott Wheeler
caa53e8de5 Read the compressed data as a stream
This avoids allocating the complete buffer at first based solely
on the value read from the frame header.  This then does a sanity
check at the end of reading to make sure that the two values match.
At present, it just prints a debugging message if the values do not
match.

Fixes #466
2015-01-04 19:58:18 +01:00
Lukáš Lalinský
31982660c8 Merge pull request #485 from TsudaKageyu/oga-segfault
Fix a segfault when reading faulty Ogg/FLAC files.
2015-01-01 19:48:23 +01:00
Lukáš Lalinský
bd7b8cc36a Merge pull request #473 from TsudaKageyu/fix-infotag
Fix an infinite loop when parsing an INFO tag.
2015-01-01 19:46:53 +01:00
Tsuda Kageyu
bc9bbfe3fa Add a check for faulty Ogg/FLAC files. 2015-01-02 00:10:51 +09:00
Tsuda Kageyu
7adea3df22 Separate tests for fuzzed WAV files. 2015-01-01 23:18:43 +09:00
Tsuda Kageyu
5ebb2ece80 Fix a segfault when reading faulty Ogg/FLAC files. 2015-01-01 19:59:30 +09:00
Tsuda Kageyu
0d2e01df61 Fix a segfault when parsing WAV properties. 2014-12-31 01:46:30 +09:00
Tsuda Kageyu
695fb5ec16 Add a test for fuzzed WAV files. 2014-12-31 01:44:25 +09:00
Tsuda Kageyu
3170d47ec3 Fix an infinite loop when parsing an INFO tag. 2014-12-31 01:44:25 +09:00
Stephen F. Booth
79b7c14129 Merge pull request #481 from TsudaKageyu/aiff-c
Add support for AIFF-C files.
2014-12-30 10:51:17 -05:00
Tsuda Kageyu
977fb2aeb0 Fix compilation errors on Clang. 2014-12-31 00:41:22 +09:00
Tsuda Kageyu
3b8c7d4e3a Add support for AIFF-C files. 2014-12-30 23:53:40 +09:00
Lukáš Lalinský
be33389884 Merge pull request #476 from TsudaKageyu/fuzzed-ape
Some fixes for fuzzed APE files.
2014-12-29 09:47:10 +01:00
Lukáš Lalinský
59ae61de6e Merge pull request #456 from TsudaKageyu/id3v2-padding
ID3v2 padding won't increase beyond 1% of the file size.
2014-12-29 09:26:55 +01:00
Tsuda Kageyu
16ac2cd240 Added some tests for fuzzed APE files. 2014-12-23 21:02:00 +09:00
Tsuda Kageyu
61543432c0 Fix an excessive loop when parsing an APE file. 2014-12-23 20:58:36 +09:00
Tsuda Kageyu
4a9614bfc3 Fix a division by zero error when parsing an APE file. 2014-12-23 20:54:20 +09:00
Tsuda Kageyu
1a917a38cd Fix ID3v2 padding size calculation. 2014-12-09 10:54:21 +09:00
Lukáš Lalinský
735e17f504 Merge remote-tracking branch 'TsudaKageyu/64bit-atom'
Conflicts:
	ConfigureChecks.cmake
2014-12-08 16:52:33 -08:00
Tsuda Kageyu
0731bc7b2e Remove CMake check for sizeof(long). 2014-12-09 08:55:46 +09:00
Bart van der Velden
fb1c744daf Compile without warnings with MSVC 2014-12-08 09:42:04 -08:00
Lukáš Lalinský
1bc5acd7a7 Merge pull request #424 from TsudaKageyu/format
Unified redundant string format functions. (backport from taglib2)
2014-12-08 09:38:03 -08:00
Lukáš Lalinský
f30f5ccce5 Merge pull request #441 from xhochy/tests-fix-vectorsize
Fix ByteVector sizes in some test cases
2014-12-08 09:36:28 -08:00
Lukáš Lalinský
421eb5e97e Merge pull request #420 from TsudaKageyu/remove-codecvt
Replaced codecvt with Win32 API.
2014-12-08 09:14:00 -08:00
Lukáš Lalinský
5e60ec48e9 Merge pull request #454 from TsudaKageyu/duplicate-id3v2
Skip duplicate ID3v2 tags in MPEG files.
2014-12-08 09:09:28 -08:00
Lukáš Lalinský
68eca440c9 Merge pull request #458 from achalddave/fix-gcc-errors
Fix more uint/TagLib::uint ambiguities
2014-12-08 08:54:27 -08:00
Achal Dave
7b03403791 Fix more uint/TagLib::uint ambiguities 2014-11-18 15:06:10 -08:00
Tsuda Kageyu
d80c4c96c3 ID3v2 padding won't increase beyond 1% of the file size. 2014-10-23 12:38:38 +09:00
Tsuda Kageyu
73b9b9b58d Avoid reading an entire ID3v2 tag when skipping it. 2014-10-23 08:14:10 +09:00
Lukáš Lalinský
072851869a Merge pull request #453 from TsudaKageyu/editorconfig
Suggestion: Use EditorConfig to help us stick to our coding style.
2014-10-22 19:31:14 +02:00
Tsuda Kageyu
269e78f1a0 Add a test for duplicate ID3v2 tags. 2014-10-21 00:16:43 +09:00
Tsuda Kageyu
71acf3b6f7 Comment on a weird workaround for duplicate ID3v2 tags. 2014-10-20 23:13:15 +09:00
Tsuda Kageyu
e41dc68a6b Skip duplicate ID3v2 tags in MPEG files. 2014-10-20 21:21:32 +09:00
Tsuda Kageyu
cfad951442 Use EditorConfig to help us stick to our coding style.
http://editorconfig.org/
2014-10-20 11:27:30 +09:00
Lukáš Lalinský
23ffb24472 Merge pull request #448 from TsudaKageyu/msvc-error
Fix a compilation error on MSVC.
2014-10-16 10:15:51 +02:00
Tsuda Kageyu
a8bfcd81be Fix a compilation error on MSVC. 2014-10-16 07:19:31 +09:00
Scott Wheeler
bd7419f0bd 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:07:09 +02:00
Scott Wheeler
71c1ce375f Don't leak 2014-09-25 20:46:47 +02:00
Scott Wheeler
cff8d22818 Missing assignment 2014-09-25 20:46:47 +02:00
Scott Wheeler
0051351ebb TableOfContents and ChapterFrame can be added to v2.3 or v2.4 tags 2014-09-25 20:01:00 +02:00
Scott Wheeler
82315276db Take ownership of embedded frames, as documented
Previously embedded frames that were created automatically were
never deleted.

Fixes #440
2014-09-18 16:23:28 +02:00
Scott Wheeler
8ea07be47e Merge branch 'master' of https://github.com/taglib/taglib 2014-09-18 16:12:34 +02:00
Scott Wheeler
eae4605e6e Merge pull request #439 from xhochy/test-memleaks
Fix various memleaks in the tests
2014-09-18 16:11:12 +02:00
Scott Wheeler
b6289c64dd Break up the mega-lines 2014-09-18 11:21:18 +02:00
Scott Wheeler
e6d7dd08f2 No reason to store this in the d-pointer 2014-09-18 10:24:48 +02:00
Uwe L. Korn
ee283789b7 Fix ByteVector sizes in some test cases 2014-09-14 20:08:31 +01:00
Uwe L. Korn
205569c8d2 Fix various memleaks in the tests 2014-09-14 18:03:27 +01:00
Lukáš Lalinský
4b67beffc8 Merge pull request #434 from DidierMalenfant/master
Ignoring files generated when creating an Xcode project via cmake.
2014-08-25 14:09:44 +02:00
Didier Malenfant
b7a514886d Ignoring files generated when creating an Xcode project via cmake. 2014-08-23 20:37:32 -07:00
Tsuda Kageyu
0e6d8617ae Revert "Removed an ambiguous cast from FileNameHandle to FileName."
This reverts commit 9af7601bae.
2014-08-23 00:04:33 +09:00
Tsuda Kageyu
dfbaee4103 Removed an ambiguous cast from FileNameHandle to FileName. 2014-08-23 00:04:33 +09:00
Tsuda Kageyu
f29c5f45f8 Workaround for 64-bit MP4 atoms. 2014-08-23 00:04:33 +09:00
Lukáš Lalinský
b1a8205561 Merge pull request #430 from TsudaKageyu/const-iterator
Reduce useless detach operations by making some non-const iterators cons...
2014-08-21 09:47:36 +02:00
Tsuda Kageyu
2971891c69 Reduce useless detach operations by making some non-const iterators const. 2014-08-21 16:35:35 +09:00
Lukáš Lalinský
d5e3d6ea7c Merge pull request #421 from TsudaKageyu/fix-wav-strip
Fixed a bug on stripping tags when saving .WAV files.
2014-08-20 10:12:43 +02:00
Lukáš Lalinský
20ce66f98b Merge pull request #422 from TsudaKageyu/detach
Added some missing detach()s to List<T>, ByteVector and String.
2014-08-20 10:09:08 +02:00
Stephen F. Booth
aff3351a25 Merge pull request #427 from TsudaKageyu/linebreak
Small fixes in line breaking.
2014-08-17 09:01:47 -04:00
Tsuda Kageyu
387890d956 Small fixes in line breaking. 2014-08-16 15:33:39 +09:00
Lukáš Lalinský
8765d40c2c Merge pull request #426 from TsudaKageyu/string-cmp
Added some operators to compare String to string literals.
2014-08-12 18:15:37 +02:00
Tsuda Kageyu
9bb0eb7ee9 Added some operators to compare String to string literals. 2014-08-12 23:58:45 +09:00
Lukáš Lalinský
d34c922c75 Merge pull request #425 from TsudaKageyu/fix-cmake
Removed a useless line from ConfigureChecks.cmake.
2014-08-12 09:42:19 +02:00
Tsuda Kageyu
3c727e091e Removed a useless line from ConfigureChecks.cmake. 2014-08-12 13:42:44 +09:00
Tsuda Kageyu
a055933e10 Unified the same debug messages. 2014-08-12 13:33:25 +09:00
Tsuda Kageyu
20c0aac309 Unified redundant string format functions. (backport from taglib2) 2014-08-11 01:09:07 +09:00
Tsuda Kageyu
929829b2b5 Removed useless strlen() and wcslen(). 2014-08-10 01:13:25 +09:00
Tsuda Kageyu
1944588595 Added some missing detach()s to List<T>, ByteVector and String. 2014-08-08 13:12:14 +09:00
Tsuda Kageyu
31a74927e4 Fixed a bug on stripping tags when saving .WAV files. 2014-08-07 18:49:53 +09:00
Tsuda Kageyu
972aa1feef Replaced codecvt with Win32 API. 2014-08-07 17:35:42 +09:00
Lukáš Lalinský
c23ee5331f Merge pull request #418 from TsudaKageyu/debug-msg
Fixed some debug messages.
2014-08-07 00:37:17 +02:00
Lukáš Lalinský
0f605be198 Merge pull request #414 from TsudaKageyu/fix-floattest
Fixed some mistakes in the CMake module for float types.
2014-08-07 00:36:59 +02:00
Tsuda Kageyu
590cb29f99 Improved the CMake check for float/double format. (Intel compiler support) 2014-08-06 20:57:04 +09:00
Tsuda Kageyu
286fd2abec Fixed some debug messages. 2014-08-06 16:13:15 +09:00
Tsuda Kageyu
f76d76728d Fixed some mistakes in the CMake module for float types. 2014-08-04 17:51:05 +09:00
Lukáš Lalinský
80f5436370 Merge pull request #413 from TsudaKageyu/msvc-tests3
Fixed a test to work with MSVC.
2014-08-04 09:09:20 +02:00
Tsuda Kageyu
043d2bbef5 Fixed a test to work with MSVC. 2014-08-04 15:11:50 +09:00
Lukáš Lalinský
cf59d51d93 Merge pull request #406 from TsudaKageyu/utf16-byteorder
Fixed handling UTF-16 byte order.
2014-07-23 10:21:37 +02:00
Lukáš Lalinský
9569b99e4c Merge pull request #405 from TsudaKageyu/missing-include
Added a missing #include.
2014-07-23 10:20:38 +02:00
Tsuda Kageyu
590405d878 Fixed handling UTF-16 byte order. 2014-07-23 15:36:16 +09:00
Tsuda Kageyu
c03b91aed3 Added a missing #include. 2014-07-23 14:56:18 +09:00
Lukáš Lalinský
ee2908a6cf Merge pull request #399 from TsudaKageyu/float-conv
Added float conversion functions to ByteVector.
2014-07-22 12:10:54 +02:00
Tsuda Kageyu
e29f1d39e7 Added float conversion functions to ByteVector.
Added CMake checks about IEEE754 compliance.
2014-07-17 12:09:14 +09:00
Lukáš Lalinský
b509106031 Merge pull request #398 from TsudaKageyu/fix-chap
Fixed some compilation error on MSVC in CHAP and CTOC frames support.
2014-07-16 22:30:10 +02:00
Tsuda Kageyu
47cd6fad4f Fixed some compilation error on MSVC in CHAP and CTOC frames support. 2014-07-17 01:43:56 +09:00
Lukáš Lalinský
fb24dfe7cf Merge pull request #393 from TsudaKageyu/msvc-tests
Modified some tests to work with MSVC.
2014-07-16 16:02:10 +02:00
Lukáš Lalinský
f42263e04a Merge pull request #392 from TsudaKageyu/zlib-source
Added a Windows-friendly build option ZLIB_SOURCE.
2014-07-16 15:58:52 +02:00
Lukáš Lalinský
43872f362d Merge pull request #390 from TsudaKageyu/vector-bounds
Fixed out-of-bounds access in findVector().
2014-07-16 15:57:55 +02:00
Lukáš Lalinský
73d3436570 Merge pull request #391 from TsudaKageyu/setlasterror
Added some SetLastError()s to get correct error codes in Win32.
2014-07-16 15:56:59 +02:00
Lukáš Lalinský
1e50b8dc25 Merge pull request #394 from ufleisch/master
Add genres 148 to 191 to list of ID3v1 genres.
2014-07-16 15:54:03 +02:00
Lukáš Lalinský
4a585c5258 Merge remote-tracking branch 'krejclu6/krejclu6_chapters' 2014-07-16 15:52:41 +02:00
Tsuda Kageyu
5f738a9819 Changed to skip the ZLib check when ZLIB_SOURCE is set. 2014-07-09 09:52:08 +09:00
Tsuda Kageyu
d7995b807f Fixed the tests to work with MSVC when UNICODE is set. 2014-06-24 01:29:15 +09:00
Urs Fleisch
3e60e339a4 Add genres 148 to 191 to list of ID3v1 genres.
This genres were added for Winamp version 5.6, see
<http://en.wikipedia.org/wiki/ID3#List_of_genres>.
2014-06-21 12:34:42 +02:00
Tsuda Kageyu
5feabe0988 Updated INSTALL. 2014-06-20 10:36:09 +09:00
Tsuda Kageyu
29a5129096 Modified some tests to work with MSVC. 2014-06-20 09:06:26 +09:00
Tsuda Kageyu
fadb57e4cd Added a Windows-friendly build option ZLIB_SOURCE. 2014-06-19 19:54:12 +09:00
Tsuda Kageyu
653b631aea Added a check for patternSize and removed a useless check. 2014-06-19 16:57:36 +09:00
Tsuda Kageyu
cb3abf15ad Added a test for out-of-bounds access in findVector(). 2014-06-19 13:22:50 +09:00
Tsuda Kageyu
29377fc8f1 Added some SetLastError()s to get correct error codes in Win32. 2014-06-19 12:58:07 +09:00
Tsuda Kageyu
663f10d51d Fixed out-of-bounds access in findVector(). 2014-06-19 12:19:18 +09:00
Lukas Krejci
a192db07c0 Code clean-up. 2014-06-11 17:52:05 +02:00
Lukas Krejci
459adc69ad Merge branch 'krejclu6_chapters' of https://github.com/krejclu6/taglib into krejclu6_chapters
Conflicts:
	taglib/mpeg/id3v2/id3v2framefactory.cpp
	tests/test_id3v2.cpp
2014-05-18 16:29:54 +02:00
Lukas Krejci
500b3e630b Uncommenting unit test. 2014-05-18 16:15:35 +02:00
Lukas Krejci
5c5c89e8d9 Added functions for work with embedded frames.
Added embedded frames parsing.

Added embedded frames rendering.
Modified constructor of CHAP and CTOC frame, so it can accept list of embedded frames.

Added unit tests for CHAP and CTOC frames parsing and rendering (with support of embedded frames).
Fixed bugs in rendering of CTOC frames.
Added functions for adding and removing child elements in CTOC frames.
2014-05-18 16:15:35 +02:00
Lukáš Krejčí
140fb2b3f6 Removed duplicated CHAP frame testing funtion. 2014-05-18 16:15:35 +02:00
Lukáš Krejčí
98ed58f910 Changed copyright and e-mail in modified files. 2014-05-18 16:15:35 +02:00
Lukáš Krejčí
7d99b8276a Fixed errors in ChapterFrame constructor.
Fixed errors in ChapterFrame method renderFields.
Fixed errors in TableOfContentsFrame method parseFields.
Added ChapterFrame and TableOfContentsFrame headers and sources to CMakeLists.txt.
Added some basic testing of CHAP and CTOC frames parsing.
2014-05-18 16:15:35 +02:00
Lukáš Krejčí
17841e89ae Fixed error in childElements function. 2014-05-18 16:14:00 +02:00
Lukáš Krejčí
c5f9258462 Finished parseFields, renderFields and asProperty methods of ChapterFrame and TableOfContentsFrame classes.
Methods setElementID of ChapterFrame and TableOfContentsFrame classes now automatically terminates new element ID with null.
2014-05-18 16:14:00 +02:00
Lukáš Krejčí
3a1040d55b Added basic members of ChapterFrame and TableOfContentsFrame classes.
Fixed minor bugs in ChapterFrame and TableOfContentsFrame headers.
2014-05-18 16:11:55 +02:00
Lukáš Krejčí
0864634ea6 Created CPP and H files for CTOC and CHAP frames. 2014-05-18 16:11:55 +02:00
Stephen F. Booth
f27e0aaecf Merge pull request #370 from supermihi/fix162v2
Fix #162: Xiph and APE generic getters return space-concatenated values
2014-04-24 21:35:50 -04:00
Lukáš Lalinský
ecc768d459 Merge pull request #380 from TsudaKageyu/fix-comment
Removed a wrong note from a comment in tstring.h.
2014-04-11 10:33:56 +02:00
Tsuda Kageyu
fabc411cb9 Removed a wrong note from a comment in tstring.h. 2014-04-11 17:16:55 +09:00
Lukáš Lalinský
2d528d844a Merge pull request #356 from TsudaKageyu/string-comment
Added some comment about UTF-16 encoding to String::data().
2014-04-10 20:05:55 +02:00
Lukáš Lalinský
c65753c766 Add ALBUMARTIST property mapping for WMA 2014-04-10 20:05:14 +02:00
Lukáš Lalinský
7e10b13962 Merge pull request #372 from TsudaKageyu/cmake-warning
Suppressed the warning "Policy CMP0022 is not set" on CMake 2.8.12.
2014-04-10 20:04:17 +02:00
Lukáš Lalinský
05e26119f7 Merge pull request #377 from amigadave/master
Add ALBUMARTIST property mapping for MP4
2014-04-10 20:01:36 +02:00
David King
95a59c416b Add ALBUMARTIST property mapping for MP4
https://code.google.com/p/mp4v2/wiki/iTunesMetadata
2014-04-10 17:33:29 +01:00
Tsuda Kageyu
3f557be608 Suppressed the warning "Policy CMP0022 is not set" on CMake 2.8.12. 2014-04-05 21:08:21 +09:00
Lukáš Lalinský
9ca7877587 Merge pull request #371 from TsudaKageyu/cmake-ver
Changed cmake_minimum_required from 2.6.0 to 2.8.0.
2014-04-05 13:07:58 +02:00
Tsuda Kageyu
a93ee10134 Changed cmake_minimum_required from 2.6.0 to 2.8.0. 2014-04-05 19:44:47 +09:00
Michael Helmling
1723e9b18a Fix #162: Xiph and APE generic getters return space-concatenated values 2014-04-03 21:07:29 +02:00
Lukáš Lalinský
16b8688c1a Merge pull request #362 from ufleisch/master
Add support for synchronized lyrics (SYLT) and event timing codes (ETCO) for ID3v2
2014-03-30 19:21:47 +02:00
Urs Fleisch
3b60af2c0b Add support for ID3v2 ETCO frames (event timing codes). 2014-03-30 09:28:14 +02:00
Urs Fleisch
eba99c3a70 Add support for ID3v2 SYLT frames (synchronized lyrics). 2014-03-30 09:26:03 +02:00
Tsuda Kageyu
6bcd422afa Small fix of a comment 2014-03-14 15:12:03 +09:00
Tsuda Kageyu
c357d293a1 Added some comment about UTF-16 encoding to String::data(). 2014-03-13 14:38:03 +09:00
Stephen F. Booth
cfb43223dc Merge pull request #354 from TsudaKageyu/opus-bitrate
opus: Estimate the bitrate if possible
2014-03-09 21:37:50 -04:00
Tsuda Kageyu
72cd379f30 opus: Estimate the bitrate if possible 2014-03-10 09:37:10 +09:00
Lukáš Lalinský
a3d724af27 Merge pull request #352 from TsudaKageyu/tagreader-sprintf
Avoid using sprintf() in tagreader.cpp to fix an MSVC warning.
2014-02-19 16:34:42 +01:00
Tsuda Kageyu
05e0081414 Avoid using sprintf() in tagreader.cpp to fix an MSVC warning. 2014-02-19 23:35:23 +09:00
Lukáš Lalinský
b658f95e06 Merge pull request #338 from funman/master
Also build/install taglib_c.pc when targetting windows
2014-02-17 08:46:13 +01:00
Lukáš Lalinský
2758aed34d Merge pull request #348 from TsudaKageyu/string-memcpy
Reduced a useless memory copy in tstring.cpp.
2014-02-17 08:45:49 +01:00
Lukáš Lalinský
12b25868b7 Merge pull request #349 from TsudaKageyu/install-typo
Fixed a typo in INSTALL.
2014-02-17 08:44:54 +01:00
Tsuda Kageyu
1deff52d95 Fixed a typo in INSTALL. 2014-02-17 11:22:40 +09:00
Tsuda Kageyu
69eaa75f64 Reduced a useless memory copy in tstring.cpp. 2014-02-15 20:25:00 +09:00
Lukáš Lalinský
3e0c73bdbc Merge pull request #347 from TsudaKageyu/xm-seek
Changed XM::File::save() to use seek() properly.
2014-02-14 17:21:49 +01:00
Tsuda Kageyu
9e94f8bb6c Changed XM::File::save() to use seek() properly. 2014-02-14 19:22:53 +09:00
Lukáš Lalinský
aa49723b48 Merge pull request #330 from TsudaKageyu/fix-emptystring
Fixed a bug reported at #328
2014-02-05 00:02:47 -08:00
Tsuda Kageyu
167513ae57 Avoid using &d->data[0] when d->data is empty. 2014-02-05 10:35:07 +09:00
Tsuda Kageyu
d0f3e9b186 Use std::string::c_str() rather than &s[0] where a const pointer is required. 2014-01-24 09:48:39 +09:00
Stephen F. Booth
4fc020e0d3 Merge pull request #340 from mineo/patch-1
Remove a superfluos 'x'
2014-01-18 13:12:21 -08:00
Wieland Hoffmann
db147e672e Remove a superfluos 'x' 2014-01-18 18:11:31 +01:00
Rafaël Carré
c45a0694f9 Also build/install taglib.pc when targetting windows
.pc file is notably used when cross-compiling windows software
2014-01-13 22:49:17 +01:00
Tsuda Kageyu
584bbc7c78 Fixed conversion from empty String to ByteVector 2013-12-04 09:37:59 +09:00
Lukáš Lalinský
10b804e0ae Merge pull request #322 from TsudaKageyu/mailaddress
Fixed a mail address
2013-11-24 23:25:19 -08:00
Tsuda Kageyu
4f8ab4b63f Fixed a mail address 2013-11-25 14:12:34 +09:00
Stephen F. Booth
5593c251c8 Merge pull request #321 from TsudaKageyu/nominmax
Fixed warnings in MinGW
2013-11-23 19:24:55 -08:00
Tsuda Kageyu
7d7a7be115 Fixed warnings in MinGW 2013-11-23 23:42:20 +09:00
Stephen F. Booth
f733077917 Merge pull request #307 from TsudaKageyu/string-abi
Fixed the ABI breakage in TagLib::String
2013-11-15 15:04:30 -08:00
Stephen F. Booth
670493f97f Merge pull request #310 from TsudaKageyu/backslash
Replaced wrongly used slashes with backslashes in some comments
2013-11-15 03:55:04 -08:00
Tsuda Kageyu
d4adc22922 Replaced wrongly used slashes with backslashes in some comments 2013-11-15 15:31:23 +09:00
Stephen F. Booth
34f8cd8a90 Merge pull request #309 from TsudaKageyu/fix-replace
Rewrote ByteVector::replace() simpler (fix for the issue #308)
2013-11-14 07:01:29 -08:00
Tsuda Kageyu
4a7d31c87b Rewrote ByteVector::replace() simpler 2013-11-14 14:58:14 +09:00
Tsuda Kageyu
3bf30af66c Fixed ABI breakage in TagLib::String 2013-11-06 17:01:21 +09:00
Lukáš Lalinský
ee9720a997 Merge pull request #304 from funman/master
Win32: avoid symbol lookup if UNICODE is defined
2013-10-28 01:12:48 -07:00
Rafaël Carré
69e58b5f3f Win32: avoid symbol lookup if UNICODE is defined 2013-10-28 04:39:04 +01:00
Lukas Krejci
1ce5385e30 Uncommenting unit test. 2013-10-13 18:38:54 +02:00
Lukas Krejci
5ed2d88f78 Added functions for work with embedded frames.
Added embedded frames parsing.

Added embedded frames rendering.
Modified constructor of CHAP and CTOC frame, so it can accept list of embedded frames.

Added unit tests for CHAP and CTOC frames parsing and rendering (with support of embedded frames).
Fixed bugs in rendering of CTOC frames.
Added functions for adding and removing child elements in CTOC frames.
2013-10-13 18:27:43 +02:00
Lukáš Lalinský
aa61823432 Fix the length of the TXXX translation mapping (closes #283) 2013-10-08 17:50:01 +02:00
Lukáš Lalinský
2f7af42092 Update version to 1.9.1 2013-10-08 17:46:34 +02:00
Lukáš Lalinský
2d5abd46d2 Added TagLib::MP4::PropertyMap::codec() 2013-10-08 17:41:09 +02:00
Lukáš Lalinský
9b5869ea37 Merge remote-tracking branch 'TsudaKageyu/chunksize' 2013-10-08 16:18:43 +02:00
Lukáš Lalinský
02ebd0bcbe Change log for 1.9.1 2013-10-08 16:18:30 +02:00
Lukáš Lalinský
5693ab0403 Merge remote-tracking branch 'TsudaKageyu/fix-string' 2013-10-08 16:12:49 +02:00
Lukáš Lalinský
27000438f5 Merge remote-tracking branch 'TsudaKageyu/msvc_wchar_t' 2013-10-08 16:09:01 +02:00
Lukáš Lalinský
a6f759cc9a These shouldn't be executable either 2013-10-08 16:06:58 +02:00
Lukáš Lalinský
a175b8356b Reintroduce the old RefCounter from 1.8, which is needed by TagLib::Map<> and TagLib::List<> (closes #296) 2013-10-08 16:06:03 +02:00
Tsuda Kageyu
873df184fe Workaround for when MSVC doesn't have wchar_t as a built-in type 2013-10-08 19:55:44 +09:00
Tsuda Kageyu
079e3e0b87 Fixed detecting RIFF files with invalid chunk sizes 2013-10-07 17:04:55 +09:00
Lukáš Lalinský
95776b5905 These files should not be marked as executable 2013-10-06 17:11:01 +02:00
Lukáš Lalinský
dcfb71bcb4 Update version number to 1.9 2013-10-05 10:53:15 +02:00
Lukáš Lalinský
f2c9ed4f36 Update NEWS 2013-10-05 10:09:09 +02:00
Lukáš Lalinský
2407933087 Merge remote-tracking branch 'TsudaKageyu/wavpack-samplerate' 2013-10-05 09:53:49 +02:00
Stephen F. Booth
2af43ec8bf Merge pull request #290 from FestusHagen/m_WinInstallNotes
Update Windows INSTALL notes.
2013-10-01 19:51:11 -07:00
Festus Hagen
85d76a2428 Update Windows INSTALL notes. 2013-09-30 18:06:55 -04:00
Stephen F. Booth
5a4a05d9bc Merge pull request #280 from TsudaKageyu/info-fieldlist
Added a missing fieldListmap() method to RIFF::Info::Tag
2013-09-28 18:07:26 -07:00
Stephen F. Booth
a2188e6cf9 Merge pull request #285 from TsudaKageyu/algorithm
Added missing #include <algorithm> for std::min() and std::max()
2013-09-20 04:59:27 -07:00
Tsuda Kageyu
e6f9a06894 Added missing #include <algorithm> for std::min() and std::max() 2013-09-20 08:26:37 +09:00
Tsuda Kageyu
e125bcb78b Fixed a possible out-of-bound access when reading WavPack files 2013-09-19 04:09:28 +09:00
Tsuda Kageyu
23b418b4e9 Added a missing fieldListmap() method to RIFF::Info::Tag 2013-09-17 14:59:19 +09:00
Tsuda Kageyu
cf892f2cb8 Fixed a bug in creating String from ByteVector 2013-09-13 03:47:03 +09:00
Lukáš Lalinský
c12b6697f9 Merge remote-tracking branch 'TsudaKageyu/byteorder-detection' 2013-07-21 14:42:50 +02:00
Tsuda Kageyu
89fcab5669 Fixed an MSVC specific runtime error only in debug mode 2013-07-17 23:35:41 +09:00
Tsuda Kageyu
35ca010df6 Introduced the runtime byte order detection when config.h is missing 2013-07-17 15:02:02 +09:00
Tsuda Kageyu
0f58646bfb Added a test for APE::Item 2013-07-14 11:35:10 +09:00
Tsuda Kageyu
4d126c49e9 Fixed a crash of APE::Item::toString() when the data type is binary 2013-07-14 02:47:48 +09:00
Lukáš Lalinský
3a636c752b Merge remote-tracking branch 'TsudaKageyu/string-api-master' 2013-07-11 10:08:05 +02:00
Lukáš Lalinský
ff5ab030c5 Merge remote-tracking branch 'TsudaKageyu/fix-opus' 2013-07-11 10:06:35 +02:00
Lukáš Lalinský
ff3b1466e1 Merge remote-tracking branch 'TsudaKageyu/comment-update' 2013-07-11 10:05:29 +02:00
Lukáš Lalinský
89cb785f22 Merge remote-tracking branch 'TsudaKageyu/has-tags' 2013-07-11 10:03:28 +02:00
Tsuda Kageyu
30f62ba887 Updated the relevant comments 2013-07-04 22:14:42 +09:00
Tsuda Kageyu
1503909824 Added the methods to check which kind of tags the file actually has. 2013-07-04 18:11:33 +09:00
Tsuda Kageyu
75b685fa53 Updated the related comments 2013-06-24 01:29:33 +09:00
Tsuda Kageyu
62d55223b2 Added conversion from String to const wchar_t* 2013-06-24 01:13:25 +09:00
Tsuda Kageyu
418a6c79cb Comment update: Added some supplementary explanations and fixed some spellings. 2013-06-23 02:08:10 +09:00
Tsuda Kageyu
ab417fd9e3 Changed the style to follow TagLib's one 2013-06-22 18:06:40 +09:00
Tsuda Kageyu
35cdcd3b95 Added a missing check if an Opus file is open 2013-06-22 16:12:57 +09:00
Tsuda Kageyu
a845f70c49 Added some test cases for FileRef about unsupported files 2013-06-21 15:29:00 +09:00
Lukáš Lalinský
7e866e11ad Merge remote-tracking branch 'FestusHagen/sw_initorder' 2013-06-21 08:01:50 +02:00
Festus Hagen
6acbcfc68a Fix file modes 2. 2013-06-20 18:50:14 -04:00
Festus Hagen
02c81aaac2 Fix file modes. 2013-06-20 18:37:06 -04:00
Festus Hagen
550510ff3f Silence Initialization Order Warnings 2. 2013-06-20 16:40:05 -04:00
Lukáš Lalinský
5051010835 Move byteSwap to a (private) shared include file, rather than having the same code in tstring.cpp and tbytevector.cpp 2013-06-20 15:22:06 +02:00
Lukáš Lalinský
fdb8a6b065 Reintroduce HAVE_CONFIG_H so that TagLib can be built without CMake 2013-06-20 15:07:25 +02:00
Lukáš Lalinský
6d4299ea94 Merge remote-tracking branch 'TsudaKageyu/debug-msg3' 2013-06-20 13:40:26 +02:00
Tsuda Kageyu
b84b3afc9c Making use of std::bitset::to_string() 2013-06-15 13:21:07 +09:00
Festus Hagen
451616f99a Silence Initialization Order Warnings. 2013-06-11 17:20:46 -04:00
Tsuda Kageyu
496b58e0c9 Updated the comment for DebugListener class 2013-06-11 19:23:46 +09:00
Tsuda Kageyu
886236b978 Removed getDebugListener() 2013-06-10 16:29:33 +09:00
Tsuda Kageyu
6d2e0e8050 Moved a macro from taglib_config.h to config.h 2013-06-10 01:19:47 +09:00
Tsuda Kageyu
2f29ed003c Added a CMake option that allows to show debug messages in release mode 2013-06-09 23:52:05 +09:00
Tsuda Kageyu
12953b3fdc Removed TAGLIB_EXPORT from getDebugListener 2013-06-08 22:26:13 +09:00
Tsuda Kageyu
448648d61b Simplified DebugListener class 2013-06-08 21:40:30 +09:00
Lukáš Lalinský
241465eaac Merge branch 'revert-changes' of https://github.com/TsudaKageyu/taglib 2013-06-08 12:58:53 +02:00
Tsuda Kageyu
dce00b96b8 Revert "Fixed some MSVC specific warnings"
This reverts commit 93f304a91d.
2013-06-08 13:14:06 +09:00
Tsuda Kageyu
3b2d620671 Enabled users to define custom debug message listeners 2013-06-08 09:59:36 +09:00
Tsuda Kageyu
e18546560e Enabled users to define custom debug message listeners 2013-06-08 03:05:50 +09:00
naiar
fc9abc7a33 fixed build failure 2013-06-07 20:00:13 +09:00
Tsuda Kageyu
98d010f460 Merge pull request #232 from TsudaKageyu/remove-shlwapi
Removed the dependency on shlwapi.dll in Win32
2013-06-05 21:59:11 -07:00
Tsuda Kageyu
36d7f9ba32 Removed the dependency on shlwapi.dll in Win32 2013-06-06 13:45:23 +09:00
Tsuda Kageyu
c4c5b06643 Merge pull request #231 from TsudaKageyu/containsat
Fixed behavior change of ByteVector::containsAt()
2013-06-01 12:03:34 -07:00
Tsuda Kageyu
767a6ec4a2 Added some tests for containsAt() 2013-06-02 04:00:34 +09:00
Tsuda Kageyu
860a605c8d Fixed behavior change of ByteVector::containsAt() 2013-06-02 03:45:13 +09:00
Tsuda Kageyu
df5bf232eb Merge pull request #230 from TsudaKageyu/gcc42-3
Fixed compilation error with GCC4.2
2013-06-01 10:49:07 -07:00
Tsuda Kageyu
90a4bae6cc Fixed compilation error with GCC4.2 2013-06-02 02:37:15 +09:00
Tsuda Kageyu
3ae452ee2a Merge pull request #229 from TsudaKageyu/gcc42-2
Fixed compilation error with GCC4.2
2013-06-01 10:11:52 -07:00
Tsuda Kageyu
bc2d3ea72e Fixed compilation error with GCC4.2 2013-06-02 02:05:11 +09:00
Tsuda Kageyu
9ccc4878d0 Merge pull request #228 from TsudaKageyu/gcc42
Fixed compilation error with GCC4.2
2013-06-01 08:05:29 -07:00
Tsuda Kageyu
6365f36c75 Fixed compilation error with GCC4.2 2013-06-01 23:55:52 +09:00
Tsuda Kageyu
da3d9b1c55 Merge pull request #226 from TsudaKageyu/file-comments
Fixed comments for File constructors
2013-05-30 22:34:21 -07:00
Tsuda Kageyu
f77a84486e Fixed comments for File constructors 2013-05-30 02:04:10 +09:00
Tsuda Kageyu
cf9f2a436b Merge pull request #224 from TsudaKageyu/memoryleak
Fixed memory leak of ByteVector
2013-05-27 08:20:38 -07:00
Tsuda Kageyu
e73afa3325 Fixed memory leak of ByteVector 2013-05-28 00:02:09 +09:00
Tsuda Kageyu
dfee045d46 Merge pull request #222 from TsudaKageyu/vc-filename
Fixed some MSVC specific warnings
2013-05-26 06:03:49 -07:00
Tsuda Kageyu
93f304a91d Fixed some MSVC specific warnings 2013-05-26 14:38:36 +09:00
Tsuda Kageyu
ddabffc7ef Merge pull request #221 from TsudaKageyu/fix-shlwapi
Fixed shlwapi.h and shlwapi.lib detection for MSVC
2013-05-25 12:20:57 -07:00
Tsuda Kageyu
42d268c2c9 Fixed shlwapi.h and shlwapi.lib detection for MSVC 2013-05-26 04:17:18 +09:00
Tsuda Kageyu
e7c0f3322d Merge pull request #220 from FestusHagen/cmake_shlwapi
Added FindShlwapi.cmake in lieu of pragma comment() in fileref.h.
2013-05-25 12:04:08 -07:00
Festus Hagen
b3f3eeeec7 Added FindShlwapi.cmake in lieu of pragma comment() in fileref.h. 2013-05-25 01:58:49 -04:00
Tsuda Kageyu
54fbe15611 Merge pull request #219 from joelverhagen/master
Windows build fails on master (due to RefCounter not being exported)
2013-05-23 18:44:15 -07:00
Joel Verhagen
d7523d7843 Added TAGLIB_EXPORT to RefCounter for Windows build 2013-05-23 13:42:51 -04:00
Tsuda Kageyu
ca801c5411 Merge pull request #215 from TsudaKageyu/smallfile
Fixed bugs on manipulating small files
2013-05-23 02:22:48 -07:00
Tsuda Kageyu
4667ba02e5 Fixed bugs on manipulating small files 2013-05-23 17:45:16 +09:00
Tsuda Kageyu
3151336050 Merge pull request #209 from TsudaKageyu/bytevector
Changed behavior of ByteVector::toNumber() when overrun
2013-05-20 13:50:59 -07:00
Tsuda Kageyu
848f8c316e Changed behavior of ByteVector::toNumber() when overrun 2013-05-21 05:36:01 +09:00
Tsuda Kageyu
2303da48a2 Merge pull request #204 from TsudaKageyu/number
Changed String::number() to use a standard function
2013-05-18 22:59:02 -07:00
Tsuda Kageyu
bbec1c7f81 Changed String::number() to use a standard function 2013-05-19 14:39:45 +09:00
Tsuda Kageyu
79f3edebc0 Added myself to AUTHORS 2013-05-19 11:59:37 +09:00
Tsuda Kageyu
d49d0a6888 Merge pull request #203 from TsudaKageyu/fix-filestream
Fixed initialization of FileStream
2013-05-18 19:21:36 -07:00
Tsuda Kageyu
5c3f096fe4 Fixed initialization of FileStream 2013-05-19 11:09:43 +09:00
Tsuda Kageyu
7060d53cf3 Merge pull request #202 from TsudaKageyu/fix-filestream
Small refactoring of FileStream
2013-05-18 10:49:31 -07:00
Tsuda Kageyu
dcf11b9586 Small refactoring of FileStream 2013-05-19 02:33:17 +09:00
Tsuda Kageyu
229d69864d Merge pull request #201 from TsudaKageyu/unicodefile
Small change in Win9x support
2013-05-18 07:41:07 -07:00
Tsuda Kageyu
36d9fc1973 Small change in Win9x support 2013-05-18 23:30:15 +09:00
Tsuda Kageyu
d06f480f82 Merge pull request #199 from TsudaKageyu/fix-zlib
Fixed the test for ID3V2's compressed frame
2013-05-16 04:38:24 -07:00
Tsuda Kageyu
f9efcfb8d6 Fixed the test for ID3V2's compressed frame 2013-05-16 20:29:58 +09:00
Lukáš Krejčí
cbd6f73431 Removed duplicated CHAP frame testing funtion. 2013-05-04 21:25:55 +02:00
Tsuda Kageyu
db06166330 Merge pull request #187 from TsudaKageyu/config
Removed config.h and moved macros into taglib_config.h
2013-05-03 08:03:51 -07:00
Tsuda Kageyu
5d8f781467 Fixed mismatched macro names 2013-05-03 21:05:55 +09:00
Tsuda Kageyu
03adafbfd9 Removed TAGLIB_HAVE_STD_WSTRING macro that affects the public ABI 2013-05-03 18:28:28 +09:00
Tsuda Kageyu
198530547d Removed RefCounter implementation from a public header 2013-05-03 13:53:32 +09:00
Tsuda Kageyu
4b6745b59b Merge pull request #188 from TsudaKageyu/string-comment
Fixed comments in tstring.h
2013-05-02 21:10:26 -07:00
Tsuda Kageyu
6f0bf734d5 Fixed comments in tstring.h 2013-05-03 13:03:38 +09:00
Tsuda Kageyu
23bd3784a1 Separated public and private config.h 2013-05-03 11:44:36 +09:00
Tsuda Kageyu
8f8ef3788f Prefixed public variables 2013-05-02 23:26:06 +09:00
Tsuda Kageyu
b0938a3cf1 Removed config.h and moved macros into taglib_config.h 2013-05-02 20:41:59 +09:00
Tsuda Kageyu
a2688a1ff0 Merge pull request #180 from TsudaKageyu/master
Fixed possible memory leak
2013-04-30 09:39:23 -07:00
Tsuda Kageyu
d6fc2ef4aa Fixed possible memory leak 2013-05-01 01:32:48 +09:00
Tsuda Kageyu
9f29804f60 Merge pull request #178 from rakuco/clear-mbstate_t-correctly
Correctly initialize std::mbstate_t.
2013-04-29 15:06:57 -07:00
Raphael Kubo da Costa
289b6abb43 Correctly initialize std::mbstate_t.
mbstate_t is an opaque type that is often a union or a struct, so setting it
directly to 0 is incorrect and causes build failures with some compilers
such as clang.
2013-04-29 23:56:07 +03:00
Tsuda Kageyu
55f1224d6e Merge pull request #176 from TsudaKageyu/master
Add some error handling to tfilestream.cpp
2013-04-27 17:37:17 -07:00
Tsuda Kageyu
395743eb49 Add some error handling to tfilestream.cpp 2013-04-28 09:14:37 +09:00
Tsuda Kageyu
62827269b6 Merge pull request #175 from TsudaKageyu/master
Comment update
2013-04-27 11:10:37 -07:00
Tsuda Kageyu
d2273a7218 Comment update 2013-04-28 03:06:59 +09:00
Tsuda Kageyu
bd85cf8928 Merge pull request #174 from TsudaKageyu/alignment
Fixed detection of alignment-tolerant CPUs
2013-04-27 11:02:31 -07:00
Tsuda Kageyu
f3cbb883f2 Fixed detection of alignment-tolerant CPUs 2013-04-28 02:57:51 +09:00
Lukáš Krejčí
65006952f3 Changed copyright and e-mail in modified files. 2013-04-27 16:09:15 +02:00
Lukáš Krejčí
4815dbba68 Fixed errors in ChapterFrame constructor.
Fixed errors in ChapterFrame method renderFields.
Fixed errors in TableOfContentsFrame method parseFields.
Added ChapterFrame and TableOfContentsFrame headers and sources to CMakeLists.txt.
Added some basic testing of CHAP and CTOC frames parsing.
2013-04-27 15:42:23 +02:00
Lukáš Krejčí
bcad792e75 Fixed error in childElements function. 2013-04-26 23:16:06 +02:00
Tsuda Kageyu
a80222efa5 Merge pull request #171 from TsudaKageyu/string-test
Add some tests for String
2013-04-26 04:35:57 -07:00
Tsuda Kageyu
5e13e0c838 Add some tests for String 2013-04-26 19:43:10 +09:00
Tsuda Kageyu
58765ac40a Merge pull request #170 from TsudaKageyu/master
Small bug fix in tstring.cpp
2013-04-26 01:52:15 -07:00
Tsuda Kageyu
6e35e56d7f Small bug fix in tstring.cpp 2013-04-26 17:32:39 +09:00
Tsuda Kageyu
a9cdbb7e75 Merge pull request #166 from TsudaKageyu/cmake_test
Refactor out some stuff to CMake tests
2013-04-25 18:54:37 -07:00
Tsuda Kageyu
8c71428d4f Add missing HAVE_WIN_ATOMIC block 2013-04-23 16:25:18 +09:00
Tsuda Kageyu
2c85b4d178 Fix mistaken preprocessor conditionals 2013-04-23 10:42:45 +09:00
Tsuda Kageyu
3293cee11e Skip unnecessary CMake tests 2013-04-23 08:47:48 +09:00
Tsuda Kageyu
27990d0623 Merge pull request #169 from TsudaKageyu/win9x-unicode
Improve Unicode file name handling in Win9x
2013-04-22 10:10:14 -07:00
Tsuda Kageyu
986ee3c44a Improve Unicode file name handling in Win9x 2013-04-23 01:59:02 +09:00
Tsuda Kageyu
dfb3962511 Merge pull request #168 from TsudaKageyu/fix-win9x
Fix a change breaks compatibility with Win9x
2013-04-22 08:28:34 -07:00
Tsuda Kageyu
3e89f7cb40 Fix a change breaks compatibility with Win9x 2013-04-23 00:15:54 +09:00
Tsuda Kageyu
8c233f4552 Merge pull request #167 from TsudaKageyu/filesize
Improve getting file size in Win32
2013-04-21 16:29:26 -07:00
Tsuda Kageyu
c2896fd629 Improve getting file size in Win32 2013-04-22 08:01:25 +09:00
Lukáš Krejčí
fcfd9f59fe Finished parseFields, renderFields and asProperty methods of ChapterFrame and TableOfContentsFrame classes.
Methods setElementID of ChapterFrame and TableOfContentsFrame classes now automatically terminates new element ID with null.
2013-04-21 16:16:57 +02:00
Tsuda kageyu
49b07a2662 Refactor out some stuff to CMake tests 2013-04-21 22:24:12 +09:00
Tsuda Kageyu
529d78f54b Merge pull request #165 from TsudaKageyu/sign-ext
Fix unexpected sign extension
2013-04-21 00:15:02 -07:00
Tsuda kageyu
dc89bdd3f0 Fix unexpected sign extension 2013-04-21 16:06:12 +09:00
Lukáš Krejčí
4be1279430 Added basic members of ChapterFrame and TableOfContentsFrame classes.
Fixed minor bugs in ChapterFrame and TableOfContentsFrame headers.
2013-04-20 16:49:57 +02:00
Lukáš Krejčí
08ae0e8c63 Created CPP and H files for CTOC and CHAP frames. 2013-04-20 15:52:52 +02:00
Tsuda Kageyu
81a9f0474d Merge pull request #161 from TsudaKageyu/fix-syncdata
Fix reading corrupted ID3v2 syncdata
2013-04-19 17:43:16 -07:00
Tsuda kageyu
8a7d1dd796 Fix reading corrupted ID3v2 syncdata 2013-04-20 09:40:01 +09:00
Tsuda Kageyu
457b1abac8 Merge pull request #160 from TsudaKageyu/fix-cast-align
Fix -Wcast-align violation
2013-04-19 14:43:42 -07:00
Tsuda kageyu
e8498b9264 Fix -Wcast-align violation 2013-04-20 05:54:06 +09:00
Tsuda Kageyu
3eeff8b933 Merge pull request #158 from TsudaKageyu/fix-errmsg
Fix an error message in Win32
2013-04-18 14:30:37 -07:00
Tsuda kageyu
d959ab89f1 Fix an error message in Win32 2013-04-19 06:13:27 +09:00
Tsuda Kageyu
b081fb2833 Merge pull request #157 from TsudaKageyu/file-win32
Fix improper file handling in Win32
2013-04-18 06:38:48 -07:00
Tsuda kageyu
e0805b039c Fix improper file handling in Win32 2013-04-18 22:16:59 +09:00
Tsuda Kageyu
c352b5e0c7 Merge pull request #155 from TsudaKageyu/gcc-warnings
Fix some GCC specific warnings
2013-04-18 04:09:30 -07:00
Tsuda kageyu
a71749a6b5 Fix some GCC specific warnings 2013-04-18 19:52:52 +09:00
Tsuda Kageyu
a188778eb8 Merge pull request #154 from TsudaKageyu/tonumber
ByteVector::toUInt() takes offset and length
2013-04-18 03:26:21 -07:00
Tsuda kageyu
439f27640a ByteVector::toUInt() takes offset and length 2013-04-18 18:36:19 +09:00
Tsuda Kageyu
c9209cc99e Merge pull request #150 from TsudaKageyu/detect-codecvt
Detect <codecvt> header automatically
2013-04-17 08:42:14 -07:00
Tsuda kageyu
1370a1cc83 Detect <codecvt> header automatically 2013-04-18 00:32:14 +09:00
Tsuda Kageyu
266e8f5ae4 Merge pull request #149 from TsudaKageyu/fileref-string
Fix improper string handling
2013-04-17 07:55:33 -07:00
Tsuda kageyu
ccaac6c336 Fix improper string handling 2013-04-17 23:47:09 +09:00
Tsuda Kageyu
88005640d5 Merge pull request #148 from TsudaKageyu/reset-smart-pointer
Revert changes concerning the smart pointer
2013-04-17 07:08:36 -07:00
Tsuda kageyu
1f4e06ea7c Revert changes concerning the smart pointer 2013-04-17 22:54:56 +09:00
Tsuda Kageyu
b6c9fb2da1 Merge pull request #147 from TsudaKageyu/shared_ptr
Use shared_ptr if possible regardless of C++11 support
2013-04-17 06:03:28 -07:00
Tsuda kageyu
66f5f396ff Use shared_ptr if possible regardless of C++11 support 2013-04-17 21:41:23 +09:00
Tsuda Kageyu
c9628aae49 Merge pull request #145 from TsudaKageyu/classname
Changed some class names
2013-04-16 20:51:33 -07:00
Tsuda kageyu
bb5d3f0600 Changed some class names 2013-04-17 12:45:14 +09:00
Tsuda Kageyu
1f819ce2c5 Merge pull request #144 from TsudaKageyu/restore-abi2
Restore ABI changed in pull request #60
2013-04-16 20:38:29 -07:00
Tsuda kageyu
593eda7d9d Restore ABI changed in pull request #60 2013-04-17 12:28:00 +09:00
Tsuda Kageyu
14dab7c649 Merge pull request #143 from TsudaKageyu/restore-abi
Restore ABI breaking change
2013-04-16 19:41:55 -07:00
Tsuda kageyu
94a07fa39a Restore ABI breaking change 2013-04-17 11:33:01 +09:00
Tsuda Kageyu
492a0f8199 Merge pull request #142 from TsudaKageyu/shared_ptr
Use std::shared_ptr<T> if C++11 is available
2013-04-16 19:27:42 -07:00
Tsuda kageyu
24736b919a Use std::shared_ptr<T> if C++11 is available 2013-04-17 11:12:42 +09:00
Tsuda Kageyu
38220a57ce Merge pull request #141 from TsudaKageyu/smart-ptr
Replace RefCounter with a smart pointer
2013-04-16 18:38:41 -07:00
Tsuda kageyu
b14dc1572d Replace RefCounter with a smart pointer 2013-04-17 10:10:25 +09:00
Tsuda Kageyu
21964f3cbc Merge pull request #139 from TsudaKageyu/refactor-string
Small refactoring of tstring.cpp
2013-04-16 06:47:28 -07:00
Tsuda kageyu
c13921b7c7 Small refactoring of tstring.cpp 2013-04-16 21:47:12 +09:00
Tsuda Kageyu
39fef2705c Merge pull request #138 from TsudaKageyu/refector-bytevector
Small refactoring of tbytevector.cpp
2013-04-16 05:34:59 -07:00
Tsuda kageyu
8c427c7de9 Small refactoring of tbytevector.cpp 2013-04-16 19:57:04 +09:00
Tsuda Kageyu
0bb995abd0 Merge pull request #137 from TsudaKageyu/refactor-bytevector
Small refactoring of tbytevector.cpp
2013-04-15 22:55:22 -07:00
Tsuda kageyu
0195eef865 Small refactoring of tbytevector.cpp 2013-04-16 14:35:47 +09:00
Tsuda Kageyu
cc3dbd84ce Merge pull request #134 from TsudaKageyu/fix-byteswap
Bug fix for #132
2013-04-15 14:02:17 -07:00
Tsuda kageyu
5e6285afab Bug fix for #132 2013-04-16 05:53:36 +09:00
Tsuda Kageyu
df28a1335a Merge pull request #133 from TsudaKageyu/fix-byteswap
Bug fix for #132
2013-04-15 12:22:37 -07:00
Tsuda kageyu
88a0871784 Bug fix for #132 2013-04-16 04:06:29 +09:00
Tsuda Kageyu
f0edca2f8c Merge pull request #132 from TsudaKageyu/byteswap
Add cross-platform byte order conversions
2013-04-15 08:26:32 -07:00
Tsuda Kageyu
f5462e3e19 Add cross-platform byte order conversions 2013-04-16 00:12:37 +09:00
Lukáš Lalinský
53c5a97b4c Add tests for newline handling in String (#125) 2013-04-15 10:47:43 +02:00
Lukáš Lalinský
a3352fd899 Use the first instance of a MP4 atom (#126)
When a file contains multiple MP4 atoms with the same name, use the first
one. This is consistent with iTunes and other popular software.
2013-04-15 10:13:47 +02:00
Jingmin Wei
4a85e1e1ca Allow the second byte of MPEG header to contain 0xFF
0xFF in the second byte means MPEG Version 1, Layer I, no CRC protection.

http://mpgedit.org/mpgedit/mpeg_format/MP3Format.html
2013-04-15 09:46:08 +02:00
Lukáš Lalinský
94efe5c187 Merge pull request #116 from ufleisch/tagduplication
Parameter to disable duplication between ID3v1 and ID3v2 tags, #115.
2013-04-14 23:47:59 -07:00
Tsuda Kageyu
bef59a0b9a Merge pull request #131 from TsudaKageyu/vc-warning
Fix VC++ specific warnings
2013-04-14 13:29:29 -07:00
Tsuda Kageyu
86142343ee Fix VC++ specific warnings 2013-04-15 05:23:39 +09:00
Tsuda Kageyu
5b2458ed66 Merge pull request #130 from TsudaKageyu/improve-string
Some improvements of String
2013-04-14 13:17:31 -07:00
Tsuda Kageyu
b52cd44c25 Some improvements of String 2013-04-15 05:03:54 +09:00
Tsuda Kageyu
40997e7fc9 Merge pull request #122 from TsudaKageyu/reduce-copy
Reduce unnecessary memory copies by ByteVector
2013-04-06 06:32:26 -07:00
Tsuda Kageyu
a4e68a0304 Reduce unnecessary memory copies by ByteVector 2013-04-05 22:07:58 +09:00
Urs Fleisch
703736fbcb Parameter to disable duplication between ID3v1 and ID3v2 tags, #115. 2013-03-23 13:56:31 +01:00
Tsuda Kageyu
fd45808555 Merge pull request #104 from TsudaKageyu/test-warnings
Fix warnings in test_flacpicture.cpp
2013-03-19 06:03:23 -07:00
Tsuda Kageyu
e9fec47411 Fix warnings in test_flacpicture.cpp 2013-03-19 21:54:56 +09:00
Stephen F. Booth
6029352c09 Merge pull request #96 from nightingale-media-player/master
Make textual lyric frames use UTF8
2013-01-20 07:56:30 -08:00
rsjtdrjgfuzkfg
077208d17a Create UTF8-Lyrics per default. 2013-01-18 17:21:35 +01:00
Michael Helmling
08863dec0b Found and fixed more missing property interface forwarders.
Probably due to a copy-and-paste error the implementation of
File::removeUnsupportedProperties() contained cases for several type
which do not reimplement this method; for others the implementation was
missing and is now included.

In addition, the formats Speex and Opus suffered from the same bug as
OggFLAC in the commit before, which is now fixed.
2013-01-03 23:20:15 +01:00
Michael Helmling
80af92a715 Add forwarders for the property interface to Ogg::FLAC::File.
Fixes an infinite method resolution recursion in File::properties() and
File::setProperties(). Thanks to Sebastian Rachuj for pointing out this bug.
2013-01-03 23:00:17 +01:00
Lukáš Lalinský
237e0ec23c Merge pull request #93 from magcius/master
c: Add support for TAGLIB_STATIC to the C bindings
2013-01-01 03:00:27 -08:00
Jasper St. Pierre
d52e97dfcd c: Add support for TAGLIB_STATIC to the C bindings
Otherwise, we'll fail with dllimport/dllexport linking errors on
Windows.
2013-01-01 04:28:00 -05:00
Michael Helmling
8329d6ac1a Update documentation of the property map interface in TagLib::File. 2012-12-27 11:38:01 +01:00
Michael Helmling
f1d723077f Consistently handle invalid and deprecated tags in setProperties()
This commit reverts the use of strip() in setProperties() because the
latter function should not change the file before save() is called.
Instead, the following policy is now consistently applied for file formats
with multiple tag types:
- the recommended tag type is created, if it does not exist
- deprecated tags are updated, if they exist, but not created
- illegal tag types are ignored by setProperties(), but used in properties()
  if no others exist.

The only tag types considered "illegal" so far are APEv2 in MPEG and ID3 in FLAC.
2012-12-26 22:46:37 +01:00
Michael Helmling
a095c468b2 Revert "Add a test to show a problem with properties() and duplication."
This reverts commit 6e3391a846. The "problem" demonstrated in there won't be fixed due to lack of significance.
2012-12-20 17:30:19 +01:00
Michael Helmling
b14e6a3570 Update for pull request #89: Change how setProperties() updates tags.
For file types supporting more than one tag format, setProperties() now always creates the most modern one. Deprecated tags are stripped.
2012-12-20 17:28:50 +01:00
Michael Helmling
6e3391a846 Add a test to show a problem with properties() and duplication. 2012-12-10 21:22:11 +01:00
Michael Helmling
c0ca5c97d5 Fix issue #88 by changing the behavior of setProperties().
For file types that support multiple tag standards (for example, FLAC
files can have ID3v1, ID3v2, and Vorbis comments) setProperties is now
called for all existing tags instead of only for the most recommended
one.
This fixes the problem that under some circumstances it was not possible
to delete a value using setProperties() because upon save() the call to
Tag::duplicate recovered that value from the ID3v1 tag.
2012-12-10 20:56:16 +01:00
Michael Helmling
d5cf6d72e2 Merge remote-tracking branch 'official/master' 2012-12-10 19:55:29 +01:00
Michael Helmling
9eb0f2941f Add a test case for the return value of setProperties() 2012-12-10 19:55:23 +01:00
naota
3fa295d99d Include sys/stat.h to define S_* properly
Without including sys/stat.h, this file failed to build on FreeBSD with the following error.

In file included from /var/tmp/portage/media-libs/taglib-1.8/work/taglib-1.8/tests/test_trueaudio.cpp:5:0:
/var/tmp/portage/media-libs/taglib-1.8/work/taglib-1.8/tests/utils.h: In function 'std::string copyFile(const string&, const string&)':
/var/tmp/portage/media-libs/taglib-1.8/work/taglib-1.8/tests/utils.h:36:62: error: 'S_IRUSR' was not declared in this scope
/var/tmp/portage/media-libs/taglib-1.8/work/taglib-1.8/tests/utils.h:36:72: error: 'S_IWUSR' was not declared in this scope
In file included from /var/tmp/portage/media-libs/taglib-1.8/work/taglib-1.8/tests/test_mpeg.cpp:6:0:
/var/tmp/portage/media-libs/taglib-1.8/work/taglib-1.8/tests/utils.h: In function 'std::string copyFile(const string&, const string&)':
/var/tmp/portage/media-libs/taglib-1.8/work/taglib-1.8/tests/utils.h:36:62: error: 'S_IRUSR' was not declared in this scope
/var/tmp/portage/media-libs/taglib-1.8/work/taglib-1.8/tests/utils.h:36:72: error: 'S_IWUSR' was not declared in this scope
gmake[2]: *** [tests/CMakeFiles/test_runner.dir/test_mpeg.cpp.o] Error 1
2012-11-28 07:54:08 +09:00
Lukáš Lalinský
812f63502b Implement the PropertyMap interface for WMA 2012-11-23 09:32:00 +01:00
Lukáš Lalinský
353eb9f00f Implement the PropertyMap interface for MP4 2012-11-22 10:40:22 +01:00
Lukáš Lalinský
1b813d9d6c Document sort names 2012-11-21 17:26:17 +01:00
Lukáš Lalinský
c5dade5ee7 Use names that are consistent with Vorbis Comments 2012-11-21 17:24:32 +01:00
Lukáš Lalinský
e75d6f616c Add support for reading MusicBrainz IDs from ID3v2 tags to PropertyMap 2012-11-21 17:21:30 +01:00
Lukáš Lalinský
15b601f053 Use PropertyMap in tagreader 2012-11-21 14:40:26 +01:00
Lukáš Lalinský
45317ef7f2 Revert "Fix opening of read-only files on Windows"
This reverts commit ade8dc1a21.
2012-11-20 18:34:51 +01:00
Lukáš Lalinský
3da792152a Merge pull request #85 from TsudaKageyu/fix-readonly
Fix reading read-only files in Win32
2012-11-20 09:23:16 -08:00
Tsuda Kageyu
3f6da779d2 Fix compilation in non-Win32 2012-11-20 22:46:03 +09:00
Tsuda Kageyu
57b8ae6e1c Fix reading read-only files in Win32 2012-11-20 22:20:34 +09:00
Lukáš Lalinský
ade8dc1a21 Fix opening of read-only files on Windows
The CreateFile* functions return INVALID_HANDLE_VALUE on error, not NULL.

http://article.gmane.org/gmane.comp.kde.devel.taglib/2346
2012-11-20 14:15:16 +01:00
Lukáš Lalinský
c6f7ad3e83 Revert "Add a tool to inspect audio files, only MP4 is implemented for now"
This reverts commit 45b0279b41.
2012-11-12 16:14:32 +01:00
Lukáš Lalinský
dbe6be778b Build also examples 2012-11-11 16:44:01 +01:00
Lukáš Lalinský
45b0279b41 Add a tool to inspect audio files, only MP4 is implemented for now 2012-11-11 16:43:36 +01:00
Lukáš Lalinský
3a5aeb4573 Parse covr atoms with type 0 (fixes issue #84) 2012-11-11 16:04:08 +01:00
Lukáš Lalinský
72745846f4 Update NEWS 2012-11-11 14:49:31 +01:00
Lukáš Lalinský
9e788bb8c2 Fix tests when compiled with clang on Linux 2012-11-11 14:26:10 +01:00
Lukáš Lalinský
56fbe7e14d Make travis run tests also with clang 2012-11-10 20:51:17 +01:00
Lukáš Lalinský
44155f6771 Merge pull request #79 from gonemad/master
Check if file is open before reading tags
2012-11-04 01:27:43 -07:00
Lukáš Lalinský
341711c04b Merge pull request #83 from jmarshallnz/more_itunes_hacks
A small fix, and some additional iTunes hacks (v2.2 frames in v2.3 tag)
2012-11-04 01:26:26 -07:00
Jonathan Marshall
be6187e893 adds new iTunes hack for v2.2 frames stored in a v2.3 tag (iTunes v8.1.1.10 for example) 2012-11-04 19:54:28 +13:00
Jonathan Marshall
c42bdeab43 fixes noop frame id size check in ID3v2::FrameFactory::createFrame 2012-11-04 19:52:10 +13:00
gonemad
7d7c58cb8e Merge branch 'master' of https://github.com/taglib/taglib 2012-10-18 20:17:35 -04:00
Lukáš Lalinský
044da877e6 Make sure we build the tests 2012-10-13 13:38:35 +02:00
Lukáš Lalinský
2d7686b5fa Actually run the tests 2012-10-13 13:36:33 +02:00
Lukáš Lalinský
074f6db6d8 Needs sudo 2012-10-13 13:34:44 +02:00
Lukáš Lalinský
7a884af0ef Experimenting with Travis CI 2012-10-13 13:33:36 +02:00
Lukáš Lalinský
e568e1019d Remove useless debug print 2012-10-13 09:11:20 +02:00
Lukáš Lalinský
ca543039a5 Include Opus in docs 2012-10-13 09:06:09 +02:00
Lukáš Lalinský
5e7b1da632 Add support for Ogg Opus 2012-10-13 08:55:23 +02:00
gonemad
6b9ef6421f Fixed indents 2012-10-11 22:10:19 -04:00
gonemad
d15c8453ac Added check if file is open before attempting to read tags 2012-10-11 21:20:03 -04:00
Lukáš Lalinský
1e660dda71 Partial changelog for 1.9 2012-10-10 17:09:03 +02:00
Lukáš Lalinský
2a77afc593 Merge remote-tracking branch 'nightingale/master' 2012-10-10 16:45:36 +02:00
Tsuda Kageyu
a9df3e48f7 Fix a bug in updating MP4 tags 2012-10-10 21:17:05 +09:00
rsjtdrjgfuzkfg
c8994ede3f Restrict url frame generation to W??? Frames to prevent known non-text non-url frameIDs to be handled as url when containing only one String. No longer describe the default comment as "COMMENT". 2012-10-08 20:19:12 +02:00
Lukáš Lalinský
7e255733e0 Merge remote-tracking branch 'TsudaKageyu/id3v1-genrenumber' 2012-10-08 13:23:17 +02:00
Julien Ramseier
72f9a96cce Fix missing CppUnit include directive 2012-10-07 15:41:40 +02:00
Stephen F. Booth
1308ff6479 Merge pull request #73 from ArnaudBienner/master
Corrupted FLAC files scan can result in heavy CPU consumption: fix
2012-10-07 05:29:02 -07:00
Arnaud Bienner
b7a15092d8 Faster FLAC::FilePrivate destructor 2012-10-07 03:07:53 +02:00
Arnaud Bienner
ad9ffc62e6 Consider FLAC file as being invalid if a 0 length block is found 2012-10-07 03:04:02 +02:00
Tsuda Kageyu
46e613dcca Add reading/writing ID3v1 genre in number 2012-10-04 19:23:10 +09:00
Urs Fleisch
2d7414733e Crash when saving xm files (fixes #68) 2012-09-30 15:42:16 +02:00
Lukáš Lalinský
9f597bab1b Change some variables to follow the TagLib naming convention 2012-09-30 10:50:19 +02:00
Lukáš Lalinský
321b9b5a8b Merge remote-tracking branch 'TsudaKageyu/filestream' 2012-09-30 10:43:58 +02:00
Lukáš Lalinský
60a3a4e455 Various uint fixes
We really need to get rid of TagLib::uint...
2012-09-30 10:22:10 +02:00
Lukáš Lalinský
57e5cc8c17 Merge remote-tracking branch 'TsudaKageyu/infotag-patch' 2012-09-30 10:15:56 +02:00
Lukáš Lalinský
5250673fa0 Merge pull request #70 from FestusHagen/taglib-config_cmd
Win32 taglib-config.cmd support.
2012-09-30 01:06:49 -07:00
Lukáš Lalinský
ab5e19a016 Merge pull request #69 from FestusHagen/SW_MinGW
Silence warnings with MinGW 4.6.3.
2012-09-29 06:54:36 -07:00
Festus Hagen
8790e9de01 Silence warnings with MinGW 4.6.3. 2012-09-29 09:01:44 -04:00
Festus Hagen
1086d4476d Win32 taglib-config.cmd support. 2012-09-28 21:41:45 -04:00
Lukáš Lalinský
7b80418122 Fix the version number 2012-09-26 20:30:53 +02:00
Stephen F. Booth
02d034f53f Merge pull request #65 from TsudaKageyu/tagsondisk
Add MPEG::FILE::Has*Tag functions
2012-09-08 05:14:30 -07:00
Tsuda Kageyu
e7126db97c Add MPEG::FILE::Has*Tag functions 2012-09-08 14:13:20 +09:00
Tsuda Kageyu
4582ea3b27 Fixed CMakeLists.txt 2012-09-08 01:17:15 +09:00
Tsuda Kageyu
43e100fd37 FileStream improvement in Win32 2012-09-07 23:48:06 +09:00
Tsuda Kageyu
071a1477b5 Fixed an API change 2012-09-07 08:16:30 +09:00
Tsuda Kageyu
61c8013f2c Added missing comments 2012-09-07 08:16:28 +09:00
Tsuda Kageyu
9c8c215c30 Support INFO tags of RIFF wave files. 2012-09-07 08:16:26 +09:00
Lukáš Lalinský
aa34afda79 Merge remote-tracking branch 'TsudaKageyu/substr-bug' 2012-09-06 20:03:15 +02:00
Lukáš Lalinský
942ec58de5 Add tests for String::substr 2012-09-06 20:03:08 +02:00
Lukáš Lalinský
082a36147b Add change log, update SOVERSION 2012-09-06 19:57:10 +02:00
Lukáš Lalinský
f11b206fe8 Do not delete the IOStream object in TagLib::File 2012-09-06 19:43:52 +02:00
Lukáš Lalinský
e37f6ed752 Update CMakeLists.txt 2012-09-06 19:30:45 +02:00
Lukáš Lalinský
d2f20e8d2a Merge branch 'master' of https://github.com/moeeka/taglib 2012-09-06 19:24:22 +02:00
Rupert Daniel
f194a55c0f Updated OWNE implementaion with minor changes after pull review 2012-09-06 12:11:20 +01:00
Rupert Daniel
719187794e Implementation of the ID3v2.4 OWNE frame. 2012-09-05 16:37:46 +01:00
Tsuda Kageyu
74b94613a0 Bug fix in String::substr() 2012-09-05 19:46:52 +09:00
Lukáš Lalinský
33d0be110b Fix ambiguous reference to uint in tests 2012-09-03 19:55:55 +02:00
Tsuda Kageyu
df12b4ffc6 Refectored the FileStream constructor. 2012-09-03 01:45:28 +09:00
Tsuda Kageyu
d16c24ae21 Merge branch 'master' of https://github.com/taglib/taglib into security-warnings 2012-09-02 23:40:11 +09:00
Lukáš Lalinský
1c35918834 Merge remote-tracking branch 'TsudaKageyu/warnings' 2012-09-02 15:25:41 +02:00
Tsuda Kageyu
d163f36d35 Fix Visual C++ specific warnings about security 2012-08-23 21:57:12 +09:00
Tsuda Kageyu
590cd4c9f6 Fix warnings with VS2010 2012-08-23 20:54:18 +09:00
Tsuda Kageyu
6c0227ee13 Fix compilation errors with Visual Studio 2010 2012-08-23 19:58:21 +09:00
Lukáš Lalinský
9bb57fe0a7 Merge remote-tracking branch 'TsudaKageyu/id3v2-comment-update' 2012-08-23 11:00:32 +02:00
tsuda.kageyu@gmail.com
3fecdbf428 Comment update for ID3v2::Tag::setLatin1StringHandler() 2012-08-23 17:57:00 +09:00
Lukáš Lalinský
356c7a5d6e Merge remote-tracking branch 'TsudaKageyu/cross-border-delete' 2012-08-23 10:51:47 +02:00
tsuda.kageyu@gmail.com
4b4f70253b Comment update for ID3v1::Tag::setStringHandler() 2012-08-23 17:45:25 +09:00
Lukáš Lalinský
8b61a06fda Merge remote-tracking branch 'TsudaKageyu/id3v2-brokenlatin1-patch' 2012-08-23 10:22:43 +02:00
Lukáš Lalinský
6801ac2515 Merge remote-tracking branch 'poiru/master' 2012-08-23 10:19:08 +02:00
Lukáš Lalinský
29d17bb8e9 Merge remote-tracking branch 'supermihi/master' 2012-08-23 10:17:05 +02:00
tsuda.kageyu@gmail.com
fe8053c7d5 Support broken Latin-1 encodings in ID3V2 2012-08-23 12:19:51 +09:00
tsuda.kageyu@gmail.com
eb63ee8ec6 Remove possible cross binary boundary delete 2012-08-23 11:09:22 +09:00
Lukáš Lalinský
e86e5f906b ID3 frame IDs with 0 should be recognized as valid
http://article.gmane.org/gmane.comp.kde.devel.taglib/2275
2012-08-17 07:50:48 +02:00
Lukáš Lalinský
60e82e6694 Ignore additional files 2012-08-17 07:34:44 +02:00
Birunthan Mohanathas
fc6e02da35 Update header comments to reflect c4163a2 2012-08-02 17:25:20 +03:00
Michael Helmling
4140c5f2eb Check PropertyMap keys format-specifically instead of globally.
Instead of statically forbidding certain keys in PropertyMap, now the
setProperties() implementations of the different formats check if the
keys are valid for that particular specification and include them in
the returned PropertyMap otherwise.
This should remove an unneccessary complification for programmers since
now there's only one step, namely calling setProperties(), where
problems might occur.
Also the previous implementation leads to problems with invalid keys:
because taglib doesn't use exceptions, something like

  map.insert("FORBIDDEN KEY", "some value");

would lead to the value being inserted under String::null, which
smells like the source of strange bugs.
2012-07-30 20:52:30 +02:00
Michael Helmling
fc3fc10f60 add id3v2 frame delete test 2012-07-23 20:53:25 +02:00
BSDKaffee
3bc123aed6 - Disambiguate uint and ushort references 2012-07-15 01:57:53 -04:00
Lukáš Lalinský
3b392f2402 Changelog for 1.8 beta 2012-07-14 21:53:09 +02:00
Lukáš Lalinský
8ff0feb28e Cast to long 2012-07-14 21:21:03 +02:00
Lukáš Lalinský
61ed295af8 Merge remote-tracking branch 'poiru/master' 2012-07-14 21:09:54 +02:00
Lukáš Lalinský
09af2a7b57 Merge remote-tracking branch 'robinst/mpeg-file-id3vxtag-docs-inexistent-tags' 2012-07-14 21:08:59 +02:00
Lukáš Lalinský
050ff3835d Revert "Install examples if built."
This reverts commit 52e96e48c5.
2012-07-14 21:06:53 +02:00
Lukáš Lalinský
674ae0fa6d Merge remote-tracking branch 'kensington/master' 2012-07-14 21:06:08 +02:00
Lukáš Lalinský
411d318f34 Merge remote-tracking branch 'robinst/dont-copy-from-id3v1-when-only-saving-id3v2' 2012-07-14 21:03:16 +02:00
Lukáš Lalinský
fbb1c7e554 Merge branch 'mpc_sv8' 2012-07-11 14:15:37 +02:00
Lukáš Lalinský
fd818857e0 More Musepack tests 2012-07-11 14:15:12 +02:00
Lukáš Lalinský
930168f990 Refactoring of the Musepack SV8 properties code 2012-07-11 14:13:41 +02:00
Alex Novichkov
291d925fc1 MPC v8 audio properties 2012-07-11 13:08:10 +02:00
Scott Wheeler
7c4c455a40 Use '0' here instead of 'NULL'
0 is used throughout the rest of the TagLib source, and generally
preferred in C++:

http://www2.research.att.com/~bs/bs_faq2.html#null
2012-07-03 12:26:20 +02:00
Stephen F. Booth
f429d6f406 Merge pull request #41 from EliaCereda/master
Properly initialize frame
2012-06-30 07:33:25 -07:00
Elia Cereda
c68fe9ad7b Fixed error "Branch condition evaluates to a garbage value" (from Xcode 4.3.3 Static Analyzer, mpeg/id3v2/id3v2tag.cpp:377)
This error occurs when the frame variable is left uninitialized because its id doesn't match any of the ids in the if and else-id cases. Initializing it on declaration fixes this issue.
2012-06-30 16:25:33 +02:00
Stephen F. Booth
81aac3a590 Merge pull request #39 from robinst/install-build-tests-option
Mention -DBUILD_TESTS=on in "Unit Tests" of INSTALL
2012-06-11 04:57:04 -07:00
Robin Stocker
7279b4fb7b Don't duplicate from ID3v1 to ID3v2 when saving only ID3v2
When saving only v2 with stripOthers (which means stripping v1), the
data from v1 would still be duplicated to v2. Likewise for the other way
around.

This is not the expected outcome when e.g. a frame was removed in v2,
because it would be added again on save from the v1 data. The test shows
that.

This changes save to only duplicate the data when the other tag type
will not be stripped.
2012-06-10 18:53:25 +02:00
Robin Stocker
b0ac79c60e Mention -DBUILD_TESTS=on in "Unit Tests" of INSTALL 2012-06-10 18:26:06 +02:00
Robin Stocker
382aec46f7 Fix docs of MPEG::File::ID3v(1|2)Tag for inexistent tag
Since 37e2d629, the ID3v1 and ID3v2 tags are always created at the end
of MPEG::File::read. So contrary to what the documentation said, a null
pointer is never returned.

To check if a tag contains data, refer to isEmpty() in the
documentation.
2012-06-10 15:27:54 +02:00
Michael Palimaka
b5ad68d64b Add custom 'check' target that depends on the test_runner target for backwards compatibility. 2012-05-17 03:42:36 +10:00
Michael Palimaka
52e96e48c5 Install examples if built. 2012-05-16 04:37:25 +10:00
Michael Palimaka
5bcfecb6cc Use ctest instead of custom target. 2012-05-16 04:00:22 +10:00
Lukáš Lalinský
2c2a486313 Merge branch 'stable'
Conflicts:
	CMakeLists.txt
	NEWS
2012-04-20 18:30:07 +02:00
Lukáš Lalinský
059f2243b3 Prepare 1.7.2 release 2012-04-20 17:57:13 +02:00
Lukáš Lalinský
cce6ad46c9 Reverse the version check, similarly to what mp4v2 does 2012-04-20 17:52:12 +02:00
Birunthan Mohanathas
06597123b8 Remove trailing whitespace 2012-04-19 13:09:45 +03:00
Birunthan Mohanathas
e5ede410bc Tabs to spaces 2012-04-19 13:04:42 +03:00
Vinnie Falco
dafb3af742 Remove 'using namespace std' in tmap.h 2012-04-17 22:05:09 -07:00
Lukáš Lalinský
089643f115 Merge remote-tracking branch 'vinniefalco/rename_enums' 2012-04-17 08:49:02 +02:00
Vinnie Falco
26f458b87f Resolve scope resolution for APE::Footer definitions in apefooter.cpp 2012-04-15 07:58:50 -07:00
Vinnie Falco
c22791318c Resolve ambiguous File symbol in apetag.cpp 2012-04-15 07:57:02 -07:00
Vinnie Falco
5081e3cf4f Rename anonymous enumeration symbols to be unique trueaudiofile.cpp 2012-04-15 02:41:27 -07:00
Vinnie Falco
1bde4cea09 Rename anonymous enumeration symbols to be unique in wavpackfile.cpp 2012-04-15 02:40:46 -07:00
Vinnie Falco
0907e86a94 Rename anonymous enumeration symbols to be unique in apefile.cpp 2012-04-15 02:40:23 -07:00
Vinnie Falco
742a3a1dbb Rename anonymous enumeration symbols to be unique in mpcfile.cpp 2012-04-15 02:39:19 -07:00
Vinnie Falco
04a4a6b8d4 Rename anonymous enumeration symbols to be unique in flacfile.cpp 2012-04-15 02:38:15 -07:00
Jeff Mitchell
b216b448c5 Fix compilation 2012-04-12 18:41:40 -04:00
Stephen F. Booth
4f8a6fdfaf Verify that an APE text item isn't empty before use 2012-04-12 10:53:32 -04:00
Stephen F. Booth
32a4ac6599 Preserve source code backward compatibility 2012-04-10 18:06:58 -04:00
Stephen F. Booth
ca26a9ad3e Added support for APE tag binary items 2012-04-10 07:24:12 -04:00
Stephen F. Booth
bd03e352cc Allow tag items to be replaced 2012-04-07 08:54:22 -04:00
Stephen F. Booth
69ac59f5f0 Added sampleFrames() to audio properties 2012-04-06 18:30:13 -04:00
Stephen F. Booth
2297a6d531 Added missing tmap.h 2012-04-06 18:29:56 -04:00
Lukáš Lalinský
2a4850f211 Merge branch 'stable'
Conflicts:
	CMakeLists.txt
2012-03-18 09:22:53 +01:00
scottmc
288c6e4a3f Include <iostream> instead of <ostream> to fix compilation on Haiku 2012-03-18 09:20:26 +01:00
Lukáš Lalinský
606edf8171 Increment the version number 2012-03-17 11:02:24 +01:00
Lukáš Lalinský
3c7b05a900 Merge branch 'stable'
Conflicts:
	NEWS
2012-03-17 10:59:34 +01:00
Lukáš Lalinský
009c43952f Changelog 2012-03-17 10:58:22 +01:00
Birunthan Mohnathas
9c1668f28b Fixed (huge) memory leak with ASF. 2012-03-17 10:48:57 +01:00
Lukáš Lalinský
8e67b40bdc Fix compilation errors 2012-03-17 10:45:52 +01:00
Lukáš Lalinský
76222cb1eb Merge branch 'master' of https://github.com/supermihi/taglib 2012-03-17 10:41:02 +01:00
Birunthan Mohnathas
138dfca682 Additional change to previous fix. 2012-03-12 22:13:58 +02:00
Birunthan Mohnathas
c4163a26e8 Fixed memory leak of FrameFactory singleton. 2012-03-12 18:56:08 +02:00
Birunthan Mohnathas
4496efe33b Fixed (huge) memory leak with ASF. 2012-03-12 18:44:08 +02:00
Lukáš Lalinský
3a760b060c Merge branch 'stable'
Conflicts:
	taglib/riff/aiff/aiffproperties.cpp
	taglib/trueaudio/trueaudioproperties.cpp
	tests/test_wav.cpp
2012-03-10 09:16:37 +01:00
Lukáš Lalinský
110cac8429 Avoid uint overflow in case the length + index is over UINT_MAX 2012-03-10 09:13:04 +01:00
Lukáš Lalinský
258ae751b5 Don't store the output of ByteVector::toUInt() in int, use uint instead 2012-03-10 09:12:32 +01:00
Lukáš Lalinský
df1d3e028e Make sure to not try dividing by zero 2012-03-10 09:12:19 +01:00
Stephen F. Booth
23c86cf27d Check if the header is TTA1 before parsing 2012-03-10 09:11:51 +01:00
Lukáš Lalinský
f59c3b67aa Detect RIFF files with invalid chunk sizes
The bug report has a WAVE file with zero-sized 'data' chunk, which causes
TagLib to iterate over the file, 8 bytes in each iteration. The new code
adds a check for the chunk name, which forces it to mark the file as
invalid if the chunk name doesn't contain ASCII characters.

https://bugs.kde.org/show_bug.cgi?id=283412
2012-03-10 09:06:55 +01:00
Stephen F. Booth
294cb22241 Don't crash when wav files have a 0 for bit per channel (sampleWidth)
I've seen this in a wav that has an audio format of MP3 (0x55)
2012-03-10 08:58:45 +01:00
Frank Lai
b7ec0d26ab Be more careful when parsing Vorbis Comments 2012-03-10 08:52:59 +01:00
Scott Wheeler
934ce51790 Don't lead the scanned blocks on save 2012-03-10 08:52:17 +01:00
Lukáš Lalinský
dcdf4fd954 Avoid uint overflow in case the length + index is over UINT_MAX 2012-03-10 08:46:20 +01:00
Lukáš Lalinský
ab8a0ee893 Don't store the output of ByteVector::toUInt() in int, use uint instead 2012-03-04 12:01:21 +01:00
Lukáš Lalinský
77d61c6eca Make sure to not try dividing by zero 2012-03-04 11:51:05 +01:00
Michael Helmling
f5a2518273 Fixed handling of UnknownFrames in ID3v2.
- If an unknown frame with id "XXXX" occurs, an entry
"UNKNOWN/XXXX" is added to unsupportedData().
The removeUnsupportedProperties() method in turn
removes all unknown frames with id "XXXX" if it
encounters a string "UNKNOWN/XXXX" in the given list.

- Implemented findByDescription() to UnsynchronizedLyricsFrame
in order to support removal of lyrics frames with unsupported
keys.

- Adapted id3v2 test case to new QuodLibet policy.
2012-02-26 19:21:57 +01:00
Michael Helmling
6e6d823992 Removed quodlibet special case handling 2012-02-26 18:38:03 +01:00
Michael Helmling
f859fcf82a Add support for Unknown TXXX frames. 2012-02-26 18:07:02 +01:00
Michael Helmling
37c87e0317 Fixed identation 2012-02-26 10:56:18 +01:00
Michael Helmling
0a3b998ca5 Fix USLT frame creation in Frame::createTextualFrame() 2012-02-26 10:43:08 +01:00
Michael Helmling
fa0656e3c6 remove Tests/Examples build from CMakeLists 2012-02-26 10:37:59 +01:00
Michael Helmling
b05c3161c7 Added ID3v2 PropertyMap interface documentation. 2012-02-25 19:11:31 +01:00
Michael Helmling
79670beca1 some cosmetic changes 2012-02-25 18:59:53 +01:00
Michael Helmling
9fd22023cd Merge remote-tracking branch 'official/master' 2012-02-25 18:51:30 +01:00
Michael Helmling
b8d5246f88 Moved APE test to correct place; added MOD tag test. 2012-02-25 18:46:19 +01:00
Michael Helmling
05b5e06928 added APE tag PropertyMap test 2012-02-25 18:32:00 +01:00
Michael Helmling
d28cc83fb4 Added another test for ID3v2 PropertyMap interface; fixed various bugs 2012-02-25 18:22:17 +01:00
Michael Helmling
495a028da3 removed debug messages 2012-02-19 15:15:25 +01:00
Michael Helmling
23d303a896 fixed bugs preventing tests from running 2012-02-19 15:13:31 +01:00
Michael Helmling
6c054af3ed Added some functions, started to fix bugs. 2012-02-19 12:15:28 +01:00
Michael Helmling
70c3264279 fixed tests 2012-02-15 22:09:28 +01:00
Michael Helmling
cfa5ac6569 Fixed id3v2 test 2012-02-15 21:56:02 +01:00
Michael Helmling
de51307de7 Added lots of missing includes 2012-02-15 21:54:19 +01:00
Michael Helmling
140f4a57e2 fixed lots of bugs found by 'make' 2012-02-14 22:11:30 +01:00
Michael Helmling
8a8e9b702c Ported xm. 2012-02-14 21:35:50 +01:00
Michael Helmling
d6215365a1 Ported wavpack. 2012-02-14 21:34:43 +01:00
Michael Helmling
2185d52f56 Ported trueaudio. 2012-02-14 21:32:36 +01:00
Michael Helmling
48aaaf8dc4 Ported s3m; removed old id3v2dicttools. 2012-02-14 21:29:30 +01:00
Michael Helmling
d2c43d7174 ID3 interface complete; vorbis done; wav done 2012-02-14 21:27:14 +01:00
Lukáš Lalinský
cdfb447042 Add explicitly declared default constructor to StringHandler 2012-02-04 21:22:52 +01:00
Lukáš Lalinský
2d00b690de Merge branch 'master' of https://github.com/poiru/taglib 2012-02-04 20:38:14 +01:00
Stephen F. Booth
51675f3399 Added sampleFrames to FLACProperties 2012-02-04 11:34:40 -05:00
Stephen F. Booth
fa662a23db Check if the header is TTA1 before parsing 2012-02-04 08:39:45 -05:00
Stephen F. Booth
dc628204c0 Added sampleFrames() for TTA files 2012-02-04 08:30:34 -05:00
Birunthan Mohanathas
9564956a7f Removed space. 2012-02-02 18:12:37 +02:00
Birunthan Mohnathas
1f2248d24b Additional change to previous fix. 2012-02-02 17:50:58 +02:00
Birunthan Mohnathas
06424598bb Fixed memory leak. 2012-02-02 15:03:41 +02:00
Stephen F. Booth
7b3f279294 Correctly handle non-integral bit depths 2012-01-30 22:31:15 -05:00
Michael Helmling
a8632f710f More progress in ID3 ... setProperties() will get messy :( 2012-01-22 22:06:24 +01:00
Michael Helmling
0c8e5bbec8 Implemented asProperties() in all relevant textual frames. 2012-01-22 17:08:02 +01:00
Michael Helmling
a5e45f196b Started to work on ID3v2. 2012-01-21 23:05:59 +01:00
Michael Helmling
e4d955d6ef Migration to new PropertyMap ... done ape to mod. 2012-01-21 14:52:24 +01:00
Michael Helmling
18ae797df4 Add unsupportedData() to PropertyMap, simplified [] behavior. 2012-01-17 18:09:30 +01:00
Michael Helmling
d11189b975 Basic implementation of a PropertyMap.
Implemented key/valuelist property map with
case-insensitive ASCII keys and StringList values.

Todo:
- subclass StringList to add flags indicating whether a value could
be written to the specific file format
- add member attribute indicating list of frames that could not be
parsed into the PropertyMap representation.
2012-01-16 22:37:30 +01:00
Michael Helmling
67d896e6a7 Implemented the most easy comments on the pull request. 2012-01-14 22:02:17 +01:00
Michael Helmling
ea41cd8903 Merge remote-tracking branch 'official/master' 2012-01-14 20:57:15 +01:00
Lukáš Lalinský
d904281c6b Make it possible to generate an XML report 2012-01-14 10:16:54 +01:00
Lukáš Lalinský
40bf52e70f Reverse the version check, similarly to what mp4v2 does 2012-01-10 17:18:20 +01:00
Lukáš Lalinský
b981b6dde7 Check also for the deprecated GIF type 2012-01-08 15:54:15 +01:00
Lukáš Lalinský
c237998983 Support non-UTF8 free-form atoms 2012-01-08 13:17:42 +01:00
Urs Fleisch
5ff810e98d Support for ID3v2.2 frames used by iTunes (TCP, TS2, TSA, TSC, TSP, TST)
https://bugs.kde.org/show_bug.cgi?id=290330
2012-01-05 16:33:29 +01:00
Michael Helmling
7875d02a8f Merge remote-tracking branch 'official/master' 2012-01-04 19:49:50 +01:00
Scott Wheeler
baafb3e290 Funny that there managed to be no operator!= for String for so long. 2012-01-01 16:01:18 +01:00
Michael Helmling
c4cef55158 Added tests and information about ignored id3 frames.
The ID3v2::toDict() function now has an optional
StringList* argument which will contain information
about frames that could not be converted to the dict
interface.
There are some dict tests for APE and FLAC now, and the
ID3v2 test was enlarged.
2012-01-01 14:42:48 +01:00
Michael Helmling
0eaf3a3fbd Implemented dict interface for more formats.
Now supported: MOD files (IT, MOD, S3M, XM), RIFF files
(AIFF, WAV), TrueAudio, WavPack.
2011-11-02 21:02:35 +01:00
Michael Helmling
292a377d1e Merge remote-tracking branch 'official/master' 2011-10-30 18:28:52 +01:00
Lukáš Lalinský
6ea8599313 Detect RIFF files with invalid chunk sizes
The bug report has a WAVE file with zero-sized 'data' chunk, which causes
TagLib to iterate over the file, 8 bytes in each iteration. The new code
adds a check for the chunk name, which forces it to mark the file as
invalid if the chunk name doesn't contain ASCII characters.

https://bugs.kde.org/show_bug.cgi?id=283412
2011-10-08 18:41:15 +02:00
Michael Helmling
772bc9f7c4 Further cleanup and simplification in id3v2dicttools 2011-09-12 21:52:11 +02:00
Michael Helmling
0c2ca20ec2 Restructured and simplified ID3v2Tag::fromDict(). 2011-09-11 22:07:49 +02:00
Michael Helmling
2d31075047 Splitted ID3v2Tag::toDict() into several functions.
This should simplify future transition to virtual functions.
2011-09-11 18:22:15 +02:00
Graham Perks
837c9ef288 Add cmake option for visibility=hidden 2011-09-09 10:17:54 -05:00
Michael Helmling
0356249368 Merge remote-tracking branch 'official/master' 2011-09-01 16:33:39 +02:00
Michael Helmling
5647b2e293 Made im/export functions nonvirtual. Added similar functions to File and
its subclasses. TagLib::File contains a bunch of dynamic_casts to call
the correct specializations.
2011-08-28 22:58:40 +02:00
Lukáš Lalinský
686bcf55a9 Add support for iPhone ringtones 2011-08-28 11:02:34 +02:00
Michael Helmling
fa8159a9d0 Added toDict and fromDict methods for APE tags. 2011-08-27 22:30:20 +02:00
Michael Helmling
58db919e43 More support for the unified dictionary interface.
Addded fromDict() function to ID3v2Tag. Added fromDict() and
toDict() functions to the TagUnion class (uses the first non-empty tag).
Added fromDict() and toDict() functions for the generic Tag class, only
handling common tags without duplicates. Addded preliminary mp3 test
case. Python3 bindings now available on my github site.
2011-08-27 01:18:21 +02:00
Michael Helmling
b262180857 Some preliminary work for unified dictionary tag interface support.
- toDict() and fromDict() for XiphComments
- toDict() for ID3v2 Tags
2011-08-26 21:48:40 +02:00
Tim De Baets
bec3875b94 Added removePicture() to FLAC::File 2011-08-16 01:57:01 +02:00
Urs Fleisch
ce53d13af1 Add suport for more MP4 metadata atoms
https://bugs.kde.org/show_bug.cgi?id=275784
2011-08-13 17:07:41 +02:00
Mathias Panzenböck
4868bb5690 ByteVector::replace: test shrinking 2011-08-06 19:43:17 +02:00
Jonathan Liu
7cc36db760 Use the default frame factory when it's necessary to parse ID3v2 tags in APE files
https://bugs.kde.org/show_bug.cgi?id=278773
2011-08-06 11:05:20 +02:00
Lukáš Lalinský
028f831417 Basic tests for ByteVector::replace() 2011-08-05 18:47:53 +02:00
Lukáš Lalinský
303af305db Merge remote branch 'panzi/master' 2011-08-05 18:35:24 +02:00
Johannes Pfau
22b57f4463 Add taglib_free function to C binding 2011-08-05 13:17:42 +02:00
Mathias Panzenböck
11c993e9f0 use DATA() macro 2011-08-01 15:33:27 +02:00
Mathias Panzenböck
3b14dc3e94 ByteVector::replace: forgot detach() and opt. when pattern not found 2011-08-01 15:14:58 +02:00
Mathias Panzenböck
ad7645f8e9 ByteVector::replace performance improvements 2011-08-01 04:13:55 +02:00
Lukáš Lalinský
fb2decb7de Reformatting 2011-07-28 19:16:32 +02:00
Lukáš Lalinský
3a837e7fc7 Reformatting 2011-07-28 19:06:35 +02:00
Lukáš Lalinský
0730076a0f Merge remote-tracking branch 'gperks/master'
Conflicts:
	taglib/asf/asfpicture.cpp
	taglib/it/itproperties.h
2011-07-28 19:03:46 +02:00
Lukáš Lalinský
364a840d83 Merge remote-tracking branch 'setosha/ASFPicture_warning_fix' 2011-07-28 18:53:57 +02:00
Scott Wheeler
e9cd383139 Merge pull request #14 from sbooth/master
Some non-PCM wave files can cause SIG_ARITHMETIC
2011-07-28 05:45:11 -07:00
Stephen F. Booth
a41b32bbb2 Don't crash when wav files have a 0 for bit per channel (sampleWidth)
I've seen this in a wav that has an audio format of MP3 (0x55)
2011-07-28 08:36:14 -04:00
Scott Wheeler
98d6b97798 Fix warning 2011-07-27 23:22:23 +02:00
Scott Wheeler
019fe4843f ByteVector works on chars, not unsigned chars, so there needs to be a cast before the comparison 2011-07-27 23:14:54 +02:00
Scott Wheeler
bb25953767 These methods can't be protected since they're called from IT::File
In general this code could use a fair bit of tidying up both stylistically and semantically.
2011-07-27 23:07:38 +02:00
Scott Wheeler
4795831b4a Fix spelling / formatting in comments. 2011-07-27 23:06:06 +02:00
Graham Perks
19484c059d Document ENABLE_STATIC_RUNTIME 2011-07-27 14:35:24 -05:00
Graham Perks
10ea76ff11 Add build option for Visual Studio to link with the static runtime (/MT vs /MD), pass -DENABLE_STATIC_RUNTIME=ON to cmake 2011-07-27 14:25:26 -05:00
Graham Perks
5f84bbf61a Correction to OS X build; include basic Windows build instructions 2011-07-27 10:54:33 -05:00
Graham Perks
8b647e5fa7 Fix for VS2010 which had been throwing out "cannot access protected member declared in class 'TagLib::Mod::Properties'" errors. 2011-07-26 21:45:32 -05:00
Graham Perks
0341079b92 Misc typo corrections 2011-07-26 21:45:28 -05:00
Graham Perks
1a53bfd71a Example cmake for OS X to build a static library 2011-07-26 11:12:27 -05:00
Graham Perks
6aa41d8180 Updated OS X build instructions 2011-07-25 17:56:42 -05:00
Scott Wheeler
101a624c46 Merge branch 'master' of github.com:taglib/taglib 2011-07-21 00:06:50 +02:00
Lukáš Lalinský
3b4e4357e6 Only include config.h if HAVE_CONFIG_H is defined 2011-07-20 22:06:28 +02:00
Scott Wheeler
3baf0a413d Missing const 2011-07-18 21:27:59 +02:00
Anton Sergunov
68c6a7da7a ASFPicture fix warning
class/struct thing

Signed-off-by: Anton Sergunov <setosha@gmail.com>
2011-07-01 16:12:04 +07:00
294 changed files with 17540 additions and 3631 deletions

18
.astylerc Normal file
View File

@@ -0,0 +1,18 @@
--suffix=none
--style=kr
--indent=spaces=2
--indent-col1-comments
--min-conditional-indent=0
--attach-extern-c
--attach-namespaces
--indent-namespaces
--pad-oper
--unpad-paren
--align-pointer=name
--align-reference=name
--max-instatement-indent=40
--break-closing-brackets
--remove-brackets
--convert-tabs
--max-code-length=100
--break-after-logical

21
.editorconfig Normal file
View File

@@ -0,0 +1,21 @@
# EditorConfig is awesome: http://EditorConfig.org
# top-most EditorConfig file
root = true
# Non-specified newlines with a newline ending every file
[*]
insert_final_newline = true
# 2 space indentation
[*.{h,cpp,tcc,cmake}]
indent_style = space
indent_size = 2
# Trim traling whitespaces
[*.{h,cpp,tcc,cmake}]
trim_trailing_whitespace = true
# UTF-8 without BOM
[*]
charset = utf-8

5
.gitignore vendored
View File

@@ -1,5 +1,7 @@
cmake_install.cmake
cmake_uninstall.cmake
Makefile
CTestTestfile.cmake
CMakeFiles/
*.so
*.so.*
@@ -16,6 +18,7 @@ CMakeFiles/
/config.h
/taglib.pc
/tests/test_runner
/tests/Testing
/taglib_config.h
/taglib-config
/bindings/c/taglib_c.pc
@@ -39,3 +42,5 @@ CMakeFiles/
/taglib/tag.dir/Release
/ALL_BUILD.dir
/ZERO_CHECK.dir
taglib.xcodeproj
CMakeScripts

12
.travis.yml Normal file
View File

@@ -0,0 +1,12 @@
language: cpp
sudo: false
compiler:
- gcc
- clang
addons:
apt:
packages:
- libcppunit-dev
- zlib1g-dev
script: cmake -DBUILD_TESTS=ON -DBUILD_EXAMPLES=ON . && make && make check

View File

@@ -10,6 +10,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.
Please send all patches and questions to taglib-devel@kde.org rather than to
individual developers!

View File

@@ -1,6 +1,12 @@
project(taglib)
cmake_minimum_required(VERSION 2.6.0 FATAL_ERROR)
cmake_minimum_required(VERSION 2.8.0 FATAL_ERROR)
if(NOT ${CMAKE_VERSION} VERSION_LESS 2.8.12)
cmake_policy(SET CMP0022 OLD)
endif()
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
option(ENABLE_STATIC "Make static version of libtag" OFF)
if(ENABLE_STATIC)
@@ -9,6 +15,12 @@ if(ENABLE_STATIC)
else()
set(BUILD_SHARED_LIBS ON)
endif()
OPTION(ENABLE_STATIC_RUNTIME "Visual Studio, link with runtime statically" OFF)
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)
@@ -34,9 +46,14 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
endif()
if (MSVC AND ENABLE_STATIC_RUNTIME)
foreach(flag_var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
endforeach(flag_var)
endif()
set(TAGLIB_LIB_MAJOR_VERSION "1")
set(TAGLIB_LIB_MINOR_VERSION "7")
set(TAGLIB_LIB_MINOR_VERSION "10")
set(TAGLIB_LIB_PATCH_VERSION "0")
set(TAGLIB_LIB_VERSION_STRING "${TAGLIB_LIB_MAJOR_VERSION}.${TAGLIB_LIB_MINOR_VERSION}.${TAGLIB_LIB_PATCH_VERSION}")
@@ -45,9 +62,9 @@ set(TAGLIB_LIB_VERSION_STRING "${TAGLIB_LIB_MAJOR_VERSION}.${TAGLIB_LIB_MINOR_VE
# 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 11)
set(TAGLIB_SOVERSION_CURRENT 16)
set(TAGLIB_SOVERSION_REVISION 0)
set(TAGLIB_SOVERSION_AGE 10)
set(TAGLIB_SOVERSION_AGE 15)
math(EXPR TAGLIB_SOVERSION_MAJOR "${TAGLIB_SOVERSION_CURRENT} - ${TAGLIB_SOVERSION_AGE}")
math(EXPR TAGLIB_SOVERSION_MINOR "${TAGLIB_SOVERSION_AGE}")
@@ -55,32 +72,52 @@ math(EXPR TAGLIB_SOVERSION_PATCH "${TAGLIB_SOVERSION_REVISION}")
include(ConfigureChecks.cmake)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/taglib-config.cmake ${CMAKE_CURRENT_BINARY_DIR}/taglib-config )
install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/taglib-config DESTINATION ${BIN_INSTALL_DIR})
if(NOT WIN32)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/taglib-config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/taglib-config")
install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/taglib-config" DESTINATION "${BIN_INSTALL_DIR}")
endif()
if(NOT WIN32 AND NOT BUILD_FRAMEWORK)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/taglib.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/taglib.pc )
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/taglib.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
if(WIN32)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/taglib-config.cmd.cmake" "${CMAKE_CURRENT_BINARY_DIR}/taglib-config.cmd")
install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/taglib-config.cmd" DESTINATION "${BIN_INSTALL_DIR}")
endif()
if(NOT BUILD_FRAMEWORK)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/taglib.pc.cmake" "${CMAKE_CURRENT_BINARY_DIR}/taglib.pc")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/taglib.pc" DESTINATION "${LIB_INSTALL_DIR}/pkgconfig")
endif()
if(NOT HAVE_ZLIB AND ZLIB_SOURCE)
set(HAVE_ZLIB 1)
set(HAVE_ZLIB_SOURCE 1)
endif()
include_directories(${CMAKE_CURRENT_BINARY_DIR})
configure_file(config-taglib.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
configure_file(config.h.cmake "${CMAKE_CURRENT_BINARY_DIR}/config.h")
if(WITH_ASF)
set(TAGLIB_WITH_ASF TRUE)
set(TAGLIB_WITH_ASF TRUE)
endif()
if(WITH_MP4)
set(TAGLIB_WITH_MP4 TRUE)
set(TAGLIB_WITH_MP4 TRUE)
endif()
configure_file(taglib/taglib_config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/taglib_config.h)
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)
add_subdirectory(bindings)
add_subdirectory(tests)
if(BUILD_TESTS)
enable_testing()
add_subdirectory(tests)
endif(BUILD_TESTS)
add_subdirectory(examples)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.cmake ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.cmake" "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile")
file(COPY doc/taglib.png DESTINATION doc)
add_custom_target(docs doxygen)
@@ -90,5 +127,7 @@ configure_file(
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
IMMEDIATE @ONLY)
add_custom_target(uninstall
COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
if (NOT TARGET uninstall)
add_custom_target(uninstall
COMMAND "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
endif()

View File

@@ -1,23 +1,211 @@
include(CheckIncludeFile)
include(CheckIncludeFiles)
include(CheckSymbolExists)
include(CheckFunctionExists)
include(CheckLibraryExists)
include(CheckTypeSize)
include(CheckCXXSourceCompiles)
# check for libz using the cmake supplied FindZLIB.cmake
find_package(ZLIB)
if(ZLIB_FOUND)
set(HAVE_ZLIB 1)
else()
set(HAVE_ZLIB 0)
# Check if the size of numeric types are suitable.
check_type_size("short" SIZEOF_SHORT)
if(NOT ${SIZEOF_SHORT} EQUAL 2)
message(FATAL_ERROR "TagLib requires that short is 16-bit wide.")
endif()
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules)
find_package(CppUnit)
if(NOT CppUnit_FOUND AND BUILD_TESTS)
message(STATUS "CppUnit not found, disabling tests.")
set(BUILD_TESTS OFF)
check_type_size("int" SIZEOF_INT)
if(NOT ${SIZEOF_INT} EQUAL 4)
message(FATAL_ERROR "TagLib requires that int is 32-bit wide.")
endif()
check_type_size("long long" SIZEOF_LONGLONG)
if(NOT ${SIZEOF_LONGLONG} EQUAL 8)
message(FATAL_ERROR "TagLib requires that long long is 64-bit wide.")
endif()
check_type_size("wchar_t" SIZEOF_WCHAR_T)
if(${SIZEOF_WCHAR_T} LESS 2)
message(FATAL_ERROR "TagLib requires that wchar_t is sufficient to store a UTF-16 char.")
endif()
check_type_size("float" SIZEOF_FLOAT)
if(NOT ${SIZEOF_FLOAT} EQUAL 4)
message(FATAL_ERROR "TagLib requires that float is 32-bit wide.")
endif()
check_type_size("double" SIZEOF_DOUBLE)
if(NOT ${SIZEOF_DOUBLE} EQUAL 8)
message(FATAL_ERROR "TagLib requires that double is 64-bit wide.")
endif()
# Determine which kind of atomic operations your compiler supports.
check_cxx_source_compiles("
#include <atomic>
int main() {
std::atomic<unsigned int> x;
x.fetch_add(1);
x.fetch_sub(1);
return 0;
}
" HAVE_STD_ATOMIC)
if(NOT HAVE_STD_ATOMIC)
check_cxx_source_compiles("
#include <boost/atomic.hpp>
int main() {
boost::atomic<unsigned int> x(1);
x.fetch_add(1);
x.fetch_sub(1);
return 0;
}
" HAVE_BOOST_ATOMIC)
if(NOT HAVE_BOOST_ATOMIC)
check_cxx_source_compiles("
int main() {
volatile int x;
__sync_add_and_fetch(&x, 1);
int y = __sync_sub_and_fetch(&x, 1);
return 0;
}
" HAVE_GCC_ATOMIC)
if(NOT HAVE_GCC_ATOMIC)
check_cxx_source_compiles("
#include <libkern/OSAtomic.h>
int main() {
volatile int32_t x;
OSAtomicIncrement32Barrier(&x);
int32_t y = OSAtomicDecrement32Barrier(&x);
return 0;
}
" HAVE_MAC_ATOMIC)
if(NOT HAVE_MAC_ATOMIC)
check_cxx_source_compiles("
#include <windows.h>
int main() {
volatile LONG x;
InterlockedIncrement(&x);
LONG y = InterlockedDecrement(&x);
return 0;
}
" HAVE_WIN_ATOMIC)
if(NOT HAVE_WIN_ATOMIC)
check_cxx_source_compiles("
#include <ia64intrin.h>
int main() {
volatile int x;
__sync_add_and_fetch(&x, 1);
int y = __sync_sub_and_fetch(&x, 1);
return 0;
}
" HAVE_IA64_ATOMIC)
endif()
endif()
endif()
endif()
endif()
# Determine which kind of byte swap functions your compiler supports.
check_cxx_source_compiles("
int main() {
__builtin_bswap16(0);
__builtin_bswap32(0);
__builtin_bswap64(0);
return 0;
}
" HAVE_GCC_BYTESWAP)
if(NOT HAVE_GCC_BYTESWAP)
check_cxx_source_compiles("
#include <byteswap.h>
int main() {
__bswap_16(0);
__bswap_32(0);
__bswap_64(0);
return 0;
}
" HAVE_GLIBC_BYTESWAP)
if(NOT HAVE_GLIBC_BYTESWAP)
check_cxx_source_compiles("
#include <stdlib.h>
int main() {
_byteswap_ushort(0);
_byteswap_ulong(0);
_byteswap_uint64(0);
return 0;
}
" HAVE_MSC_BYTESWAP)
if(NOT HAVE_MSC_BYTESWAP)
check_cxx_source_compiles("
#include <libkern/OSByteOrder.h>
int main() {
OSSwapInt16(0);
OSSwapInt32(0);
OSSwapInt64(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()
endif()
endif()
endif()
# Determine whether your compiler supports some safer version of vsprintf.
check_cxx_source_compiles("
#include <cstdio>
#include <cstdarg>
int main() {
char buf[20];
va_list args;
vsnprintf(buf, 20, \"%d\", args);
return 0;
}
" HAVE_VSNPRINTF)
if(NOT HAVE_VSNPRINTF)
check_cxx_source_compiles("
#include <cstdio>
#include <cstdarg>
int main() {
char buf[20];
va_list args;
vsprintf_s(buf, \"%d\", args);
return 0;
}
" HAVE_VSPRINTF_S)
endif()
# Check for libz using the cmake supplied FindZLIB.cmake
if(NOT ZLIB_SOURCE)
find_package(ZLIB)
if(ZLIB_FOUND)
set(HAVE_ZLIB 1)
else()
set(HAVE_ZLIB 0)
endif()
endif()
if(BUILD_TESTS)
find_package(CppUnit)
if(NOT CppUnit_FOUND)
message(STATUS "CppUnit not found, disabling tests.")
set(BUILD_TESTS OFF)
endif()
endif()

128
INSTALL
View File

@@ -5,7 +5,7 @@ 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_RELEASE_TYPE=Release .
cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_BUILD_TYPE=Release .
make
sudo make install
@@ -16,8 +16,8 @@ In order to build the included examples, use the BUILD_EXAMPLES option:
See http://www.cmake.org/cmake/help/runningcmake.html for generic help on
running CMake.
Mac OS X Framework
------------------
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
@@ -30,14 +30,130 @@ an Universal Binary framework with Mac OS X 10.4 as the deployment target:
-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;i368;x86_64"
-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" \
-DENABLE_STATIC=ON \
-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 enable the following two options with CMake.
-DENABLE_STATIC=ON -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. The test suite has a custom target
in the build system, so you can run the tests using make:
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

127
NEWS
View File

@@ -1,9 +1,128 @@
TagLib 1.8 (In Development)
TagLib 1.10 (Aug 23, 2015)
==========================
1.10 BETA:
* New API for the audio length in milliseconds.
* Added support for ID3v2 ETCO and SYLT frames.
* Added support for album artist in PropertyMap API of MP4 files.
* Added support for embedded frames in ID3v2 CHAP and CTOC frames.
* Added support for AIFF-C files.
* Better handling of duplicate ID3v2 tags in MPEG files.
* Allowed generating taglib.pc on Windows.
* Added ZLIB_SOURCE build option.
* Fixed backwards-incompatible change in TagLib::String when constructing UTF16 strings.
* Fixed crash when parsing certain FLAC files.
* Fixed crash when encoding empty strings.
* Fixed saving of certain XM files on OS X.
* Changed Xiph and APE generic getters to return space-concatenated values.
* Fixed possible file corruptions when removing tags from WAV files.
* Added support for MP4 files with 64-bit atoms in certain 64-bit environments.
* Prevented ID3v2 padding from being too large.
* Fixed crash when parsing corrupted APE files.
* Fixed crash when parsing corrupted WAV files.
* Fixed crash when parsing corrupted Ogg FLAC files.
* Fixed crash when parsing corrupted MPEG files.
* Fixed saving empty tags in WAV files.
* Fixed crash when parsing corrupted Musepack files.
* Fixed possible memory leaks when parsing AIFF and WAV files.
* Fixed crash when parsing corrupted MP4 files.
* Stopped writing empty ID3v2 frames.
* Fixed possible file corruptions when saving WMA files.
* Added TagLib::MP4::Tag::isEmpty().
* Added accessors to manipulate MP4 tags.
* Fixed crash when parsing corrupted WavPack files.
* Fixed seeking MPEG frames.
* Fixed reading FLAC files with zero-sized padding blocks.
* Added support for reading the encoder information of WMA files.
* Added support for reading the codec of WAV files.
* Added support for multi channel WavPack files.
* Added support for reading the nominal bitrate of Ogg Speex files.
* Added support for VBR headers in MPEG files.
* Marked FLAC::File::streamInfoData() deprecated. It returns an empty ByteVector.
* Marked FLAC::File::streamLength() deprecated. It returns zero.
* Fixed possible file corruptions when adding an ID3v1 tag to FLAC files.
* Many smaller bug fixes and performance improvements.
TagLib 1.9.1 (Oct 8, 2013)
==========================
* Fixed binary incompatible change in TagLib::Map and TagLib::List.
* Fixed constructing String from ByteVector.
* Fixed compilation on MSVC with the /Zc:wchar_t- option.
* Fixed detecting of RIFF files with invalid chunk sizes.
* Added TagLib::MP4::Properties::codec().
TagLib 1.9 (Oct 6, 2013)
========================
* Added support for the Ogg Opus file format.
* Added support for INFO tags in WAV files.
* Changed FileStream to use Windows file API.
* Included taglib-config.cmd script for Windows.
* New ID3v1::Tag methods for working directly with genre numbers.
* New MPEG::File methods for checking which tags are saved in the file.
* Added support for the PropertyMap API to ASF and MP4 files.
* Added MusicBrainz identifiers to the PropertyMap API.
* Allowed reading of MP4 cover art without an explicitly specified format.
* Better parsing of corrupted FLAC files.
* Fixed saving of PropertyMap comments without description into ID3v2 tags.
* Fixed crash when parsing certain XM files.
* Fixed compilation of unit test with clang.
* Better handling of files that can't be open or have read-only permissions.
* Improved atomic reference counting.
* New hookable API for debug messages.
* More complete Windows install instructions.
* Many smaller bug fixes and performance improvements.
TagLib 1.8 (Sep 6, 2012)
========================
1.8:
* Added support for OWNE ID3 frames.
* Changed key validation in the new PropertyMap API.
* ID3v1::Tag::setStringHandler will no londer delete the previous handler,
the caller is responsible for this.
* File objects will also no longer delete the passed IOStream objects. It
should be done in the caller code after the File object is no longer
used.
* Added ID3v2::Tag::setLatin1StringHandler for custom handling of
latin1-encoded text in ID3v2 frames.
* Fixed validation of ID3v2 frame IDs (IDs with '0' were ignored).
1.8 BETA:
* New API for accessing tags by name.
* New abstract I/O stream layer to allow custom I/O handlers.
* Support for writing ID3v2.3 tags.
* Support for various module file formats (MOD, S3M, IT, XM).
* Support for MP4 and ASF is now enabled by default.
* Started using atomic int operations for reference counting.
* Added methods for checking if WMA and MP4 files are DRM-protected.
* Added taglib_free to the C bindings.
* New method to allow removing pictures from FLAC files.
* Support for reading audio properties from ALAC and Musepack SV8 files.
* Added replay-gain information to Musepack audio properties.
* Support for APEv2 binary tags.
* Many AudioProperties subclasses now provide information about the total number of samples.
* Various small bug fixes.
TagLib 1.7.2 (Apr 20, 2012)
===========================
* Support for writing ID3v2.3 tags.
* Added methods for checking if WMA and MP4 files are DRM-protected.
* Started using atomic int operations for reference counting.
* Fixed division by zero while parsing corrupted MP4 files (CVE-2012-2396).
* Fixed compilation on Haiku.
TagLib 1.7.1 (Mar 17, 2012)
===========================
* Improved parsing of corrupted WMA, RIFF and OGG files.
* Fixed a memory leak in the WMA parser.
* Fixed a memory leak in the FLAC parser.
* Fixed a possible division by zero in the APE parser.
* Added detection of TTA2 files.
* Fixed saving of multiple identically named tags to Vorbis Comments.
TagLib 1.7 (Mar 11, 2011)
=========================

View File

@@ -61,7 +61,7 @@ install(TARGETS tag_c
PUBLIC_HEADER DESTINATION ${INCLUDE_INSTALL_DIR}/taglib
)
if(NOT WIN32 AND NOT BUILD_FRAMEWORK)
if(NOT BUILD_FRAMEWORK)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/taglib_c.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/taglib_c.pc)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/taglib_c.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
endif()

View File

@@ -19,10 +19,6 @@
* USA *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <fileref.h>
#include <tfile.h>
@@ -50,12 +46,17 @@ static bool stringManagementEnabled = true;
void taglib_set_strings_unicode(BOOL unicode)
{
unicodeStrings = bool(unicode);
unicodeStrings = (unicode != 0);
}
void taglib_set_string_management_enabled(BOOL management)
{
stringManagementEnabled = bool(management);
stringManagementEnabled = (management != 0);
}
void taglib_free(void* pointer)
{
free(pointer);
}
////////////////////////////////////////////////////////////////////////////////
@@ -104,7 +105,7 @@ void taglib_file_free(TagLib_File *file)
BOOL taglib_file_is_valid(const TagLib_File *file)
{
return reinterpret_cast<const File *>(file)->isValid();
return reinterpret_cast<const File *>(file)->isValid();
}
TagLib_Tag *taglib_file_tag(const TagLib_File *file)
@@ -232,7 +233,7 @@ void taglib_tag_free_strings()
if(!stringManagementEnabled)
return;
for(List<char *>::Iterator it = strings.begin(); it != strings.end(); ++it)
for(List<char *>::ConstIterator it = strings.begin(); it != strings.end(); ++it)
free(*it);
strings.clear();
}

View File

@@ -29,7 +29,9 @@
extern "C" {
#endif
#if defined(_WIN32) || defined(_WIN64)
#if defined(TAGLIB_STATIC)
#define TAGLIB_C_EXPORT
#elif defined(_WIN32) || defined(_WIN64)
#ifdef MAKE_TAGLIB_C_LIB
#define TAGLIB_C_EXPORT __declspec(dllexport)
#else
@@ -79,6 +81,11 @@ TAGLIB_C_EXPORT void taglib_set_strings_unicode(BOOL unicode);
*/
TAGLIB_C_EXPORT void taglib_set_string_management_enabled(BOOL management);
/*!
* Explicitly free a string returned from TagLib
*/
TAGLIB_C_EXPORT void taglib_free(void* pointer);
/*******************************************************************************
* File API
******************************************************************************/
@@ -99,7 +106,7 @@ typedef enum {
/*!
* Creates a TagLib file based on \a filename. TagLib will try to guess the file
* type.
*
*
* \returns NULL if the file type cannot be determined or the file cannot
* be opened.
*/

View File

@@ -1,11 +0,0 @@
/* config-taglib.h. Generated by cmake from config-taglib.h.cmake */
/* Define if you have libz */
#cmakedefine HAVE_ZLIB 1
#cmakedefine NO_ITUNES_HACKS 1
#cmakedefine WITH_ASF 1
#cmakedefine WITH_MP4 1
#cmakedefine TESTS_DIR "@TESTS_DIR@"

28
config.h.cmake Normal file
View File

@@ -0,0 +1,28 @@
/* config.h. Generated by cmake from config.h.cmake */
/* Defined if your compiler supports some byte swap functions */
#cmakedefine HAVE_GCC_BYTESWAP 1
#cmakedefine HAVE_GLIBC_BYTESWAP 1
#cmakedefine HAVE_MSC_BYTESWAP 1
#cmakedefine HAVE_MAC_BYTESWAP 1
#cmakedefine HAVE_OPENBSD_BYTESWAP 1
/* Defined if your compiler supports some atomic operations */
#cmakedefine HAVE_STD_ATOMIC 1
#cmakedefine HAVE_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 some safer version of vsprintf */
#cmakedefine HAVE_VSNPRINTF 1
#cmakedefine HAVE_VSPRINTF_S 1
/* Defined if you have libz */
#cmakedefine HAVE_ZLIB 1
/* Indicates whether debug messages are shown even in release mode */
#cmakedefine TRACE_IN_RELEASE 1
#cmakedefine TESTS_DIR "@TESTS_DIR@"

View File

@@ -95,7 +95,10 @@ int main(int argc, char *argv[])
for(APE::ItemListMap::ConstIterator it = ape->itemListMap().begin();
it != ape->itemListMap().end(); ++it)
{
cout << (*it).first << " - \"" << (*it).second.toString() << "\"" << endl;
if((*it).second.type() != APE::Item::Binary)
cout << (*it).first << " - \"" << (*it).second.toString() << "\"" << endl;
else
cout << (*it).first << " - Binary data (" << (*it).second.binaryData().size() << " bytes)" << endl;
}
}
else

View File

@@ -23,20 +23,15 @@
*/
#include <iostream>
#include <iomanip>
#include <stdio.h>
#include <fileref.h>
#include <tag.h>
#include <tpropertymap.h>
using namespace std;
TagLib::String formatSeconds(int seconds)
{
char secondsString[3];
sprintf(secondsString, "%02i", seconds);
return secondsString;
}
int main(int argc, char *argv[])
{
for(int i = 1; i < argc; i++) {
@@ -49,7 +44,7 @@ int main(int argc, char *argv[])
TagLib::Tag *tag = f.tag();
cout << "-- TAG --" << endl;
cout << "-- TAG (basic) --" << endl;
cout << "title - \"" << tag->title() << "\"" << endl;
cout << "artist - \"" << tag->artist() << "\"" << endl;
cout << "album - \"" << tag->album() << "\"" << endl;
@@ -57,6 +52,23 @@ int main(int argc, char *argv[])
cout << "comment - \"" << tag->comment() << "\"" << endl;
cout << "track - \"" << tag->track() << "\"" << endl;
cout << "genre - \"" << tag->genre() << "\"" << endl;
TagLib::PropertyMap tags = f.file()->properties();
unsigned int longest = 0;
for(TagLib::PropertyMap::ConstIterator i = tags.begin(); i != tags.end(); ++i) {
if (i->first.size() > longest) {
longest = i->first.size();
}
}
cout << "-- TAG (properties) --" << endl;
for(TagLib::PropertyMap::ConstIterator i = tags.begin(); i != tags.end(); ++i) {
for(TagLib::StringList::ConstIterator j = i->second.begin(); j != i->second.end(); ++j) {
cout << left << std::setw(longest) << i->first << " - " << '"' << *j << '"' << endl;
}
}
}
if(!f.isNull() && f.audioProperties()) {
@@ -70,7 +82,7 @@ int main(int argc, char *argv[])
cout << "bitrate - " << properties->bitrate() << endl;
cout << "sample rate - " << properties->sampleRate() << endl;
cout << "channels - " << properties->channels() << endl;
cout << "length - " << minutes << ":" << formatSeconds(seconds) << endl;
cout << "length - " << minutes << ":" << setfill('0') << setw(2) << seconds << endl;
}
}
return 0;

View File

@@ -94,7 +94,7 @@ int main(int argc, char *argv[])
char field = argv[i][1];
TagLib::String value = argv[i + 1];
TagLib::List<TagLib::FileRef>::Iterator it;
TagLib::List<TagLib::FileRef>::ConstIterator it;
for(it = fileList.begin(); it != fileList.end(); ++it) {
TagLib::Tag *t = (*it).tag();
@@ -131,7 +131,7 @@ int main(int argc, char *argv[])
usage();
}
TagLib::List<TagLib::FileRef>::Iterator it;
TagLib::List<TagLib::FileRef>::ConstIterator it;
for(it = fileList.begin(); it != fileList.end(); ++it)
(*it).file()->save();

36
taglib-config.cmd.cmake Normal file
View File

@@ -0,0 +1,36 @@
@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_MAJOR_VERSION}.${TAGLIB_LIB_MINOR_VERSION}.${TAGLIB_LIB_PATCH_VERSION}
if /i "%1#" == "--prefix#" echo ${CMAKE_INSTALL_PREFIX}
:theend

View File

@@ -10,6 +10,7 @@ include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/mp4
${CMAKE_CURRENT_SOURCE_DIR}/ogg/vorbis
${CMAKE_CURRENT_SOURCE_DIR}/ogg/speex
${CMAKE_CURRENT_SOURCE_DIR}/ogg/opus
${CMAKE_CURRENT_SOURCE_DIR}/mpeg/id3v2
${CMAKE_CURRENT_SOURCE_DIR}/mpeg/id3v2/frames
${CMAKE_CURRENT_SOURCE_DIR}/mpeg/id3v1
@@ -27,6 +28,8 @@ include_directories(
if(ZLIB_FOUND)
include_directories(${ZLIB_INCLUDE_DIR})
elseif(HAVE_ZLIB_SOURCE)
include_directories(${ZLIB_SOURCE})
endif()
set(tag_HDRS
@@ -34,7 +37,7 @@ set(tag_HDRS
fileref.h
audioproperties.h
taglib_export.h
${CMAKE_BINARY_DIR}/taglib_config.h
${CMAKE_CURRENT_BINARY_DIR}/../taglib_config.h
toolkit/taglib.h
toolkit/tstring.h
toolkit/tlist.h
@@ -48,6 +51,9 @@ set(tag_HDRS
toolkit/tfilestream.h
toolkit/tmap.h
toolkit/tmap.tcc
toolkit/tpropertymap.h
toolkit/trefcounter.h
toolkit/tdebuglistener.h
mpeg/mpegfile.h
mpeg/mpegproperties.h
mpeg/mpegheader.h
@@ -63,15 +69,20 @@ set(tag_HDRS
mpeg/id3v2/id3v2tag.h
mpeg/id3v2/frames/attachedpictureframe.h
mpeg/id3v2/frames/commentsframe.h
mpeg/id3v2/frames/eventtimingcodesframe.h
mpeg/id3v2/frames/generalencapsulatedobjectframe.h
mpeg/id3v2/frames/ownershipframe.h
mpeg/id3v2/frames/popularimeterframe.h
mpeg/id3v2/frames/privateframe.h
mpeg/id3v2/frames/relativevolumeframe.h
mpeg/id3v2/frames/synchronizedlyricsframe.h
mpeg/id3v2/frames/textidentificationframe.h
mpeg/id3v2/frames/uniquefileidentifierframe.h
mpeg/id3v2/frames/unknownframe.h
mpeg/id3v2/frames/unsynchronizedlyricsframe.h
mpeg/id3v2/frames/urllinkframe.h
mpeg/id3v2/frames/chapterframe.h
mpeg/id3v2/frames/tableofcontentsframe.h
ogg/oggfile.h
ogg/oggpage.h
ogg/oggpageheader.h
@@ -81,6 +92,8 @@ set(tag_HDRS
ogg/flac/oggflacfile.h
ogg/speex/speexfile.h
ogg/speex/speexproperties.h
ogg/opus/opusfile.h
ogg/opus/opusproperties.h
flac/flacfile.h
flac/flacpicture.h
flac/flacproperties.h
@@ -101,6 +114,7 @@ set(tag_HDRS
riff/aiff/aiffproperties.h
riff/wav/wavfile.h
riff/wav/wavproperties.h
riff/wav/infotag.h
asf/asffile.h
asf/asfproperties.h
asf/asftag.h
@@ -149,15 +163,20 @@ set(id3v2_SRCS
set(frames_SRCS
mpeg/id3v2/frames/attachedpictureframe.cpp
mpeg/id3v2/frames/commentsframe.cpp
mpeg/id3v2/frames/eventtimingcodesframe.cpp
mpeg/id3v2/frames/generalencapsulatedobjectframe.cpp
mpeg/id3v2/frames/ownershipframe.cpp
mpeg/id3v2/frames/popularimeterframe.cpp
mpeg/id3v2/frames/privateframe.cpp
mpeg/id3v2/frames/relativevolumeframe.cpp
mpeg/id3v2/frames/synchronizedlyricsframe.cpp
mpeg/id3v2/frames/textidentificationframe.cpp
mpeg/id3v2/frames/uniquefileidentifierframe.cpp
mpeg/id3v2/frames/unknownframe.cpp
mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp
mpeg/id3v2/frames/urllinkframe.cpp
mpeg/id3v2/frames/chapterframe.cpp
mpeg/id3v2/frames/tableofcontentsframe.cpp
)
set(ogg_SRCS
@@ -216,6 +235,11 @@ set(speex_SRCS
ogg/speex/speexproperties.cpp
)
set(opus_SRCS
ogg/opus/opusfile.cpp
ogg/opus/opusproperties.cpp
)
set(trueaudio_SRCS
trueaudio/trueaudiofile.cpp
trueaudio/trueaudioproperties.cpp
@@ -241,6 +265,7 @@ set(aiff_SRCS
set(wav_SRCS
riff/wav/wavfile.cpp
riff/wav/wavproperties.cpp
riff/wav/infotag.cpp
)
set(mod_SRCS
@@ -275,14 +300,34 @@ set(toolkit_SRCS
toolkit/tfile.cpp
toolkit/tfilestream.cpp
toolkit/tdebug.cpp
toolkit/unicode.cpp
toolkit/tpropertymap.cpp
toolkit/trefcounter.cpp
toolkit/tdebuglistener.cpp
)
if(NOT WIN32)
set(unicode_SRCS
toolkit/unicode.cpp
)
endif()
if(HAVE_ZLIB_SOURCE)
set(zlib_SRCS
${ZLIB_SOURCE}/adler32.c
${ZLIB_SOURCE}/crc32.c
${ZLIB_SOURCE}/inffast.c
${ZLIB_SOURCE}/inflate.c
${ZLIB_SOURCE}/inftrees.c
${ZLIB_SOURCE}/zutil.c
)
endif()
set(tag_LIB_SRCS
${mpeg_SRCS} ${id3v1_SRCS} ${id3v2_SRCS} ${frames_SRCS} ${ogg_SRCS}
${vorbis_SRCS} ${oggflacs_SRCS} ${mpc_SRCS} ${ape_SRCS} ${toolkit_SRCS} ${flacs_SRCS}
${wavpack_SRCS} ${speex_SRCS} ${trueaudio_SRCS} ${riff_SRCS} ${aiff_SRCS} ${wav_SRCS}
${asf_SRCS} ${mp4_SRCS} ${mod_SRCS} ${s3m_SRCS} ${it_SRCS} ${xm_SRCS}
${asf_SRCS} ${mp4_SRCS} ${mod_SRCS} ${s3m_SRCS} ${it_SRCS} ${xm_SRCS} ${opus_SRCS}
${unicode_SRCS} ${zlib_SRCS}
tag.cpp
tagunion.cpp
fileref.cpp
@@ -292,7 +337,7 @@ set(tag_LIB_SRCS
add_library(tag ${tag_LIB_SRCS} ${tag_HDRS})
if(ZLIB_FOUND)
target_link_libraries(tag ${ZLIB_LIBRARIES})
target_link_libraries(tag ${ZLIB_LIBRARIES})
endif()
set_target_properties(tag PROPERTIES
@@ -308,10 +353,9 @@ if(BUILD_FRAMEWORK)
endif()
install(TARGETS tag
FRAMEWORK DESTINATION ${FRAMEWORK_INSTALL_DIR}
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
RUNTIME DESTINATION ${BIN_INSTALL_DIR}
ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
PUBLIC_HEADER DESTINATION ${INCLUDE_INSTALL_DIR}/taglib
FRAMEWORK DESTINATION ${FRAMEWORK_INSTALL_DIR}
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
RUNTIME DESTINATION ${BIN_INSTALL_DIR}
ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
PUBLIC_HEADER DESTINATION ${INCLUDE_INSTALL_DIR}/taglib
)

View File

@@ -36,6 +36,8 @@
#include <tdebug.h>
#include <tagunion.h>
#include <id3v1tag.h>
#include <id3v2header.h>
#include <tpropertymap.h>
#include "apefile.h"
@@ -46,7 +48,7 @@ using namespace TagLib;
namespace
{
enum { APEIndex, ID3v1Index };
enum { ApeAPEIndex = 0, ApeID3v1Index = 1 };
}
class APE::File::FilePrivate
@@ -56,12 +58,17 @@ public:
APELocation(-1),
APESize(0),
ID3v1Location(-1),
ID3v2Header(0),
ID3v2Location(-1),
ID3v2Size(0),
properties(0),
hasAPE(false),
hasID3v1(false) {}
hasID3v1(false),
hasID3v2(false) {}
~FilePrivate()
{
delete ID3v2Header;
delete properties;
}
@@ -70,6 +77,10 @@ public:
long ID3v1Location;
ID3v2::Header *ID3v2Header;
long ID3v2Location;
uint ID3v2Size;
TagUnion tag;
Properties *properties;
@@ -79,24 +90,27 @@ public:
bool hasAPE;
bool hasID3v1;
bool hasID3v2;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
APE::File::File(FileName file, bool readProperties,
Properties::ReadStyle propertiesStyle) : TagLib::File(file)
APE::File::File(FileName file, bool readProperties, Properties::ReadStyle) :
TagLib::File(file),
d(new FilePrivate())
{
d = new FilePrivate;
read(readProperties, propertiesStyle);
if(isOpen())
read(readProperties);
}
APE::File::File(IOStream *stream, bool readProperties,
Properties::ReadStyle propertiesStyle) : TagLib::File(stream)
APE::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle) :
TagLib::File(stream),
d(new FilePrivate())
{
d = new FilePrivate;
read(readProperties, propertiesStyle);
if(isOpen())
read(readProperties);
}
APE::File::~File()
@@ -109,6 +123,30 @@ TagLib::Tag *APE::File::tag() const
return &d->tag;
}
PropertyMap APE::File::properties() const
{
if(d->hasAPE)
return d->tag.access<APE::Tag>(ApeAPEIndex, false)->properties();
if(d->hasID3v1)
return d->tag.access<ID3v1::Tag>(ApeID3v1Index, false)->properties();
return PropertyMap();
}
void APE::File::removeUnsupportedProperties(const StringList &properties)
{
if(d->hasAPE)
d->tag.access<APE::Tag>(ApeAPEIndex, false)->removeUnsupportedProperties(properties);
if(d->hasID3v1)
d->tag.access<ID3v1::Tag>(ApeID3v1Index, false)->removeUnsupportedProperties(properties);
}
PropertyMap APE::File::setProperties(const PropertyMap &properties)
{
if(d->hasID3v1)
d->tag.access<ID3v1::Tag>(ApeID3v1Index, false)->setProperties(properties);
return d->tag.access<APE::Tag>(ApeAPEIndex, true)->setProperties(properties);
}
APE::Properties *APE::File::audioProperties() const
{
return d->properties;
@@ -185,41 +223,62 @@ bool APE::File::save()
ID3v1::Tag *APE::File::ID3v1Tag(bool create)
{
return d->tag.access<ID3v1::Tag>(ID3v1Index, create);
return d->tag.access<ID3v1::Tag>(ApeID3v1Index, create);
}
APE::Tag *APE::File::APETag(bool create)
{
return d->tag.access<APE::Tag>(APEIndex, create);
return d->tag.access<APE::Tag>(ApeAPEIndex, create);
}
void APE::File::strip(int tags)
{
if(tags & ID3v1) {
d->tag.set(ID3v1Index, 0);
d->tag.set(ApeID3v1Index, 0);
APETag(true);
}
if(tags & APE) {
d->tag.set(APEIndex, 0);
d->tag.set(ApeAPEIndex, 0);
if(!ID3v1Tag())
APETag(true);
}
}
bool APE::File::hasAPETag() const
{
return d->hasAPE;
}
bool APE::File::hasID3v1Tag() const
{
return d->hasID3v1;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void APE::File::read(bool readProperties, Properties::ReadStyle /* propertiesStyle */)
void APE::File::read(bool readProperties)
{
// Look for an ID3v2 tag
d->ID3v2Location = findID3v2();
if(d->ID3v2Location >= 0) {
seek(d->ID3v2Location);
d->ID3v2Header = new ID3v2::Header(readBlock(ID3v2::Header::size()));
d->ID3v2Size = d->ID3v2Header->completeTagSize();
d->hasID3v2 = true;
}
// Look for an ID3v1 tag
d->ID3v1Location = findID3v1();
if(d->ID3v1Location >= 0) {
d->tag.set(ID3v1Index, new ID3v1::Tag(this, d->ID3v1Location));
d->tag.set(ApeID3v1Index, new ID3v1::Tag(this, d->ID3v1Location));
d->hasID3v1 = true;
}
@@ -228,7 +287,7 @@ void APE::File::read(bool readProperties, Properties::ReadStyle /* propertiesSty
d->APELocation = findAPE();
if(d->APELocation >= 0) {
d->tag.set(APEIndex, new APE::Tag(this, d->APELocation));
d->tag.set(ApeAPEIndex, new APE::Tag(this, d->APELocation));
d->APESize = APETag()->footer()->completeTagSize();
d->APELocation = d->APELocation + APETag()->footer()->size() - d->APESize;
d->hasAPE = true;
@@ -240,7 +299,25 @@ void APE::File::read(bool readProperties, Properties::ReadStyle /* propertiesSty
// Look for APE audio properties
if(readProperties) {
d->properties = new Properties(this);
long streamLength;
if(d->hasAPE)
streamLength = d->APELocation;
else if(d->hasID3v1)
streamLength = d->ID3v1Location;
else
streamLength = length();
if(d->hasID3v2) {
seek(d->ID3v2Location + d->ID3v2Size);
streamLength -= (d->ID3v2Location + d->ID3v2Size);
}
else {
seek(0);
}
d->properties = new Properties(this, streamLength);
}
}
@@ -275,3 +352,16 @@ long APE::File::findID3v1()
return -1;
}
long APE::File::findID3v2()
{
if(!isValid())
return -1;
seek(0);
if(readBlock(3) == ID3v2::Header::fileIdentifier())
return 0;
return -1;
}

View File

@@ -59,7 +59,7 @@ namespace TagLib {
//! An implementation of TagLib::File with APE specific methods
/*!
* This implements and provides an interface APE WavPack files to the
* This implements and provides an interface for APE files to the
* TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing
* the abstract TagLib::File API as well as providing some additional
* information specific to APE files.
@@ -84,17 +84,22 @@ namespace TagLib {
};
/*!
* Contructs an WavPack file from \a file. If \a readProperties is true the
* file's audio properties will also be read using \a propertiesStyle. If
* false, \a propertiesStyle is ignored.
* Constructs an APE 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,
Properties::ReadStyle propertiesStyle = Properties::Average);
/*!
* Contructs an WavPack file from \a file. If \a readProperties is true the
* file's audio properties will also be read using \a propertiesStyle. If
* false, \a propertiesStyle is ignored.
* Constructs an APE 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,
Properties::ReadStyle propertiesStyle = Properties::Average);
@@ -110,6 +115,26 @@ 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 &);
/*!
* Returns the APE::Properties for this file. If no audio properties
* were read then this will return a null pointer.
@@ -121,33 +146,47 @@ namespace TagLib {
*
* \note According to the official Monkey's Audio SDK, an APE file
* can only have either ID3V1 or APE tags, so a parameter is used here.
*
* \warning In the current implementation, it's dangerous to call save()
* repeatedly. At worst it will corrupt the file.
*/
virtual bool save();
/*!
* Returns a pointer to the ID3v1 tag of the file.
*
* If \a create is false (the default) this will return a null pointer
* If \a create is false (the default) this may return a null pointer
* if there is no valid ID3v1 tag. If \a create is true it will create
* an ID3v1 tag if one does not exist. If there is already an APE tag, the
* new ID3v1 tag will be placed after it.
* an ID3v1 tag if one does not exist and returns a valid pointer.
*
* \note The Tag <b>is still</b> owned by the APE::File and should not be
* \note This may return a valid pointer regardless of whether or not the
* file on disk has an ID3v1 tag. Use hasID3v1Tag() to check if the file
* on disk actually has an ID3v1 tag.
*
* \note The Tag <b>is still</b> owned by the MPEG::File and should not be
* deleted by the user. It will be deleted when the file (object) is
* destroyed.
*
* \see hasID3v1Tag()
*/
ID3v1::Tag *ID3v1Tag(bool create = false);
/*!
* Returns a pointer to the APE tag of the file.
*
* If \a create is false (the default) this will return a null pointer
* If \a create is false (the default) this may return a null pointer
* if there is no valid APE tag. If \a create is true it will create
* a APE tag if one does not exist.
* an APE tag if one does not exist and returns a valid pointer.
*
* \note The Tag <b>is still</b> owned by the APE::File and should not be
* \note This may return a valid pointer regardless of whether or not the
* file on disk has an APE tag. Use hasAPETag() to check if the file
* on disk actually has an APE tag.
*
* \note The Tag <b>is still</b> owned by the MPEG::File and should not be
* deleted by the user. It will be deleted when the file (object) is
* destroyed.
*
* \see hasAPETag()
*/
APE::Tag *APETag(bool create = false);
@@ -161,14 +200,28 @@ namespace TagLib {
*/
void strip(int tags = AllTags);
/*!
* Returns whether or not the file on disk actually has an APE tag.
*
* \see APETag()
*/
bool hasAPETag() const;
/*!
* Returns whether or not the file on disk actually has an ID3v1 tag.
*
* \see ID3v1Tag()
*/
bool hasID3v1Tag() const;
private:
File(const File &);
File &operator=(const File &);
void read(bool readProperties, Properties::ReadStyle propertiesStyle);
void scan();
long findID3v1();
void read(bool readProperties);
long findAPE();
long findID3v1();
long findID3v2();
class FilePrivate;
FilePrivate *d;

View File

@@ -24,7 +24,7 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <ostream>
#include <iostream>
#include <bitset>
#include <tstring.h>
@@ -35,7 +35,7 @@
using namespace TagLib;
using namespace APE;
class Footer::FooterPrivate
class APE::Footer::FooterPrivate
{
public:
FooterPrivate() : version(0),
@@ -64,12 +64,12 @@ public:
// static members
////////////////////////////////////////////////////////////////////////////////
TagLib::uint Footer::size()
TagLib::uint APE::Footer::size()
{
return FooterPrivate::size;
}
ByteVector Footer::fileIdentifier()
ByteVector APE::Footer::fileIdentifier()
{
return ByteVector::fromCString("APETAGEX");
}
@@ -78,63 +78,63 @@ ByteVector Footer::fileIdentifier()
// public members
////////////////////////////////////////////////////////////////////////////////
Footer::Footer()
APE::Footer::Footer()
{
d = new FooterPrivate;
}
Footer::Footer(const ByteVector &data)
APE::Footer::Footer(const ByteVector &data)
{
d = new FooterPrivate;
parse(data);
}
Footer::~Footer()
APE::Footer::~Footer()
{
delete d;
}
TagLib::uint Footer::version() const
TagLib::uint APE::Footer::version() const
{
return d->version;
}
bool Footer::headerPresent() const
bool APE::Footer::headerPresent() const
{
return d->headerPresent;
}
bool Footer::footerPresent() const
bool APE::Footer::footerPresent() const
{
return d->footerPresent;
}
bool Footer::isHeader() const
bool APE::Footer::isHeader() const
{
return d->isHeader;
}
void Footer::setHeaderPresent(bool b) const
void APE::Footer::setHeaderPresent(bool b) const
{
d->headerPresent = b;
}
TagLib::uint Footer::itemCount() const
TagLib::uint APE::Footer::itemCount() const
{
return d->itemCount;
}
void Footer::setItemCount(uint s)
void APE::Footer::setItemCount(uint s)
{
d->itemCount = s;
}
TagLib::uint Footer::tagSize() const
TagLib::uint APE::Footer::tagSize() const
{
return d->tagSize;
}
TagLib::uint Footer::completeTagSize() const
TagLib::uint APE::Footer::completeTagSize() const
{
if(d->headerPresent)
return d->tagSize + d->size;
@@ -142,22 +142,22 @@ TagLib::uint Footer::completeTagSize() const
return d->tagSize;
}
void Footer::setTagSize(uint s)
void APE::Footer::setTagSize(uint s)
{
d->tagSize = s;
}
void Footer::setData(const ByteVector &data)
void APE::Footer::setData(const ByteVector &data)
{
parse(data);
}
ByteVector Footer::renderFooter() const
ByteVector APE::Footer::renderFooter() const
{
return render(false);
}
ByteVector Footer::renderHeader() const
ByteVector APE::Footer::renderHeader() const
{
if (!d->headerPresent) return ByteVector();
@@ -168,7 +168,7 @@ ByteVector Footer::renderHeader() const
// protected members
////////////////////////////////////////////////////////////////////////////////
void Footer::parse(const ByteVector &data)
void APE::Footer::parse(const ByteVector &data)
{
if(data.size() < size())
return;
@@ -177,19 +177,19 @@ void Footer::parse(const ByteVector &data)
// Read the version number
d->version = data.mid(8, 4).toUInt(false);
d->version = data.toUInt(8, false);
// Read the tag size
d->tagSize = data.mid(12, 4).toUInt(false);
d->tagSize = data.toUInt(12, false);
// Read the item count
d->itemCount = data.mid(16, 4).toUInt(false);
d->itemCount = data.toUInt(16, false);
// Read the flags
std::bitset<32> flags(TAGLIB_CONSTRUCT_BITSET(data.mid(20, 4).toUInt(false)));
std::bitset<32> flags(TAGLIB_CONSTRUCT_BITSET(data.toUInt(20, false)));
d->headerPresent = flags[31];
d->footerPresent = !flags[30];
@@ -197,7 +197,7 @@ void Footer::parse(const ByteVector &data)
}
ByteVector Footer::render(bool isHeader) const
ByteVector APE::Footer::render(bool isHeader) const
{
ByteVector v;

View File

@@ -37,7 +37,7 @@ namespace TagLib {
/*!
* This class implements APE footers (and headers). It attempts to follow, both
* semantically and programatically, the structure specified in
* semantically and programmatically, the structure specified in
* the APE v2.0 standard. The API is based on the properties of APE footer and
* headers specified there.
*/

View File

@@ -62,6 +62,18 @@ APE::Item::Item(const String &key, const StringList &values)
d->text = values;
}
APE::Item::Item(const String &key, const ByteVector &value, bool binary)
{
d = new ItemPrivate;
d->key = key;
if(binary) {
d->type = Binary;
d->value = value;
}
else
d->text.append(value);
}
APE::Item::Item(const Item &item)
{
d = new ItemPrivate(*item.d);
@@ -104,6 +116,18 @@ String APE::Item::key() const
return d->key;
}
ByteVector APE::Item::binaryData() const
{
return d->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
@@ -114,32 +138,59 @@ ByteVector APE::Item::value() const
void APE::Item::setKey(const String &key)
{
d->key = key;
d->key = key;
}
void APE::Item::setValue(const String &value)
{
d->text = value;
d->type = Text;
d->text = value;
d->value.clear();
}
void APE::Item::setValues(const StringList &value)
{
d->text = value;
d->type = Text;
d->text = value;
d->value.clear();
}
void APE::Item::appendValue(const String &value)
{
d->text.append(value);
d->type = Text;
d->text.append(value);
d->value.clear();
}
void APE::Item::appendValues(const StringList &values)
{
d->text.append(values);
d->type = Text;
d->text.append(values);
d->value.clear();
}
int APE::Item::size() const
{
return 8 + d->key.size() + 1 + d->value.size();
// SFB: Why is d->key.size() used when size() returns the length in UniChars and not UTF-8?
int result = 8 + d->key.size() /* d->key.data(String::UTF8).size() */ + 1;
switch (d->type) {
case Text:
if(d->text.size()) {
StringList::ConstIterator it = d->text.begin();
result += it->data(String::UTF8).size();
it++;
for(; it != d->text.end(); ++it)
result += 1 + it->data(String::UTF8).size();
}
break;
case Binary:
case Locator:
result += d->value.size();
break;
}
return result;
}
StringList APE::Item::toStringList() const
@@ -154,19 +205,22 @@ StringList APE::Item::values() const
String APE::Item::toString() const
{
return isEmpty() ? String::null : d->text.front();
if(d->type == Text && !isEmpty())
return d->text.front();
else
return String::null;
}
bool APE::Item::isEmpty() const
{
switch(d->type) {
case Text:
case Binary:
if(d->text.isEmpty())
return true;
if(d->text.size() == 1 && d->text.front().isEmpty())
return true;
return false;
case Binary:
case Locator:
return d->value.isEmpty();
default:
@@ -183,18 +237,20 @@ void APE::Item::parse(const ByteVector &data)
return;
}
uint valueLength = data.mid(0, 4).toUInt(false);
uint flags = data.mid(4, 4).toUInt(false);
const uint valueLength = data.toUInt(0, false);
const uint flags = data.toUInt(4, false);
d->key = String(data.mid(8), String::UTF8);
d->value = data.mid(8 + d->key.size() + 1, valueLength);
const ByteVector value = data.mid(8 + d->key.size() + 1, valueLength);
setReadOnly(flags & 1);
setType(ItemTypes((flags >> 1) & 3));
if(int(d->type) < 2)
d->text = StringList(ByteVectorList::split(d->value, '\0'), String::UTF8);
if(Text == d->type)
d->text = StringList(ByteVectorList::split(value, '\0'), String::UTF8);
else
d->value = value;
}
ByteVector APE::Item::render() const

View File

@@ -59,16 +59,22 @@ namespace TagLib {
Item();
/*!
* Constructs an item with \a key and \a value.
* 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);
/*!
* Constructs an item with \a key and \a values.
* Constructs a text item with \a key and \a values.
*/
Item(const String &key, const StringList &values);
/*!
* Constructs an item with \a key and \a value.
* If \a binary is true a Binary item will be created, otherwise \a value will be interpreted as text
*/
Item(const String &key, const ByteVector &value, bool binary);
/*!
* Construct an item as a copy of \a item.
*/
@@ -91,12 +97,20 @@ namespace TagLib {
/*!
* Returns the binary value.
*
* \deprecated This will be removed in the next binary incompatible version
* as it is not kept in sync with the things that are set using setValue()
* and friends.
* If the item type is not \a Binary, always returns an empty ByteVector.
*/
ByteVector binaryData() const;
/*!
* Set the binary value to \a value
* The item's type will also be set to \a Binary
*/
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.
@@ -104,14 +118,14 @@ namespace TagLib {
void setKey(const String &key);
/*!
* Sets the value of the item to \a value and clears any previous contents.
* Sets the text value of the item to \a value and clears any previous contents.
*
* \see toString()
*/
void setValue(const String &value);
/*!
* Sets the value of the item to the list of values in \a value and clears
* Sets the text value of the item to the list of values in \a value and clears
* any previous contents.
*
* \see toStringList()
@@ -119,14 +133,14 @@ namespace TagLib {
void setValues(const StringList &values);
/*!
* Appends \a value to create (or extend) the current list of values.
* Appends \a value to create (or extend) the current list of text values.
*
* \see toString()
*/
void appendValue(const String &value);
/*!
* Appends \a values to extend the current list of values.
* Appends \a values to extend the current list of text values.
*
* \see toStringList()
*/
@@ -138,19 +152,20 @@ namespace TagLib {
int size() const;
/*!
* Returns the value as a single string. In case of multiple strings,
* the first is returned.
* Returns the value as a single string. In case of multiple strings,
* the first is returned. If the data type is not \a Text, always returns
* an empty String.
*/
String toString() const;
/*!
* \deprecated
* \see values
*/
#ifndef DO_NOT_DOCUMENT
/* Remove in next binary incompatible release */
StringList toStringList() const;
#endif
/*!
* Returns the list of values.
* Returns the list of text values. If the data type is not \a Text, always
* returns an empty StringList.
*/
StringList values() const;

View File

@@ -33,21 +33,22 @@
#include "id3v2tag.h"
#include "apeproperties.h"
#include "apefile.h"
#include "apetag.h"
#include "apefooter.h"
using namespace TagLib;
class APE::Properties::PropertiesPrivate
{
public:
PropertiesPrivate(File *file, long streamLength) :
PropertiesPrivate() :
length(0),
bitrate(0),
sampleRate(0),
channels(0),
version(0),
bitsPerSample(0),
file(file),
streamLength(streamLength) {}
sampleFrames(0) {}
int length;
int bitrate;
@@ -55,18 +56,25 @@ public:
int channels;
int version;
int bitsPerSample;
File *file;
long streamLength;
uint sampleFrames;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
APE::Properties::Properties(File *file, ReadStyle style) : AudioProperties(style)
APE::Properties::Properties(File *, ReadStyle style) :
AudioProperties(style),
d(new PropertiesPrivate())
{
d = new PropertiesPrivate(file, file->length());
read();
debug("APE::Properties::Properties() -- This constructor is no longer used.");
}
APE::Properties::Properties(File *file, long streamLength, ReadStyle style) :
AudioProperties(style),
d(new PropertiesPrivate())
{
read(file, streamLength);
}
APE::Properties::~Properties()
@@ -75,6 +83,16 @@ APE::Properties::~Properties()
}
int APE::Properties::length() const
{
return lengthInSeconds();
}
int APE::Properties::lengthInSeconds() const
{
return d->length / 1000;
}
int APE::Properties::lengthInMilliseconds() const
{
return d->length;
}
@@ -104,109 +122,109 @@ int APE::Properties::bitsPerSample() const
return d->bitsPerSample;
}
TagLib::uint APE::Properties::sampleFrames() const
{
return d->sampleFrames;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void APE::Properties::read()
namespace
{
// First we are searching the descriptor
long offset = findDescriptor();
if(offset < 0)
return;
inline int headerVersion(const ByteVector &header)
{
if(header.size() < 6 || !header.startsWith("MAC "))
return -1;
// Then we read the header common for all versions of APE
d->file->seek(offset);
ByteVector commonHeader=d->file->readBlock(6);
if(!commonHeader.startsWith("MAC "))
return;
d->version = commonHeader.mid(4).toUInt(false);
if(d->version >= 3980) {
analyzeCurrent();
}
else {
analyzeOld();
return header.toUShort(4, false);
}
}
long APE::Properties::findDescriptor()
void APE::Properties::read(File *file, long streamLength)
{
long ID3v2Location = findID3v2();
long ID3v2OriginalSize = 0;
bool hasID3v2 = false;
if(ID3v2Location >= 0) {
ID3v2::Tag tag(d->file, ID3v2Location, 0);
ID3v2OriginalSize = tag.header()->completeTagSize();
if(tag.header()->tagSize() > 0)
hasID3v2 = true;
// First, we assume that the file pointer is set at the first descriptor.
long offset = file->tell();
int version = headerVersion(file->readBlock(6));
// Next, we look for the descriptor.
if(version < 0) {
offset = file->find("MAC ", offset);
file->seek(offset);
version = headerVersion(file->readBlock(6));
}
long offset = 0;
if(hasID3v2)
offset = d->file->find("MAC ", ID3v2Location + ID3v2OriginalSize);
if(version < 0) {
debug("APE::Properties::read() -- APE descriptor not found");
return;
}
d->version = version;
if(d->version >= 3980)
analyzeCurrent(file);
else
offset = d->file->find("MAC ");
analyzeOld(file);
if(offset < 0) {
debug("APE::Properties::findDescriptor() -- APE descriptor not found");
return -1;
if(d->sampleFrames > 0 && d->sampleRate > 0) {
const double length = d->sampleFrames * 1000.0 / d->sampleRate;
d->length = static_cast<int>(length + 0.5);
d->bitrate = static_cast<int>(streamLength * 8.0 / length + 0.5);
}
return offset;
}
long APE::Properties::findID3v2()
{
if(!d->file->isValid())
return -1;
d->file->seek(0);
if(d->file->readBlock(3) == ID3v2::Header::fileIdentifier())
return 0;
return -1;
}
void APE::Properties::analyzeCurrent()
void APE::Properties::analyzeCurrent(File *file)
{
// Read the descriptor
d->file->seek(2, File::Current);
ByteVector descriptor = d->file->readBlock(44);
uint descriptorBytes = descriptor.mid(0,4).toUInt(false);
file->seek(2, File::Current);
const ByteVector descriptor = file->readBlock(44);
if(descriptor.size() < 44) {
debug("APE::Properties::analyzeCurrent() -- descriptor is too short.");
return;
}
if ((descriptorBytes - 52) > 0)
d->file->seek(descriptorBytes - 52, File::Current);
const uint descriptorBytes = descriptor.toUInt(0, false);
if((descriptorBytes - 52) > 0)
file->seek(descriptorBytes - 52, File::Current);
// Read the header
ByteVector header = d->file->readBlock(24);
const ByteVector header = file->readBlock(24);
if(header.size() < 24) {
debug("APE::Properties::analyzeCurrent() -- MAC header is too short.");
return;
}
// Get the APE info
d->channels = header.mid(18, 2).toShort(false);
d->sampleRate = header.mid(20, 4).toUInt(false);
d->bitsPerSample = header.mid(16, 2).toShort(false);
//d->compressionLevel =
d->channels = header.toShort(18, false);
d->sampleRate = header.toUInt(20, false);
d->bitsPerSample = header.toShort(16, false);
uint totalFrames = header.mid(12, 4).toUInt(false);
uint blocksPerFrame = header.mid(4, 4).toUInt(false);
uint finalFrameBlocks = header.mid(8, 4).toUInt(false);
uint totalBlocks = totalFrames > 0 ? (totalFrames - 1) * blocksPerFrame + finalFrameBlocks : 0;
d->length = totalBlocks / d->sampleRate;
d->bitrate = d->length > 0 ? ((d->streamLength * 8L) / d->length) / 1000 : 0;
const uint totalFrames = header.toUInt(12, false);
if(totalFrames == 0)
return;
const uint blocksPerFrame = header.toUInt(4, false);
const uint finalFrameBlocks = header.toUInt(8, false);
d->sampleFrames = (totalFrames - 1) * blocksPerFrame + finalFrameBlocks;
}
void APE::Properties::analyzeOld()
void APE::Properties::analyzeOld(File *file)
{
ByteVector header = d->file->readBlock(26);
uint totalFrames = header.mid(18, 4).toUInt(false);
const ByteVector header = file->readBlock(26);
if(header.size() < 26) {
debug("APE::Properties::analyzeOld() -- MAC header is too short.");
return;
}
const uint totalFrames = header.toUInt(18, false);
// Fail on 0 length APE files (catches non-finalized APE files)
if(totalFrames == 0)
return;
short compressionLevel = header.mid(0, 2).toShort(false);
const short compressionLevel = header.toShort(0, false);
uint blocksPerFrame;
if(d->version >= 3950)
blocksPerFrame = 73728 * 4;
@@ -214,11 +232,21 @@ void APE::Properties::analyzeOld()
blocksPerFrame = 73728;
else
blocksPerFrame = 9216;
d->channels = header.mid(4, 2).toShort(false);
d->sampleRate = header.mid(6, 4).toUInt(false);
uint finalFrameBlocks = header.mid(22, 4).toUInt(false);
uint totalBlocks = totalFrames > 0 ? (totalFrames - 1) * blocksPerFrame + finalFrameBlocks : 0;
d->length = totalBlocks / d->sampleRate;
d->bitrate = d->length > 0 ? ((d->streamLength * 8L) / d->length) / 1000 : 0;
}
// Get the APE info
d->channels = header.toShort(4, false);
d->sampleRate = header.toUInt(6, false);
const uint finalFrameBlocks = header.toUInt(22, false);
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.");
return;
}
d->bitsPerSample = fmt.toShort(26, false);
}

View File

@@ -51,27 +51,75 @@ namespace TagLib {
public:
/*!
* Create an instance of APE::Properties with the data read from the
* ByteVector \a data.
* APE::File \a file.
*
* \deprecated
*/
Properties(File *f, ReadStyle style = Average);
Properties(File *file, ReadStyle style = Average);
/*!
* Create an instance of APE::Properties with the data read from the
* APE::File \a file.
*/
Properties(File *file, long streamLength, ReadStyle style = Average);
/*!
* Destroys this APE::Properties instance.
*/
virtual ~Properties();
// Reimplementations.
/*!
* Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second.
*
* \note This method is just an alias of lengthInSeconds().
*
* \deprecated
*/
virtual int length() const;
/*!
* Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second.
*
* \see lengthInMilliseconds()
*/
// BIC: make virtual
int lengthInSeconds() const;
/*!
* Returns the length of the file in milliseconds.
*
* \see lengthInSeconds()
*/
// BIC: make virtual
int lengthInMilliseconds() const;
/*!
* Returns the average bit rate of the file in kb/s.
*/
virtual int bitrate() const;
/*!
* Returns the sample rate in Hz.
*/
virtual int sampleRate() const;
/*!
* Returns the number of audio channels.
*/
virtual int channels() const;
/*!
* Returns number of bits per sample.
* Returns the number of bits per audio sample.
*/
int bitsPerSample() const;
/*!
* Returns the total number of audio samples in file.
*/
uint sampleFrames() const;
/*!
* Returns APE version.
*/
@@ -81,13 +129,10 @@ namespace TagLib {
Properties(const Properties &);
Properties &operator=(const Properties &);
void read();
void read(File *file, long streamLength);
long findDescriptor();
long findID3v2();
void analyzeCurrent();
void analyzeOld();
void analyzeCurrent(File *file);
void analyzeOld(File *file);
class PropertiesPrivate;
PropertiesPrivate *d;

View File

@@ -34,6 +34,7 @@
#include <tfile.h>
#include <tstring.h>
#include <tmap.h>
#include <tpropertymap.h>
#include "apetag.h"
#include "apefooter.h"
@@ -45,11 +46,12 @@ using namespace APE;
class APE::Tag::TagPrivate
{
public:
TagPrivate() : file(0), footerLocation(-1), tagLength(0) {}
TagPrivate() :
file(0),
footerLocation(-1) {}
File *file;
TagLib::File *file;
long footerLocation;
long tagLength;
Footer footer;
@@ -60,14 +62,16 @@ public:
// public methods
////////////////////////////////////////////////////////////////////////////////
APE::Tag::Tag() : TagLib::Tag()
APE::Tag::Tag() :
TagLib::Tag(),
d(new TagPrivate())
{
d = new TagPrivate;
}
APE::Tag::Tag(File *file, long footerLocation) : TagLib::Tag()
APE::Tag::Tag(TagLib::File *file, long footerLocation) :
TagLib::Tag(),
d(new TagPrivate())
{
d = new TagPrivate;
d->file = file;
d->footerLocation = footerLocation;
@@ -88,35 +92,35 @@ String APE::Tag::title() const
{
if(d->itemListMap["TITLE"].isEmpty())
return String::null;
return d->itemListMap["TITLE"].toString();
return d->itemListMap["TITLE"].values().toString();
}
String APE::Tag::artist() const
{
if(d->itemListMap["ARTIST"].isEmpty())
return String::null;
return d->itemListMap["ARTIST"].toString();
return d->itemListMap["ARTIST"].values().toString();
}
String APE::Tag::album() const
{
if(d->itemListMap["ALBUM"].isEmpty())
return String::null;
return d->itemListMap["ALBUM"].toString();
return d->itemListMap["ALBUM"].values().toString();
}
String APE::Tag::comment() const
{
if(d->itemListMap["COMMENT"].isEmpty())
return String::null;
return d->itemListMap["COMMENT"].toString();
return d->itemListMap["COMMENT"].values().toString();
}
String APE::Tag::genre() const
{
if(d->itemListMap["GENRE"].isEmpty())
return String::null;
return d->itemListMap["GENRE"].toString();
return d->itemListMap["GENRE"].values().toString();
}
TagLib::uint APE::Tag::year() const
@@ -174,6 +178,103 @@ void APE::Tag::setTrack(uint i)
addValue("TRACK", String::number(i), true);
}
// conversions of tag keys between what we use in PropertyMap and what's usual
// for APE tags
static const TagLib::uint keyConversionsSize = 5; //usual, APE
static const char *keyConversions[][2] = {{"TRACKNUMBER", "TRACK" },
{"DATE", "YEAR" },
{"ALBUMARTIST", "ALBUM ARTIST"},
{"DISCNUMBER", "DISC" },
{"REMIXER", "MIXARTIST" }};
PropertyMap APE::Tag::properties() const
{
PropertyMap properties;
ItemListMap::ConstIterator it = itemListMap().begin();
for(; it != itemListMap().end(); ++it) {
String tagName = it->first.upper();
// if the item is Binary or Locator, or if the key is an invalid string,
// add to unsupportedData
if(it->second.type() != Item::Text || tagName.isNull())
properties.unsupportedData().append(it->first);
else {
// Some tags need to be handled specially
for(uint i = 0; i < keyConversionsSize; ++i)
if(tagName == keyConversions[i][1])
tagName = keyConversions[i][0];
properties[tagName].append(it->second.toStringList());
}
}
return properties;
}
void APE::Tag::removeUnsupportedProperties(const StringList &properties)
{
StringList::ConstIterator it = properties.begin();
for(; it != properties.end(); ++it)
removeItem(*it);
}
PropertyMap APE::Tag::setProperties(const PropertyMap &origProps)
{
PropertyMap properties(origProps); // make a local copy that can be modified
// see comment in properties()
for(uint i = 0; i < keyConversionsSize; ++i)
if(properties.contains(keyConversions[i][0])) {
properties.insert(keyConversions[i][1], properties[keyConversions[i][0]]);
properties.erase(keyConversions[i][0]);
}
// first check if tags need to be removed completely
StringList toRemove;
ItemListMap::ConstIterator remIt = itemListMap().begin();
for(; remIt != itemListMap().end(); ++remIt) {
String key = remIt->first.upper();
// only remove if a) key is valid, b) type is text, c) key not contained in new properties
if(!key.isNull() && remIt->second.type() == APE::Item::Text && !properties.contains(key))
toRemove.append(remIt->first);
}
for(StringList::ConstIterator removeIt = toRemove.begin(); removeIt != toRemove.end(); removeIt++)
removeItem(*removeIt);
// now sync in the "forward direction"
PropertyMap::ConstIterator it = properties.begin();
PropertyMap invalid;
for(; it != properties.end(); ++it) {
const String &tagName = it->first;
if(!checkKey(tagName))
invalid.insert(it->first, it->second);
else if(!(itemListMap().contains(tagName)) || !(itemListMap()[tagName].values() == it->second)) {
if(it->second.size() == 0)
removeItem(tagName);
else {
StringList::ConstIterator valueIt = it->second.begin();
addValue(tagName, *valueIt, true);
++valueIt;
for(; valueIt != it->second.end(); ++valueIt)
addValue(tagName, *valueIt, false);
}
}
}
return invalid;
}
bool APE::Tag::checkKey(const String &key)
{
if(key.size() < 2 || key.size() > 16)
return false;
for(String::ConstIterator it = key.begin(); it != key.end(); it++)
// only allow printable ASCII including space (32..127)
if (*it < 32 || *it >= 128)
return false;
String upperKey = key.upper();
if (upperKey=="ID3" || upperKey=="TAG" || upperKey=="OGGS" || upperKey=="MP+")
return false;
return true;
}
APE::Footer *APE::Tag::footer() const
{
return &d->footer;
@@ -186,26 +287,38 @@ const APE::ItemListMap& APE::Tag::itemListMap() const
void APE::Tag::removeItem(const String &key)
{
Map<const String, Item>::Iterator it = d->itemListMap.find(key.upper());
if(it != d->itemListMap.end())
d->itemListMap.erase(it);
d->itemListMap.erase(key.upper());
}
void APE::Tag::addValue(const String &key, const String &value, bool replace)
{
if(replace)
removeItem(key);
if(!value.isEmpty()) {
if(d->itemListMap.contains(key) || !replace)
d->itemListMap[key.upper()].appendValue(value);
if(!key.isEmpty() && !value.isEmpty()) {
if(!replace && d->itemListMap.contains(key)) {
// Text items may contain more than one value
if(APE::Item::Text == d->itemListMap.begin()->second.type())
d->itemListMap[key.upper()].appendValue(value);
// Binary or locator items may have only one value
else
setItem(key, Item(key, value));
}
else
setItem(key, Item(key, value));
}
}
void APE::Tag::setData(const String &key, const ByteVector &value)
{
removeItem(key);
if(!key.isEmpty() && !value.isEmpty())
setItem(key, Item(key, value, true));
}
void APE::Tag::setItem(const String &key, const Item &item)
{
d->itemListMap.insert(key.upper(), item);
if(!key.isEmpty())
d->itemListMap.insert(key.upper(), item);
}
bool APE::Tag::isEmpty() const
@@ -256,10 +369,13 @@ ByteVector APE::Tag::render() const
void APE::Tag::parse(const ByteVector &data)
{
uint pos = 0;
// 11 bytes is the minimum size for an APE item
if(data.size() < 11)
return;
uint pos = 0;
for(uint i = 0; i < d->footer.itemCount() && pos <= data.size() - 11; i++) {
APE::Item item;
item.parse(data.mid(pos));

View File

@@ -103,6 +103,37 @@ namespace TagLib {
virtual void setYear(uint i);
virtual void setTrack(uint i);
/*!
* Implements the unified tag dictionary interface -- export function.
* APE tags are perfectly compatible with the dictionary interface because they
* support both arbitrary tag names and multiple values. Currently only
* APE items of type *Text* are handled by the dictionary interface; all *Binary*
* and *Locator* items will be put into the unsupportedData list and can be
* deleted on request using removeUnsupportedProperties(). The same happens
* to Text items if their key is invalid for PropertyMap (which should actually
* never happen).
*
* The only conversion done by this export function is to rename the APE tags
* TRACK to TRACKNUMBER, YEAR to DATE, and ALBUM ARTIST to ALBUMARTIST, respectively,
* in order to be compliant with the names used in other formats.
*/
PropertyMap properties() const;
void removeUnsupportedProperties(const StringList &properties);
/*!
* Implements the unified tag dictionary interface -- import function. The same
* comments as for the export function apply; additionally note that the APE tag
* specification requires keys to have between 2 and 16 printable ASCII characters
* with the exception of the fixed strings "ID3", "TAG", "OGGS", and "MP+".
*/
PropertyMap setProperties(const PropertyMap &);
/*!
* Check if the given String is a valid APE tag key.
*/
static bool checkKey(const String&);
/*!
* Returns a pointer to the tag's footer.
*/
@@ -112,7 +143,7 @@ namespace TagLib {
* Returns a reference to the item list map. This is an ItemListMap of
* all of the items in the tag.
*
* This is the most powerfull structure for accessing the items of the tag.
* This is the most powerful structure for accessing the items of the tag.
*
* APE tags are case-insensitive, all keys in this map have been converted
* to upper case.
@@ -128,12 +159,19 @@ namespace TagLib {
void removeItem(const String &key);
/*!
* Adds to the item specified by \a key the data \a value. If \a replace
* Adds to the text item specified by \a key the data \a value. If \a replace
* is true, then all of the other values on the same key will be removed
* first.
* first. If a binary item exists for \a key it will be removed first.
*/
void addValue(const String &key, const String &value, bool replace = true);
/*!
* Set the binary data for the key specified by \a item to \a value
* This will convert the item to type \a Binary if it isn't already and
* all of the other values on the same key will be removed.
*/
void setData(const String &key, const ByteVector &value);
/*!
* Sets the \a key item to the value of \a item. If an item with the \a key is already
* present, it will be replaced.

View File

@@ -23,14 +23,13 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <taglib.h>
#include <tdebug.h>
#include <trefcounter.h>
#include "asfattribute.h"
#include "asffile.h"
#include "asfutils.h"
using namespace TagLib;
@@ -184,23 +183,23 @@ String ASF::Attribute::parse(ASF::File &f, int kind)
d->pictureValue = Picture::fromInvalid();
// extended content descriptor
if(kind == 0) {
nameLength = f.readWORD();
name = f.readString(nameLength);
d->type = ASF::Attribute::AttributeTypes(f.readWORD());
size = f.readWORD();
nameLength = readWORD(&f);
name = readString(&f, nameLength);
d->type = ASF::Attribute::AttributeTypes(readWORD(&f));
size = readWORD(&f);
}
// metadata & metadata library
else {
int temp = f.readWORD();
int temp = readWORD(&f);
// metadata library
if(kind == 2) {
d->language = temp;
}
d->stream = f.readWORD();
nameLength = f.readWORD();
d->type = ASF::Attribute::AttributeTypes(f.readWORD());
size = f.readDWORD();
name = f.readString(nameLength);
d->stream = readWORD(&f);
nameLength = readWORD(&f);
d->type = ASF::Attribute::AttributeTypes(readWORD(&f));
size = readDWORD(&f);
name = readString(&f, nameLength);
}
if(kind != 2 && size > 65535) {
@@ -209,28 +208,28 @@ String ASF::Attribute::parse(ASF::File &f, int kind)
switch(d->type) {
case WordType:
d->shortValue = f.readWORD();
d->shortValue = readWORD(&f);
break;
case BoolType:
if(kind == 0) {
d->boolValue = f.readDWORD() == 1;
d->boolValue = (readDWORD(&f) == 1);
}
else {
d->boolValue = f.readWORD() == 1;
d->boolValue = (readWORD(&f) == 1);
}
break;
case DWordType:
d->intValue = f.readDWORD();
d->intValue = readDWORD(&f);
break;
case QWordType:
d->longLongValue = f.readQWORD();
d->longLongValue = readQWORD(&f);
break;
case UnicodeType:
d->stringValue = f.readString(size);
d->stringValue = readString(&f, size);
break;
case BytesType:
@@ -298,7 +297,7 @@ ByteVector ASF::Attribute::render(const String &name, int kind) const
break;
case UnicodeType:
data.append(File::renderString(d->stringValue));
data.append(renderString(d->stringValue));
break;
case BytesType:
@@ -312,13 +311,13 @@ ByteVector ASF::Attribute::render(const String &name, int kind) const
}
if(kind == 0) {
data = File::renderString(name, true) +
data = renderString(name, true) +
ByteVector::fromShort((int)d->type, false) +
ByteVector::fromShort(data.size(), false) +
data;
}
else {
ByteVector nameData = File::renderString(name);
ByteVector nameData = renderString(name);
data = ByteVector::fromShort(kind == 2 ? d->language : 0, false) +
ByteVector::fromShort(d->stream, false) +
ByteVector::fromShort(nameData.size(), false) +

View File

@@ -70,7 +70,7 @@ namespace TagLib
/*!
* Constructs an attribute with \a key and a BytesType \a value.
*/
Attribute(const ByteVector &value);
Attribute(const ByteVector &value);
/*!
* Constructs an attribute with \a key and a Picture \a value.

View File

@@ -23,22 +23,32 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <tdebug.h>
#include <tbytevectorlist.h>
#include <tpropertymap.h>
#include <tstring.h>
#include "asffile.h"
#include "asftag.h"
#include "asfproperties.h"
#include "asfutils.h"
using namespace TagLib;
class ASF::File::FilePrivate
{
public:
class BaseObject;
class UnknownObject;
class FilePropertiesObject;
class StreamPropertiesObject;
class ContentDescriptionObject;
class ExtendedContentDescriptionObject;
class HeaderExtensionObject;
class CodecListObject;
class MetadataObject;
class MetadataLibraryObject;
FilePrivate():
size(0),
tag(0),
@@ -47,180 +57,227 @@ public:
extendedContentDescriptionObject(0),
headerExtensionObject(0),
metadataObject(0),
metadataLibraryObject(0) {}
metadataLibraryObject(0)
{
objects.setAutoDelete(true);
}
~FilePrivate()
{
delete tag;
delete properties;
}
unsigned long long size;
ASF::Tag *tag;
ASF::Properties *properties;
List<ASF::File::BaseObject *> objects;
ASF::File::ContentDescriptionObject *contentDescriptionObject;
ASF::File::ExtendedContentDescriptionObject *extendedContentDescriptionObject;
ASF::File::HeaderExtensionObject *headerExtensionObject;
ASF::File::MetadataObject *metadataObject;
ASF::File::MetadataLibraryObject *metadataLibraryObject;
List<BaseObject *> objects;
ContentDescriptionObject *contentDescriptionObject;
ExtendedContentDescriptionObject *extendedContentDescriptionObject;
HeaderExtensionObject *headerExtensionObject;
MetadataObject *metadataObject;
MetadataLibraryObject *metadataLibraryObject;
};
static ByteVector headerGuid("\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
static ByteVector filePropertiesGuid("\xA1\xDC\xAB\x8C\x47\xA9\xCF\x11\x8E\xE4\x00\xC0\x0C\x20\x53\x65", 16);
static ByteVector streamPropertiesGuid("\x91\x07\xDC\xB7\xB7\xA9\xCF\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65", 16);
static ByteVector contentDescriptionGuid("\x33\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
static ByteVector extendedContentDescriptionGuid("\x40\xA4\xD0\xD2\x07\xE3\xD2\x11\x97\xF0\x00\xA0\xC9\x5E\xA8\x50", 16);
static ByteVector headerExtensionGuid("\xb5\x03\xbf_.\xa9\xcf\x11\x8e\xe3\x00\xc0\x0c Se", 16);
static ByteVector metadataGuid("\xEA\xCB\xF8\xC5\xAF[wH\204g\xAA\214D\xFAL\xCA", 16);
static ByteVector metadataLibraryGuid("\224\034#D\230\224\321I\241A\x1d\x13NEpT", 16);
static ByteVector contentEncryptionGuid("\xFB\xB3\x11\x22\x23\xBD\xD2\x11\xB4\xB7\x00\xA0\xC9\x55\xFC\x6E", 16);
static ByteVector extendedContentEncryptionGuid("\x14\xE6\x8A\x29\x22\x26 \x17\x4C\xB9\x35\xDA\xE0\x7E\xE9\x28\x9C", 16);
static ByteVector advancedContentEncryptionGuid("\xB6\x9B\x07\x7A\xA4\xDA\x12\x4E\xA5\xCA\x91\xD3\x8D\xC1\x1A\x8D", 16);
namespace
{
const ByteVector headerGuid("\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
const ByteVector filePropertiesGuid("\xA1\xDC\xAB\x8C\x47\xA9\xCF\x11\x8E\xE4\x00\xC0\x0C\x20\x53\x65", 16);
const ByteVector streamPropertiesGuid("\x91\x07\xDC\xB7\xB7\xA9\xCF\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65", 16);
const ByteVector contentDescriptionGuid("\x33\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
const ByteVector extendedContentDescriptionGuid("\x40\xA4\xD0\xD2\x07\xE3\xD2\x11\x97\xF0\x00\xA0\xC9\x5E\xA8\x50", 16);
const ByteVector headerExtensionGuid("\xb5\x03\xbf_.\xa9\xcf\x11\x8e\xe3\x00\xc0\x0c Se", 16);
const ByteVector metadataGuid("\xEA\xCB\xF8\xC5\xAF[wH\204g\xAA\214D\xFAL\xCA", 16);
const ByteVector metadataLibraryGuid("\224\034#D\230\224\321I\241A\x1d\x13NEpT", 16);
const ByteVector codecListGuid("\x40\x52\xd1\x86\x1d\x31\xd0\x11\xa3\xa4\x00\xa0\xc9\x03\x48\xf6", 16);
const ByteVector contentEncryptionGuid("\xFB\xB3\x11\x22\x23\xBD\xD2\x11\xB4\xB7\x00\xA0\xC9\x55\xFC\x6E", 16);
const ByteVector extendedContentEncryptionGuid("\x14\xE6\x8A\x29\x22\x26 \x17\x4C\xB9\x35\xDA\xE0\x7E\xE9\x28\x9C", 16);
const ByteVector advancedContentEncryptionGuid("\xB6\x9B\x07\x7A\xA4\xDA\x12\x4E\xA5\xCA\x91\xD3\x8D\xC1\x1A\x8D", 16);
}
class ASF::File::BaseObject
class ASF::File::FilePrivate::BaseObject
{
public:
ByteVector data;
virtual ~BaseObject() {}
virtual ByteVector guid() = 0;
virtual ByteVector guid() const = 0;
virtual void parse(ASF::File *file, unsigned int size);
virtual ByteVector render(ASF::File *file);
};
class ASF::File::UnknownObject : public ASF::File::BaseObject
class ASF::File::FilePrivate::UnknownObject : public ASF::File::FilePrivate::BaseObject
{
ByteVector myGuid;
public:
UnknownObject(const ByteVector &guid);
ByteVector guid();
ByteVector guid() const;
};
class ASF::File::FilePropertiesObject : public ASF::File::BaseObject
class ASF::File::FilePrivate::FilePropertiesObject : public ASF::File::FilePrivate::BaseObject
{
public:
ByteVector guid();
ByteVector guid() const;
void parse(ASF::File *file, uint size);
};
class ASF::File::StreamPropertiesObject : public ASF::File::BaseObject
class ASF::File::FilePrivate::StreamPropertiesObject : public ASF::File::FilePrivate::BaseObject
{
public:
ByteVector guid();
ByteVector guid() const;
void parse(ASF::File *file, uint size);
};
class ASF::File::ContentDescriptionObject : public ASF::File::BaseObject
class ASF::File::FilePrivate::ContentDescriptionObject : public ASF::File::FilePrivate::BaseObject
{
public:
ByteVector guid();
ByteVector guid() const;
void parse(ASF::File *file, uint size);
ByteVector render(ASF::File *file);
};
class ASF::File::ExtendedContentDescriptionObject : public ASF::File::BaseObject
class ASF::File::FilePrivate::ExtendedContentDescriptionObject : public ASF::File::FilePrivate::BaseObject
{
public:
ByteVectorList attributeData;
ByteVector guid();
ByteVector guid() const;
void parse(ASF::File *file, uint size);
ByteVector render(ASF::File *file);
};
class ASF::File::MetadataObject : public ASF::File::BaseObject
class ASF::File::FilePrivate::MetadataObject : public ASF::File::FilePrivate::BaseObject
{
public:
ByteVectorList attributeData;
ByteVector guid();
ByteVector guid() const;
void parse(ASF::File *file, uint size);
ByteVector render(ASF::File *file);
};
class ASF::File::MetadataLibraryObject : public ASF::File::BaseObject
class ASF::File::FilePrivate::MetadataLibraryObject : public ASF::File::FilePrivate::BaseObject
{
public:
ByteVectorList attributeData;
ByteVector guid();
ByteVector guid() const;
void parse(ASF::File *file, uint size);
ByteVector render(ASF::File *file);
};
class ASF::File::HeaderExtensionObject : public ASF::File::BaseObject
class ASF::File::FilePrivate::HeaderExtensionObject : public ASF::File::FilePrivate::BaseObject
{
public:
List<ASF::File::BaseObject *> objects;
ByteVector guid();
List<ASF::File::FilePrivate::BaseObject *> objects;
HeaderExtensionObject();
ByteVector guid() const;
void parse(ASF::File *file, uint size);
ByteVector render(ASF::File *file);
};
void ASF::File::BaseObject::parse(ASF::File *file, unsigned int size)
class ASF::File::FilePrivate::CodecListObject : public ASF::File::FilePrivate::BaseObject
{
public:
ByteVector guid() const;
void parse(ASF::File *file, uint size);
private:
enum CodecType
{
Video = 0x0001,
Audio = 0x0002,
Unknown = 0xFFFF
};
};
void ASF::File::FilePrivate::BaseObject::parse(ASF::File *file, unsigned int size)
{
data.clear();
if (size > 24 && size <= (unsigned int)(file->length()))
if(size > 24 && size <= (unsigned int)(file->length()))
data = file->readBlock(size - 24);
else
data = ByteVector::null;
}
ByteVector ASF::File::BaseObject::render(ASF::File * /*file*/)
ByteVector ASF::File::FilePrivate::BaseObject::render(ASF::File * /*file*/)
{
return guid() + ByteVector::fromLongLong(data.size() + 24, false) + data;
}
ASF::File::UnknownObject::UnknownObject(const ByteVector &guid) : myGuid(guid)
ASF::File::FilePrivate::UnknownObject::UnknownObject(const ByteVector &guid) : myGuid(guid)
{
}
ByteVector ASF::File::UnknownObject::guid()
ByteVector ASF::File::FilePrivate::UnknownObject::guid() const
{
return myGuid;
}
ByteVector ASF::File::FilePropertiesObject::guid()
ByteVector ASF::File::FilePrivate::FilePropertiesObject::guid() const
{
return filePropertiesGuid;
}
void ASF::File::FilePropertiesObject::parse(ASF::File *file, uint size)
void ASF::File::FilePrivate::FilePropertiesObject::parse(ASF::File *file, uint size)
{
BaseObject::parse(file, size);
file->d->properties->setLength((int)(data.mid(40, 8).toLongLong(false) / 10000000L - data.mid(56, 8).toLongLong(false) / 1000L));
if(data.size() < 64) {
debug("ASF::File::FilePrivate::FilePropertiesObject::parse() -- data is too short.");
return;
}
const long long duration = data.toLongLong(40, false);
const long long preroll = data.toLongLong(56, false);
file->d->properties->setLengthInMilliseconds(static_cast<int>(duration / 10000.0 - preroll + 0.5));
}
ByteVector ASF::File::StreamPropertiesObject::guid()
ByteVector ASF::File::FilePrivate::StreamPropertiesObject::guid() const
{
return streamPropertiesGuid;
}
void ASF::File::StreamPropertiesObject::parse(ASF::File *file, uint size)
void ASF::File::FilePrivate::StreamPropertiesObject::parse(ASF::File *file, uint size)
{
BaseObject::parse(file, size);
file->d->properties->setChannels(data.mid(56, 2).toShort(false));
file->d->properties->setSampleRate(data.mid(58, 4).toUInt(false));
file->d->properties->setBitrate(data.mid(62, 4).toUInt(false) * 8 / 1000);
if(data.size() < 70) {
debug("ASF::File::FilePrivate::StreamPropertiesObject::parse() -- data is too short.");
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));
}
ByteVector ASF::File::ContentDescriptionObject::guid()
ByteVector ASF::File::FilePrivate::ContentDescriptionObject::guid() const
{
return contentDescriptionGuid;
}
void ASF::File::ContentDescriptionObject::parse(ASF::File *file, uint /*size*/)
void ASF::File::FilePrivate::ContentDescriptionObject::parse(ASF::File *file, uint /*size*/)
{
file->d->contentDescriptionObject = this;
int titleLength = file->readWORD();
int artistLength = file->readWORD();
int copyrightLength = file->readWORD();
int commentLength = file->readWORD();
int ratingLength = file->readWORD();
file->d->tag->setTitle(file->readString(titleLength));
file->d->tag->setArtist(file->readString(artistLength));
file->d->tag->setCopyright(file->readString(copyrightLength));
file->d->tag->setComment(file->readString(commentLength));
file->d->tag->setRating(file->readString(ratingLength));
const int titleLength = readWORD(file);
const int artistLength = readWORD(file);
const int copyrightLength = readWORD(file);
const int commentLength = readWORD(file);
const int ratingLength = readWORD(file);
file->d->tag->setTitle(readString(file,titleLength));
file->d->tag->setArtist(readString(file,artistLength));
file->d->tag->setCopyright(readString(file,copyrightLength));
file->d->tag->setComment(readString(file,commentLength));
file->d->tag->setRating(readString(file,ratingLength));
}
ByteVector ASF::File::ContentDescriptionObject::render(ASF::File *file)
ByteVector ASF::File::FilePrivate::ContentDescriptionObject::render(ASF::File *file)
{
ByteVector v1 = file->renderString(file->d->tag->title());
ByteVector v2 = file->renderString(file->d->tag->artist());
ByteVector v3 = file->renderString(file->d->tag->copyright());
ByteVector v4 = file->renderString(file->d->tag->comment());
ByteVector v5 = file->renderString(file->d->tag->rating());
const ByteVector v1 = renderString(file->d->tag->title());
const ByteVector v2 = renderString(file->d->tag->artist());
const ByteVector v3 = renderString(file->d->tag->copyright());
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));
@@ -235,15 +292,15 @@ ByteVector ASF::File::ContentDescriptionObject::render(ASF::File *file)
return BaseObject::render(file);
}
ByteVector ASF::File::ExtendedContentDescriptionObject::guid()
ByteVector ASF::File::FilePrivate::ExtendedContentDescriptionObject::guid() const
{
return extendedContentDescriptionGuid;
}
void ASF::File::ExtendedContentDescriptionObject::parse(ASF::File *file, uint /*size*/)
void ASF::File::FilePrivate::ExtendedContentDescriptionObject::parse(ASF::File *file, uint /*size*/)
{
file->d->extendedContentDescriptionObject = this;
int count = file->readWORD();
int count = readWORD(file);
while(count--) {
ASF::Attribute attribute;
String name = attribute.parse(*file);
@@ -251,7 +308,7 @@ void ASF::File::ExtendedContentDescriptionObject::parse(ASF::File *file, uint /*
}
}
ByteVector ASF::File::ExtendedContentDescriptionObject::render(ASF::File *file)
ByteVector ASF::File::FilePrivate::ExtendedContentDescriptionObject::render(ASF::File *file)
{
data.clear();
data.append(ByteVector::fromShort(attributeData.size(), false));
@@ -259,15 +316,15 @@ ByteVector ASF::File::ExtendedContentDescriptionObject::render(ASF::File *file)
return BaseObject::render(file);
}
ByteVector ASF::File::MetadataObject::guid()
ByteVector ASF::File::FilePrivate::MetadataObject::guid() const
{
return metadataGuid;
}
void ASF::File::MetadataObject::parse(ASF::File *file, uint /*size*/)
void ASF::File::FilePrivate::MetadataObject::parse(ASF::File *file, uint /*size*/)
{
file->d->metadataObject = this;
int count = file->readWORD();
int count = readWORD(file);
while(count--) {
ASF::Attribute attribute;
String name = attribute.parse(*file, 1);
@@ -275,7 +332,7 @@ void ASF::File::MetadataObject::parse(ASF::File *file, uint /*size*/)
}
}
ByteVector ASF::File::MetadataObject::render(ASF::File *file)
ByteVector ASF::File::FilePrivate::MetadataObject::render(ASF::File *file)
{
data.clear();
data.append(ByteVector::fromShort(attributeData.size(), false));
@@ -283,15 +340,15 @@ ByteVector ASF::File::MetadataObject::render(ASF::File *file)
return BaseObject::render(file);
}
ByteVector ASF::File::MetadataLibraryObject::guid()
ByteVector ASF::File::FilePrivate::MetadataLibraryObject::guid() const
{
return metadataLibraryGuid;
}
void ASF::File::MetadataLibraryObject::parse(ASF::File *file, uint /*size*/)
void ASF::File::FilePrivate::MetadataLibraryObject::parse(ASF::File *file, uint /*size*/)
{
file->d->metadataLibraryObject = this;
int count = file->readWORD();
int count = readWORD(file);
while(count--) {
ASF::Attribute attribute;
String name = attribute.parse(*file, 2);
@@ -299,7 +356,7 @@ void ASF::File::MetadataLibraryObject::parse(ASF::File *file, uint /*size*/)
}
}
ByteVector ASF::File::MetadataLibraryObject::render(ASF::File *file)
ByteVector ASF::File::FilePrivate::MetadataLibraryObject::render(ASF::File *file)
{
data.clear();
data.append(ByteVector::fromShort(attributeData.size(), false));
@@ -307,16 +364,21 @@ ByteVector ASF::File::MetadataLibraryObject::render(ASF::File *file)
return BaseObject::render(file);
}
ByteVector ASF::File::HeaderExtensionObject::guid()
ASF::File::FilePrivate::HeaderExtensionObject::HeaderExtensionObject()
{
objects.setAutoDelete(true);
}
ByteVector ASF::File::FilePrivate::HeaderExtensionObject::guid() const
{
return headerExtensionGuid;
}
void ASF::File::HeaderExtensionObject::parse(ASF::File *file, uint /*size*/)
void ASF::File::FilePrivate::HeaderExtensionObject::parse(ASF::File *file, uint /*size*/)
{
file->d->headerExtensionObject = this;
file->seek(18, File::Current);
long long dataSize = file->readDWORD();
long long dataSize = readDWORD(file);
long long dataPos = 0;
while(dataPos < dataSize) {
ByteVector guid = file->readBlock(16);
@@ -325,7 +387,7 @@ void ASF::File::HeaderExtensionObject::parse(ASF::File *file, uint /*size*/)
break;
}
bool ok;
long long size = file->readQWORD(&ok);
long long size = readQWORD(file, &ok);
if(!ok) {
file->setValid(false);
break;
@@ -340,51 +402,99 @@ void ASF::File::HeaderExtensionObject::parse(ASF::File *file, uint /*size*/)
else {
obj = new UnknownObject(guid);
}
obj->parse(file, size);
obj->parse(file, (unsigned int)size);
objects.append(obj);
dataPos += size;
}
}
ByteVector ASF::File::HeaderExtensionObject::render(ASF::File *file)
ByteVector ASF::File::FilePrivate::HeaderExtensionObject::render(ASF::File *file)
{
data.clear();
for(unsigned int i = 0; i < objects.size(); i++) {
data.append(objects[i]->render(file));
for(List<BaseObject *>::ConstIterator 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;
return BaseObject::render(file);
}
ByteVector ASF::File::FilePrivate::CodecListObject::guid() const
{
return codecListGuid;
}
void ASF::File::FilePrivate::CodecListObject::parse(ASF::File *file, uint size)
{
BaseObject::parse(file, size);
if(data.size() <= 20) {
debug("ASF::File::FilePrivate::CodecListObject::parse() -- data is too short.");
return;
}
uint pos = 16;
const int count = data.toUInt(pos, false);
pos += 4;
for(int i = 0; i < count; ++i) {
if(pos >= data.size())
break;
const CodecType type = static_cast<CodecType>(data.toUShort(pos, false));
pos += 2;
int nameLength = data.toUShort(pos, false);
pos += 2;
const uint namePos = pos;
pos += nameLength * 2;
const int descLength = data.toUShort(pos, false);
pos += 2;
const uint descPos = pos;
pos += descLength * 2;
const int infoLength = data.toUShort(pos, false);
pos += 2 + infoLength * 2;
if(type == CodecListObject::Audio) {
// First audio codec found.
const String name(data.mid(namePos, nameLength * 2), String::UTF16LE);
file->d->properties->setCodecName(name.stripWhiteSpace());
const String desc(data.mid(descPos, descLength * 2), String::UTF16LE);
file->d->properties->setCodecDescription(desc.stripWhiteSpace());
break;
}
}
}
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
ASF::File::File(FileName file, bool readProperties, Properties::ReadStyle propertiesStyle)
: TagLib::File(file)
ASF::File::File(FileName file, bool, Properties::ReadStyle) :
TagLib::File(file),
d(new FilePrivate())
{
d = new FilePrivate;
read(readProperties, propertiesStyle);
if(isOpen())
read();
}
ASF::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle propertiesStyle)
: TagLib::File(stream)
ASF::File::File(IOStream *stream, bool, Properties::ReadStyle) :
TagLib::File(stream),
d(new FilePrivate())
{
d = new FilePrivate;
read(readProperties, propertiesStyle);
if(isOpen())
read();
}
ASF::File::~File()
{
for(unsigned int i = 0; i < d->objects.size(); i++) {
delete d->objects[i];
}
if(d->tag) {
delete d->tag;
}
if(d->properties) {
delete d->properties;
}
delete d;
}
@@ -393,79 +503,26 @@ ASF::Tag *ASF::File::tag() const
return d->tag;
}
PropertyMap ASF::File::properties() const
{
return d->tag->properties();
}
void ASF::File::removeUnsupportedProperties(const StringList &properties)
{
d->tag->removeUnsupportedProperties(properties);
}
PropertyMap ASF::File::setProperties(const PropertyMap &properties)
{
return d->tag->setProperties(properties);
}
ASF::Properties *ASF::File::audioProperties() const
{
return d->properties;
}
void ASF::File::read(bool /*readProperties*/, Properties::ReadStyle /*propertiesStyle*/)
{
if(!isValid())
return;
ByteVector guid = readBlock(16);
if(guid != headerGuid) {
debug("ASF: Not an ASF file.");
setValid(false);
return;
}
d->tag = new ASF::Tag();
d->properties = new ASF::Properties();
bool ok;
d->size = readQWORD(&ok);
if(!ok) {
setValid(false);
return;
}
int numObjects = readDWORD(&ok);
if(!ok) {
setValid(false);
return;
}
seek(2, Current);
for(int i = 0; i < numObjects; i++) {
ByteVector guid = readBlock(16);
if(guid.size() != 16) {
setValid(false);
break;
}
long size = (long)readQWORD(&ok);
if(!ok) {
setValid(false);
break;
}
BaseObject *obj;
if(guid == filePropertiesGuid) {
obj = new FilePropertiesObject();
}
else if(guid == streamPropertiesGuid) {
obj = new StreamPropertiesObject();
}
else if(guid == contentDescriptionGuid) {
obj = new ContentDescriptionObject();
}
else if(guid == extendedContentDescriptionGuid) {
obj = new ExtendedContentDescriptionObject();
}
else if(guid == headerExtensionGuid) {
obj = new HeaderExtensionObject();
}
else {
if(guid == contentEncryptionGuid ||
guid == extendedContentEncryptionGuid ||
guid == advancedContentEncryptionGuid) {
d->properties->setEncrypted(true);
}
obj = new UnknownObject(guid);
}
obj->parse(this, size);
d->objects.append(obj);
}
}
bool ASF::File::save()
{
if(readOnly()) {
@@ -479,40 +536,47 @@ bool ASF::File::save()
}
if(!d->contentDescriptionObject) {
d->contentDescriptionObject = new ContentDescriptionObject();
d->contentDescriptionObject = new FilePrivate::ContentDescriptionObject();
d->objects.append(d->contentDescriptionObject);
}
if(!d->extendedContentDescriptionObject) {
d->extendedContentDescriptionObject = new ExtendedContentDescriptionObject();
d->extendedContentDescriptionObject = new FilePrivate::ExtendedContentDescriptionObject();
d->objects.append(d->extendedContentDescriptionObject);
}
if(!d->headerExtensionObject) {
d->headerExtensionObject = new HeaderExtensionObject();
d->headerExtensionObject = new FilePrivate::HeaderExtensionObject();
d->objects.append(d->headerExtensionObject);
}
if(!d->metadataObject) {
d->metadataObject = new MetadataObject();
d->metadataObject = new FilePrivate::MetadataObject();
d->headerExtensionObject->objects.append(d->metadataObject);
}
if(!d->metadataLibraryObject) {
d->metadataLibraryObject = new MetadataLibraryObject();
d->metadataLibraryObject = new FilePrivate::MetadataLibraryObject();
d->headerExtensionObject->objects.append(d->metadataLibraryObject);
}
ASF::AttributeListMap::ConstIterator it = d->tag->attributeListMap().begin();
for(; it != d->tag->attributeListMap().end(); it++) {
const AttributeListMap allAttributes = d->tag->attributeListMap();
for(AttributeListMap::ConstIterator it = allAttributes.begin(); it != allAttributes.end(); ++it) {
const String &name = it->first;
const AttributeList &attributes = it->second;
bool inExtendedContentDescriptionObject = false;
bool inMetadataObject = false;
for(unsigned int j = 0; j < attributes.size(); j++) {
const Attribute &attribute = attributes[j];
bool largeValue = attribute.dataSize() > 65535;
if(!inExtendedContentDescriptionObject && !largeValue && attribute.language() == 0 && attribute.stream() == 0) {
for(AttributeList::ConstIterator jt = attributes.begin(); jt != attributes.end(); ++jt) {
const Attribute &attribute = *jt;
const bool largeValue = (attribute.dataSize() > 65535);
const bool guid = (attribute.type() == Attribute::GuidType);
if(!inExtendedContentDescriptionObject && !guid && !largeValue && attribute.language() == 0 && attribute.stream() == 0) {
d->extendedContentDescriptionObject->attributeData.append(attribute.render(name));
inExtendedContentDescriptionObject = true;
}
else if(!inMetadataObject && !largeValue && attribute.language() == 0 && attribute.stream() != 0) {
else if(!inMetadataObject && !guid && !largeValue && attribute.language() == 0 && attribute.stream() != 0) {
d->metadataObject->attributeData.append(attribute.render(name, 1));
inMetadataObject = true;
}
@@ -523,85 +587,87 @@ bool ASF::File::save()
}
ByteVector data;
for(unsigned int i = 0; i < d->objects.size(); i++) {
data.append(d->objects[i]->render(this));
for(List<FilePrivate::BaseObject *>::ConstIterator it = d->objects.begin(); it != d->objects.end(); ++it) {
data.append((*it)->render(this));
}
data = headerGuid + ByteVector::fromLongLong(data.size() + 30, false) + ByteVector::fromUInt(d->objects.size(), false) + ByteVector("\x01\x02", 2) + data;
insert(data, 0, d->size);
insert(data, 0, (TagLib::ulong)d->size);
return true;
}
////////////////////////////////////////////////////////////////////////////////
// protected members
// private members
////////////////////////////////////////////////////////////////////////////////
int ASF::File::readBYTE(bool *ok)
void ASF::File::read()
{
ByteVector v = readBlock(1);
if(v.size() != 1) {
if(ok) *ok = false;
return 0;
}
if(ok) *ok = true;
return v[0];
}
if(!isValid())
return;
int ASF::File::readWORD(bool *ok)
{
ByteVector v = readBlock(2);
if(v.size() != 2) {
if(ok) *ok = false;
return 0;
ByteVector guid = readBlock(16);
if(guid != headerGuid) {
debug("ASF: Not an ASF file.");
setValid(false);
return;
}
if(ok) *ok = true;
return v.toUShort(false);
}
unsigned int ASF::File::readDWORD(bool *ok)
{
ByteVector v = readBlock(4);
if(v.size() != 4) {
if(ok) *ok = false;
return 0;
d->tag = new ASF::Tag();
d->properties = new ASF::Properties();
bool ok;
d->size = readQWORD(this, &ok);
if(!ok) {
setValid(false);
return;
}
if(ok) *ok = true;
return v.toUInt(false);
}
long long ASF::File::readQWORD(bool *ok)
{
ByteVector v = readBlock(8);
if(v.size() != 8) {
if(ok) *ok = false;
return 0;
int numObjects = readDWORD(this, &ok);
if(!ok) {
setValid(false);
return;
}
if(ok) *ok = true;
return v.toLongLong(false);
}
seek(2, Current);
String ASF::File::readString(int length)
{
ByteVector data = readBlock(length);
unsigned int size = data.size();
while (size >= 2) {
if(data[size - 1] != '\0' || data[size - 2] != '\0') {
for(int i = 0; i < numObjects; i++) {
guid = readBlock(16);
if(guid.size() != 16) {
setValid(false);
break;
}
size -= 2;
long size = (long)readQWORD(this, &ok);
if(!ok) {
setValid(false);
break;
}
FilePrivate::BaseObject *obj;
if(guid == filePropertiesGuid) {
obj = new FilePrivate::FilePropertiesObject();
}
else if(guid == streamPropertiesGuid) {
obj = new FilePrivate::StreamPropertiesObject();
}
else if(guid == contentDescriptionGuid) {
obj = new FilePrivate::ContentDescriptionObject();
}
else if(guid == extendedContentDescriptionGuid) {
obj = new FilePrivate::ExtendedContentDescriptionObject();
}
else if(guid == headerExtensionGuid) {
obj = new FilePrivate::HeaderExtensionObject();
}
else if(guid == codecListGuid) {
obj = new FilePrivate::CodecListObject();
}
else {
if(guid == contentEncryptionGuid ||
guid == extendedContentEncryptionGuid ||
guid == advancedContentEncryptionGuid) {
d->properties->setEncrypted(true);
}
obj = new FilePrivate::UnknownObject(guid);
}
obj->parse(this, size);
d->objects.append(obj);
}
if(size != data.size()) {
data.resize(size);
}
return String(data, String::UTF16LE);
}
ByteVector ASF::File::renderString(const String &str, bool includeLength)
{
ByteVector data = str.data(String::UTF16LE) + ByteVector::fromShort(0, false);
if(includeLength) {
data = ByteVector::fromShort(data.size(), false) + data;
}
return data;
}

View File

@@ -48,24 +48,27 @@ namespace TagLib {
public:
/*!
* Contructs an ASF file from \a file. If \a readProperties is true the
* file's audio properties will also be read using \a propertiesStyle. If
* false, \a propertiesStyle is ignored.
* Constructs an ASF file from \a file.
*
* \note In the current implementation, both \a readProperties and
* \a propertiesStyle are ignored.
* \a propertiesStyle are ignored. The audio properties are always
* read.
*/
File(FileName file, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average);
File(FileName file, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
/*!
* 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.
* Constructs an ASF file from \a stream.
*
* \note In the current implementation, both \a readProperties and
* \a propertiesStyle are ignored.
* \a propertiesStyle are ignored. The audio properties are always
* read.
*
* \note TagLib will *not* take ownership of the stream, the caller is
* responsible for deleting it after the File object.
*/
File(IOStream *stream, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average);
File(IOStream *stream, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
/*!
* Destroys this instance of the File.
@@ -84,6 +87,22 @@ 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.
*/
@@ -93,31 +112,14 @@ namespace TagLib {
* Save the file.
*
* This returns true if the save was successful.
*
* \warning In the current implementation, it's dangerous to call save()
* repeatedly. At worst it will corrupt the file.
*/
virtual bool save();
private:
int readBYTE(bool *ok = 0);
int readWORD(bool *ok = 0);
unsigned int readDWORD(bool *ok = 0);
long long readQWORD(bool *ok = 0);
static ByteVector renderString(const String &str, bool includeLength = false);
String readString(int len);
void read(bool readProperties, Properties::ReadStyle propertiesStyle);
friend class Attribute;
friend class Picture;
class BaseObject;
class UnknownObject;
class FilePropertiesObject;
class StreamPropertiesObject;
class ContentDescriptionObject;
class ExtendedContentDescriptionObject;
class HeaderExtensionObject;
class MetadataObject;
class MetadataLibraryObject;
void read();
class FilePrivate;
FilePrivate *d;

View File

@@ -23,19 +23,18 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <taglib.h>
#include <tdebug.h>
#include <trefcounter.h>
#include "asfattribute.h"
#include "asffile.h"
#include "asfpicture.h"
#include "asfutils.h"
using namespace TagLib;
class ASF::Picture::PicturePriavte : public RefCounter
class ASF::Picture::PicturePrivate : public RefCounter
{
public:
bool valid;
@@ -51,7 +50,7 @@ public:
ASF::Picture::Picture()
{
d = new PicturePriavte();
d = new PicturePrivate();
d->valid = true;
}
@@ -137,8 +136,8 @@ ByteVector ASF::Picture::render() const
return
ByteVector((char)d->type) +
ByteVector::fromUInt(d->picture.size(), false) +
ASF::File::renderString(d->mimeType) +
ASF::File::renderString(d->description) +
renderString(d->mimeType) +
renderString(d->description) +
d->picture;
}
@@ -149,7 +148,7 @@ void ASF::Picture::parse(const ByteVector& bytes)
return;
int pos = 0;
d->type = (Type)bytes[0]; ++pos;
uint dataLen = bytes.mid(pos, 4).toUInt(false); pos+=4;
const uint dataLen = bytes.toUInt(pos, false); pos+=4;
const ByteVector nullStringTerminator(2, 0);

View File

@@ -205,11 +205,11 @@ namespace TagLib
/* THIS IS PRIVATE, DON'T TOUCH IT! */
void parse(const ByteVector& );
static Picture fromInvalid();
friend class Attribute;
#endif
private:
struct PicturePriavte;
PicturePriavte *d;
class PicturePrivate;
PicturePrivate *d;
};
}
}

View File

@@ -23,10 +23,6 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <tdebug.h>
#include <tstring.h>
#include "asfproperties.h"
@@ -36,11 +32,23 @@ using namespace TagLib;
class ASF::Properties::PropertiesPrivate
{
public:
PropertiesPrivate(): length(0), bitrate(0), sampleRate(0), channels(0), encrypted(false) {}
PropertiesPrivate() :
length(0),
bitrate(0),
sampleRate(0),
channels(0),
bitsPerSample(0),
codec(ASF::Properties::Unknown),
encrypted(false) {}
int length;
int bitrate;
int sampleRate;
int channels;
int bitsPerSample;
ASF::Properties::Codec codec;
String codecName;
String codecDescription;
bool encrypted;
};
@@ -48,18 +56,28 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
ASF::Properties::Properties() : AudioProperties(AudioProperties::Average)
ASF::Properties::Properties() :
AudioProperties(AudioProperties::Average),
d(new PropertiesPrivate())
{
d = new PropertiesPrivate;
}
ASF::Properties::~Properties()
{
if(d)
delete d;
delete d;
}
int ASF::Properties::length() const
{
return lengthInSeconds();
}
int ASF::Properties::lengthInSeconds() const
{
return d->length / 1000;
}
int ASF::Properties::lengthInMilliseconds() const
{
return d->length;
}
@@ -77,7 +95,27 @@ int ASF::Properties::sampleRate() const
int ASF::Properties::channels() const
{
return d->channels;
}
}
int ASF::Properties::bitsPerSample() const
{
return d->bitsPerSample;
}
ASF::Properties::Codec ASF::Properties::codec() const
{
return d->codec;
}
String ASF::Properties::codecName() const
{
return d->codecName;
}
String ASF::Properties::codecDescription() const
{
return d->codecDescription;
}
bool ASF::Properties::isEncrypted() const
{
@@ -88,28 +126,69 @@ bool ASF::Properties::isEncrypted() const
// private members
////////////////////////////////////////////////////////////////////////////////
void ASF::Properties::setLength(int length)
void ASF::Properties::setLength(int /*length*/)
{
d->length = length;
debug("ASF::Properties::setLength() -- This method is deprecated. Do not use.");
}
void ASF::Properties::setBitrate(int length)
void ASF::Properties::setLengthInMilliseconds(int value)
{
d->bitrate = length;
d->length = value;
}
void ASF::Properties::setSampleRate(int length)
void ASF::Properties::setBitrate(int value)
{
d->sampleRate = length;
d->bitrate = value;
}
void ASF::Properties::setChannels(int length)
void ASF::Properties::setSampleRate(int value)
{
d->channels = length;
d->sampleRate = value;
}
void ASF::Properties::setEncrypted(bool encrypted)
void ASF::Properties::setChannels(int value)
{
d->encrypted = encrypted;
d->channels = value;
}
void ASF::Properties::setBitsPerSample(int value)
{
d->bitsPerSample = value;
}
void ASF::Properties::setCodec(int value)
{
switch(value)
{
case 0x0160:
d->codec = WMA1;
break;
case 0x0161:
d->codec = WMA2;
break;
case 0x0162:
d->codec = WMA9Pro;
break;
case 0x0163:
d->codec = WMA9Lossless;
break;
default:
d->codec = Unknown;
break;
}
}
void ASF::Properties::setCodecName(const String &value)
{
d->codecName = value;
}
void ASF::Properties::setCodecDescription(const String &value)
{
d->codecDescription = value;
}
void ASF::Properties::setEncrypted(bool value)
{
d->encrypted = value;
}

View File

@@ -40,7 +40,38 @@ namespace TagLib {
public:
/*!
* Create an instance of ASF::Properties.
* Audio codec types can be used in ASF file.
*/
enum Codec
{
/*!
* Couldn't detect the codec.
*/
Unknown = 0,
/*!
* Windows Media Audio 1
*/
WMA1,
/*!
* Windows Media Audio 2 or above
*/
WMA2,
/*!
* Windows Media Audio 9 Professional
*/
WMA9Pro,
/*!
* Windows Media Audio 9 Lossless
*/
WMA9Lossless,
};
/*!
* Creates an instance of ASF::Properties.
*/
Properties();
@@ -49,18 +80,97 @@ namespace TagLib {
*/
virtual ~Properties();
// Reimplementations.
/*!
* Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second.
*
* \note This method is just an alias of lengthInSeconds().
*
* \deprecated
*/
virtual int length() const;
/*!
* Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second.
*
* \see lengthInMilliseconds()
*/
// BIC: make virtual
int lengthInSeconds() const;
/*!
* Returns the length of the file in milliseconds.
*
* \see lengthInSeconds()
*/
// BIC: make virtual
int lengthInMilliseconds() const;
/*!
* Returns the average bit rate of the file in kb/s.
*/
virtual int bitrate() const;
/*!
* Returns the sample rate in Hz.
*/
virtual int sampleRate() const;
/*!
* Returns the number of audio channels.
*/
virtual int channels() const;
/*!
* Returns the number of bits per audio sample.
*/
int bitsPerSample() const;
/*!
* Returns the codec used in the file.
*
* \see codecName()
* \see codecDescription()
*/
Codec codec() const;
/*!
* Returns the concrete codec name, for example "Windows Media Audio 9.1"
* used in the file if available, otherwise an empty string.
*
* \see codec()
* \see codecDescription()
*/
String codecName() const;
/*!
* Returns the codec description, typically contains the encoder settings,
* for example "VBR Quality 50, 44kHz, stereo 1-pass VBR" if available,
* otherwise an empty string.
*
* \see codec()
* \see codecName()
*/
String codecDescription() const;
/*!
* Returns whether or not the file is encrypted.
*/
bool isEncrypted() const;
#ifndef DO_NOT_DOCUMENT
// deprecated
void setLength(int value);
void setLengthInMilliseconds(int value);
void setBitrate(int value);
void setSampleRate(int value);
void setChannels(int value);
void setBitsPerSample(int value);
void setCodec(int value);
void setCodecName(const String &value);
void setCodecDescription(const String &value);
void setEncrypted(bool value);
#endif
@@ -73,4 +183,4 @@ namespace TagLib {
}
#endif
#endif

View File

@@ -23,10 +23,7 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <tpropertymap.h>
#include "asftag.h"
using namespace TagLib;
@@ -50,8 +47,7 @@ ASF::Tag::Tag()
ASF::Tag::~Tag()
{
if(d)
delete d;
delete d;
}
String ASF::Tag::title() const
@@ -164,11 +160,24 @@ ASF::AttributeListMap& ASF::Tag::attributeListMap()
return d->attributeListMap;
}
const ASF::AttributeListMap &ASF::Tag::attributeListMap() const
{
return d->attributeListMap;
}
bool ASF::Tag::contains(const String &key) const
{
return d->attributeListMap.contains(key);
}
void ASF::Tag::removeItem(const String &key)
{
AttributeListMap::Iterator it = d->attributeListMap.find(key);
if(it != d->attributeListMap.end())
d->attributeListMap.erase(it);
d->attributeListMap.erase(key);
}
ASF::AttributeList ASF::Tag::attribute(const String &name) const
{
return d->attributeListMap[name];
}
void ASF::Tag::setAttribute(const String &name, const Attribute &attribute)
@@ -178,6 +187,11 @@ void ASF::Tag::setAttribute(const String &name, const Attribute &attribute)
d->attributeListMap.insert(name, value);
}
void ASF::Tag::setAttribute(const String &name, const AttributeList &values)
{
d->attributeListMap.insert(name, values);
}
void ASF::Tag::addAttribute(const String &name, const Attribute &attribute)
{
if(d->attributeListMap.contains(name)) {
@@ -196,3 +210,163 @@ bool ASF::Tag::isEmpty() const
d->attributeListMap.isEmpty();
}
static const char *keyTranslation[][2] = {
{ "WM/AlbumTitle", "ALBUM" },
{ "WM/AlbumArtist", "ALBUMARTIST" },
{ "WM/Composer", "COMPOSER" },
{ "WM/Writer", "WRITER" },
{ "WM/Conductor", "CONDUCTOR" },
{ "WM/ModifiedBy", "REMIXER" },
{ "WM/Year", "DATE" },
{ "WM/OriginalReleaseYear", "ORIGINALDATE" },
{ "WM/Producer", "PRODUCER" },
{ "WM/ContentGroupDescription", "GROUPING" },
{ "WM/SubTitle", "SUBTITLE" },
{ "WM/SetSubTitle", "DISCSUBTITLE" },
{ "WM/TrackNumber", "TRACKNUMBER" },
{ "WM/PartOfSet", "DISCNUMBER" },
{ "WM/Genre", "GENRE" },
{ "WM/BeatsPerMinute", "BPM" },
{ "WM/Mood", "MOOD" },
{ "WM/ISRC", "ISRC" },
{ "WM/Lyrics", "LYRICS" },
{ "WM/Media", "MEDIA" },
{ "WM/Publisher", "LABEL" },
{ "WM/CatalogNo", "CATALOGNUMBER" },
{ "WM/Barcode", "BARCODE" },
{ "WM/EncodedBy", "ENCODEDBY" },
{ "WM/AlbumSortOrder", "ALBUMSORT" },
{ "WM/AlbumArtistSortOrder", "ALBUMARTISTSORT" },
{ "WM/ArtistSortOrder", "ARTISTSORT" },
{ "WM/TitleSortOrder", "TITLESORT" },
{ "WM/Script", "SCRIPT" },
{ "WM/Language", "LANGUAGE" },
{ "MusicBrainz/Track Id", "MUSICBRAINZ_TRACKID" },
{ "MusicBrainz/Artist Id", "MUSICBRAINZ_ARTISTID" },
{ "MusicBrainz/Album Id", "MUSICBRAINZ_ALBUMID" },
{ "MusicBrainz/Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID" },
{ "MusicBrainz/Release Group Id", "MUSICBRAINZ_RELEASEGROUPID" },
{ "MusicBrainz/Work Id", "MUSICBRAINZ_WORKID" },
{ "MusicIP/PUID", "MUSICIP_PUID" },
{ "Acoustid/Id", "ACOUSTID_ID" },
{ "Acoustid/Fingerprint", "ACOUSTID_FINGERPRINT" },
};
PropertyMap ASF::Tag::properties() const
{
static Map<String, String> keyMap;
if(keyMap.isEmpty()) {
int numKeys = sizeof(keyTranslation) / sizeof(keyTranslation[0]);
for(int i = 0; i < numKeys; i++) {
keyMap[keyTranslation[i][0]] = keyTranslation[i][1];
}
}
PropertyMap props;
if(!d->title.isEmpty()) {
props["TITLE"] = d->title;
}
if(!d->artist.isEmpty()) {
props["ARTIST"] = d->artist;
}
if(!d->copyright.isEmpty()) {
props["COPYRIGHT"] = d->copyright;
}
if(!d->comment.isEmpty()) {
props["COMMENT"] = d->comment;
}
ASF::AttributeListMap::ConstIterator it = d->attributeListMap.begin();
for(; it != d->attributeListMap.end(); ++it) {
if(keyMap.contains(it->first)) {
String key = keyMap[it->first];
AttributeList::ConstIterator it2 = it->second.begin();
for(; it2 != it->second.end(); ++it2) {
if(key == "TRACKNUMBER") {
if(it2->type() == ASF::Attribute::DWordType)
props.insert(key, String::number(it2->toUInt()));
else
props.insert(key, it2->toString());
}
else {
props.insert(key, it2->toString());
}
}
}
else {
props.unsupportedData().append(it->first);
}
}
return props;
}
void ASF::Tag::removeUnsupportedProperties(const StringList &props)
{
StringList::ConstIterator it = props.begin();
for(; it != props.end(); ++it)
d->attributeListMap.erase(*it);
}
PropertyMap ASF::Tag::setProperties(const PropertyMap &props)
{
static Map<String, String> reverseKeyMap;
if(reverseKeyMap.isEmpty()) {
int numKeys = sizeof(keyTranslation) / sizeof(keyTranslation[0]);
for(int i = 0; i < numKeys; i++) {
reverseKeyMap[keyTranslation[i][1]] = keyTranslation[i][0];
}
}
PropertyMap origProps = properties();
PropertyMap::ConstIterator it = origProps.begin();
for(; it != origProps.end(); ++it) {
if(!props.contains(it->first) || props[it->first].isEmpty()) {
if(it->first == "TITLE") {
d->title = String::null;
}
else if(it->first == "ARTIST") {
d->artist = String::null;
}
else if(it->first == "COMMENT") {
d->comment = String::null;
}
else if(it->first == "COPYRIGHT") {
d->copyright = String::null;
}
else {
d->attributeListMap.erase(reverseKeyMap[it->first]);
}
}
}
PropertyMap ignoredProps;
it = props.begin();
for(; it != props.end(); ++it) {
if(reverseKeyMap.contains(it->first)) {
String name = reverseKeyMap[it->first];
removeItem(name);
StringList::ConstIterator it2 = it->second.begin();
for(; it2 != it->second.end(); ++it2) {
addAttribute(name, *it2);
}
}
else if(it->first == "TITLE") {
d->title = it->second.toString();
}
else if(it->first == "ARTIST") {
d->artist = it->second.toString();
}
else if(it->first == "COMMENT") {
d->comment = it->second.toString();
}
else if(it->first == "COPYRIGHT") {
d->copyright = it->second.toString();
}
else {
ignoredProps.insert(it->first, it->second);
}
}
return ignoredProps;
}

View File

@@ -120,17 +120,17 @@ namespace TagLib {
virtual void setComment(const String &s);
/*!
* Sets the rating to \a s.
* Sets the rating to \a s.
*/
virtual void setRating(const String &s);
/*!
* Sets the copyright to \a s.
* Sets the copyright to \a s.
*/
virtual void setCopyright(const String &s);
/*!
* Sets the genre to \a s.
* Sets the genre to \a s.
*/
virtual void setGenre(const String &s);
@@ -152,30 +152,53 @@ namespace TagLib {
virtual bool isEmpty() const;
/*!
* Returns a reference to the item list map. This is an AttributeListMap of
* all of the items in the tag.
*
* This is the most powerfull structure for accessing the items of the tag.
* \deprecated
*/
AttributeListMap &attributeListMap();
/*!
* Returns a reference to the item list map. This is an AttributeListMap of
* all of the items in the tag.
*/
const AttributeListMap &attributeListMap() const;
/*!
* \return True if a value for \a attribute is currently set.
*/
bool contains(const String &name) const;
/*!
* Removes the \a key attribute from the tag
*/
void removeItem(const String &name);
/*!
* \return The list of values for the key \a name, or an empty list if no
* values have been set.
*/
AttributeList attribute(const String &name) const;
/*!
* Sets the \a key attribute to the value of \a attribute. If an attribute
* with the \a key is already present, it will be replaced.
*/
void setAttribute(const String &name, const Attribute &attribute);
/*!
* Sets multiple \a values to the key \a name.
*/
void setAttribute(const String &name, const AttributeList &values);
/*!
* Sets the \a key attribute to the value of \a attribute. If an attribute
* with the \a key is already present, it will be added to the list.
*/
void addAttribute(const String &name, const Attribute &attribute);
PropertyMap properties() const;
void removeUnsupportedProperties(const StringList& properties);
PropertyMap setProperties(const PropertyMap &properties);
private:
class TagPrivate;

101
taglib/asf/asfutils.h Normal file
View File

@@ -0,0 +1,101 @@
/***************************************************************************
copyright : (C) 2015 by Tsuda Kageyu
email : tsuda.kageyu@gmail.com
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifndef TAGLIB_ASFUTILS_H
#define TAGLIB_ASFUTILS_H
// THIS FILE IS NOT A PART OF THE TAGLIB API
#ifndef DO_NOT_DOCUMENT // tell Doxygen not to document this header
namespace TagLib
{
namespace ASF
{
inline ushort readWORD(File *file, bool *ok = 0)
{
const ByteVector v = file->readBlock(2);
if(v.size() != 2) {
if(ok) *ok = false;
return 0;
}
if(ok) *ok = true;
return v.toUShort(false);
}
inline uint readDWORD(File *file, bool *ok = 0)
{
const ByteVector v = file->readBlock(4);
if(v.size() != 4) {
if(ok) *ok = false;
return 0;
}
if(ok) *ok = true;
return v.toUInt(false);
}
inline long long readQWORD(File *file, bool *ok = 0)
{
const ByteVector v = file->readBlock(8);
if(v.size() != 8) {
if(ok) *ok = false;
return 0;
}
if(ok) *ok = true;
return v.toLongLong(false);
}
inline String readString(File *file, int length)
{
ByteVector data = file->readBlock(length);
unsigned int size = data.size();
while (size >= 2) {
if(data[size - 1] != '\0' || data[size - 2] != '\0') {
break;
}
size -= 2;
}
if(size != data.size()) {
data.resize(size);
}
return String(data, String::UTF16LE);
}
inline ByteVector renderString(const String &str, bool includeLength = false)
{
ByteVector data = str.data(String::UTF16LE) + ByteVector::fromShort(0, false);
if(includeLength) {
data = ByteVector::fromShort(data.size(), false) + data;
}
return data;
}
}
}
#endif
#endif

View File

@@ -23,6 +23,22 @@
* 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 "audioproperties.h"
using namespace TagLib;
@@ -41,11 +57,108 @@ AudioProperties::~AudioProperties()
}
int TagLib::AudioProperties::lengthInSeconds() const
{
// This is an ugly workaround but we can't add a virtual function.
// Should be virtual in taglib2.
if(dynamic_cast<const APE::Properties*>(this))
return dynamic_cast<const APE::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const ASF::Properties*>(this))
return dynamic_cast<const ASF::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const FLAC::Properties*>(this))
return dynamic_cast<const FLAC::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const MP4::Properties*>(this))
return dynamic_cast<const MP4::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const MPC::Properties*>(this))
return dynamic_cast<const MPC::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const MPEG::Properties*>(this))
return dynamic_cast<const MPEG::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const Ogg::Opus::Properties*>(this))
return dynamic_cast<const Ogg::Opus::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const Ogg::Speex::Properties*>(this))
return dynamic_cast<const Ogg::Speex::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const TrueAudio::Properties*>(this))
return dynamic_cast<const TrueAudio::Properties*>(this)->lengthInSeconds();
else if (dynamic_cast<const RIFF::AIFF::Properties*>(this))
return dynamic_cast<const RIFF::AIFF::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const RIFF::WAV::Properties*>(this))
return dynamic_cast<const RIFF::WAV::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const Vorbis::Properties*>(this))
return dynamic_cast<const Vorbis::Properties*>(this)->lengthInSeconds();
else if(dynamic_cast<const WavPack::Properties*>(this))
return dynamic_cast<const WavPack::Properties*>(this)->lengthInSeconds();
else
return 0;
}
int TagLib::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;
}
////////////////////////////////////////////////////////////////////////////////
// protected methods
////////////////////////////////////////////////////////////////////////////////
AudioProperties::AudioProperties(ReadStyle)
AudioProperties::AudioProperties(ReadStyle) :
d(0)
{
}

View File

@@ -34,7 +34,7 @@ namespace TagLib {
/*!
* The values here are common to most audio formats. For more specific, codec
* dependant values, please see see the subclasses APIs. This is meant to
* dependent values, please see see the subclasses APIs. This is meant to
* compliment the TagLib::File and TagLib::Tag APIs in providing a simple
* interface that is sufficient for most applications.
*/
@@ -69,6 +69,23 @@ namespace TagLib {
*/
virtual int length() const = 0;
/*!
* Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second.
*
* \see lengthInMilliseconds()
*/
// BIC: make virtual
int lengthInSeconds() const;
/*!
* Returns the length of the file in milliseconds.
*
* \see lengthInSeconds()
*/
// BIC: make virtual
int lengthInMilliseconds() const;
/*!
* Returns the most appropriate bit rate for the file in kb/s. For constant
* bitrate formats this is simply the bitrate of the file. For variable

View File

@@ -1,7 +1,7 @@
/***************************************************************************
copyright : (C) 2002 - 2008 by Scott Wheeler
email : wheeler@kde.org
copyright : (C) 2010 by Alex Novichkov
email : novichko@atnet.ru
(added APE file support)
@@ -27,13 +27,10 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <tfile.h>
#include <tstring.h>
#include <tdebug.h>
#include "trefcounter.h"
#include "fileref.h"
#include "asffile.h"
@@ -45,6 +42,7 @@
#include "mp4file.h"
#include "wavpackfile.h"
#include "speexfile.h"
#include "opusfile.h"
#include "trueaudiofile.h"
#include "aifffile.h"
#include "wavfile.h"
@@ -152,6 +150,7 @@ StringList FileRef::defaultFileExtensions()
l.append("spx");
l.append("tta");
l.append("m4a");
l.append("m4r");
l.append("m4b");
l.append("m4p");
l.append("3g2");
@@ -216,21 +215,28 @@ File *FileRef::create(FileName fileName, bool readAudioProperties,
// Ok, this is really dumb for now, but it works for testing.
String s;
String ext;
{
#ifdef _WIN32
s = (wcslen((const wchar_t *) fileName) > 0) ? String((const wchar_t *) fileName) : String((const char *) fileName);
String s = fileName.toString();
#else
s = fileName;
#endif
String s = fileName;
#endif
const int pos = s.rfind(".");
if(pos != -1)
ext = s.substr(pos + 1).upper();
}
// If this list is updated, the method defaultFileExtensions() should also be
// updated. However at some point that list should be created at the same time
// that a default file type resolver is created.
int pos = s.rfind(".");
if(pos != -1) {
String ext = s.substr(pos + 1).upper();
if(!ext.isEmpty()) {
if(ext == "MP3")
return new MPEG::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "OGG")
@@ -251,13 +257,15 @@ File *FileRef::create(FileName fileName, bool readAudioProperties,
return new WavPack::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "SPX")
return new Ogg::Speex::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "OPUS")
return new Ogg::Opus::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "TTA")
return new TrueAudio::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "M4A" || ext == "M4B" || ext == "M4P" || ext == "MP4" || ext == "3G2")
if(ext == "M4A" || ext == "M4R" || ext == "M4B" || ext == "M4P" || ext == "MP4" || ext == "3G2")
return new MP4::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "WMA" || ext == "ASF")
return new ASF::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "AIF" || ext == "AIFF")
if(ext == "AIF" || ext == "AIFF" || ext == "AFC" || ext == "AIFC")
return new RIFF::AIFF::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "WAV")
return new RIFF::WAV::File(fileName, readAudioProperties, audioPropertiesStyle);

View File

@@ -72,7 +72,7 @@ namespace TagLib {
*
* class MyFileTypeResolver : FileTypeResolver
* {
* TagLib::File *createFile(TagLib::FileName *fileName, bool, AudioProperties::ReadStyle)
* TagLib::File *createFile(TagLib::FileName *fileName, bool, AudioProperties::ReadStyle) const
* {
* if(someCheckForAnMP3File(fileName))
* return new TagLib::MPEG::File(fileName);
@@ -128,7 +128,7 @@ namespace TagLib {
audioPropertiesStyle = AudioProperties::Average);
/*!
* Contruct a FileRef using \a file. The FileRef now takes ownership of the
* Construct a FileRef using \a file. The FileRef now takes ownership of the
* pointer and will delete the File when it passes out of scope.
*/
explicit FileRef(File *file);
@@ -191,7 +191,7 @@ namespace TagLib {
* is tried.
*
* Returns a pointer to the added resolver (the same one that's passed in --
* this is mostly so that static inialializers have something to use for
* this is mostly so that static initializers have something to use for
* assignment).
*
* \see FileTypeResolver
@@ -209,7 +209,7 @@ namespace TagLib {
* by TagLib for resolution is case-insensitive.
*
* \note This does not account for any additional file type resolvers that
* are plugged in. Also note that this is not intended to replace a propper
* are plugged in. Also note that this is not intended to replace a proper
* mime-type resolution system, but is just here for reference.
*
* \see FileTypeResolver

View File

@@ -28,6 +28,7 @@
#include <tlist.h>
#include <tdebug.h>
#include <tagunion.h>
#include <tpropertymap.h>
#include <id3v2header.h>
#include <id3v2tag.h>
@@ -43,7 +44,7 @@ using namespace TagLib;
namespace
{
enum { XiphIndex = 0, ID3v2Index = 1, ID3v1Index = 2 };
enum { FlacXiphIndex = 0, FlacID3v2Index = 1, FlacID3v1Index = 2 };
enum { MinPaddingLength = 4096 };
enum { LastBlockFlag = 0x80 };
}
@@ -59,7 +60,6 @@ public:
properties(0),
flacStart(0),
streamStart(0),
streamLength(0),
scanned(false),
hasXiphComment(false),
hasID3v2(false),
@@ -69,7 +69,8 @@ public:
~FilePrivate()
{
for(uint i = 0; i < blocks.size(); i++) {
uint size = blocks.size();
for(uint i = 0; i < size; i++) {
delete blocks[i];
}
delete properties;
@@ -84,13 +85,11 @@ public:
TagUnion tag;
Properties *properties;
ByteVector streamInfoData;
ByteVector xiphCommentData;
List<MetadataBlock *> blocks;
long flacStart;
long streamStart;
long streamLength;
bool scanned;
bool hasXiphComment;
@@ -102,30 +101,32 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
FLAC::File::File(FileName file, bool readProperties,
Properties::ReadStyle propertiesStyle) :
TagLib::File(file)
FLAC::File::File(FileName file, bool readProperties, Properties::ReadStyle) :
TagLib::File(file),
d(new FilePrivate())
{
d = new FilePrivate;
read(readProperties, propertiesStyle);
if(isOpen())
read(readProperties);
}
FLAC::File::File(FileName file, ID3v2::FrameFactory *frameFactory,
bool readProperties, Properties::ReadStyle propertiesStyle) :
TagLib::File(file)
bool readProperties, Properties::ReadStyle) :
TagLib::File(file),
d(new FilePrivate())
{
d = new FilePrivate;
d->ID3v2FrameFactory = frameFactory;
read(readProperties, propertiesStyle);
if(isOpen())
read(readProperties);
}
FLAC::File::File(IOStream *stream, ID3v2::FrameFactory *frameFactory,
bool readProperties, Properties::ReadStyle propertiesStyle) :
TagLib::File(stream)
bool readProperties, Properties::ReadStyle) :
TagLib::File(stream),
d(new FilePrivate())
{
d = new FilePrivate;
d->ID3v2FrameFactory = frameFactory;
read(readProperties, propertiesStyle);
if(isOpen())
read(readProperties);
}
FLAC::File::~File()
@@ -138,12 +139,39 @@ TagLib::Tag *FLAC::File::tag() const
return &d->tag;
}
PropertyMap FLAC::File::properties() const
{
// once Tag::properties() is virtual, this case distinction could actually be done
// within TagUnion.
if(d->hasXiphComment)
return d->tag.access<Ogg::XiphComment>(FlacXiphIndex, false)->properties();
if(d->hasID3v2)
return d->tag.access<ID3v2::Tag>(FlacID3v2Index, false)->properties();
if(d->hasID3v1)
return d->tag.access<ID3v1::Tag>(FlacID3v1Index, false)->properties();
return PropertyMap();
}
void FLAC::File::removeUnsupportedProperties(const StringList &unsupported)
{
if(d->hasXiphComment)
d->tag.access<Ogg::XiphComment>(FlacXiphIndex, false)->removeUnsupportedProperties(unsupported);
if(d->hasID3v2)
d->tag.access<ID3v2::Tag>(FlacID3v2Index, false)->removeUnsupportedProperties(unsupported);
if(d->hasID3v1)
d->tag.access<ID3v1::Tag>(FlacID3v1Index, false)->removeUnsupportedProperties(unsupported);
}
PropertyMap FLAC::File::setProperties(const PropertyMap &properties)
{
return d->tag.access<Ogg::XiphComment>(FlacXiphIndex, true)->setProperties(properties);
}
FLAC::Properties *FLAC::File::audioProperties() const
{
return d->properties;
}
bool FLAC::File::save()
{
if(readOnly()) {
@@ -202,12 +230,12 @@ bool FLAC::File::save()
long originalLength = d->streamStart - d->flacStart;
int paddingLength = originalLength - data.size() - 4;
if (paddingLength < 0) {
if(paddingLength <= 0) {
paddingLength = MinPaddingLength;
}
ByteVector padding = ByteVector::fromUInt(paddingLength);
padding.resize(paddingLength + 4);
padding[0] = FLAC::MetadataBlock::Padding | LastBlockFlag;
padding[0] = (char)(FLAC::MetadataBlock::Padding | LastBlockFlag);
data.append(padding);
// Write the data to the file
@@ -230,8 +258,16 @@ bool FLAC::File::save()
}
if(ID3v1Tag()) {
seek(-128, End);
if(d->hasID3v1) {
seek(d->ID3v1Location);
}
else {
seek(0, End);
d->ID3v1Location = tell();
}
writeBlock(ID3v1Tag()->render());
d->hasID3v1 = true;
}
return true;
@@ -239,21 +275,21 @@ bool FLAC::File::save()
ID3v2::Tag *FLAC::File::ID3v2Tag(bool create)
{
if(!create || d->tag[ID3v2Index])
return static_cast<ID3v2::Tag *>(d->tag[ID3v2Index]);
if(!create || d->tag[FlacID3v2Index])
return static_cast<ID3v2::Tag *>(d->tag[FlacID3v2Index]);
d->tag.set(ID3v2Index, new ID3v2::Tag);
return static_cast<ID3v2::Tag *>(d->tag[ID3v2Index]);
d->tag.set(FlacID3v2Index, new ID3v2::Tag);
return static_cast<ID3v2::Tag *>(d->tag[FlacID3v2Index]);
}
ID3v1::Tag *FLAC::File::ID3v1Tag(bool create)
{
return d->tag.access<ID3v1::Tag>(ID3v1Index, create);
return d->tag.access<ID3v1::Tag>(FlacID3v1Index, create);
}
Ogg::XiphComment *FLAC::File::xiphComment(bool create)
{
return d->tag.access<Ogg::XiphComment>(XiphIndex, create);
return d->tag.access<Ogg::XiphComment>(FlacXiphIndex, create);
}
void FLAC::File::setID3v2FrameFactory(const ID3v2::FrameFactory *factory)
@@ -261,12 +297,81 @@ 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(uint i = 0; i < d->blocks.size(); i++) {
Picture *picture = dynamic_cast<Picture *>(d->blocks[i]);
if(picture) {
pictures.append(picture);
}
}
return pictures;
}
void FLAC::File::addPicture(Picture *picture)
{
d->blocks.append(picture);
}
void FLAC::File::removePicture(Picture *picture, bool del)
{
MetadataBlock *block = picture;
List<MetadataBlock *>::Iterator it = d->blocks.find(block);
if(it != d->blocks.end())
d->blocks.erase(it);
if(del)
delete picture;
}
void FLAC::File::removePictures()
{
List<MetadataBlock *> newBlocks;
for(uint i = 0; i < d->blocks.size(); i++) {
Picture *picture = dynamic_cast<Picture *>(d->blocks[i]);
if(picture) {
delete picture;
}
else {
newBlocks.append(d->blocks[i]);
}
}
d->blocks = newBlocks;
}
bool FLAC::File::hasXiphComment() const
{
return d->hasXiphComment;
}
bool FLAC::File::hasID3v1Tag() const
{
return d->hasID3v1;
}
bool FLAC::File::hasID3v2Tag() const
{
return d->hasID3v2;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void FLAC::File::read(bool readProperties, Properties::ReadStyle propertiesStyle)
void FLAC::File::read(bool readProperties)
{
// Look for an ID3v2 tag
@@ -274,12 +379,12 @@ void FLAC::File::read(bool readProperties, Properties::ReadStyle propertiesStyle
if(d->ID3v2Location >= 0) {
d->tag.set(ID3v2Index, new ID3v2::Tag(this, d->ID3v2Location, d->ID3v2FrameFactory));
d->tag.set(FlacID3v2Index, new ID3v2::Tag(this, d->ID3v2Location, d->ID3v2FrameFactory));
d->ID3v2OriginalSize = ID3v2Tag()->header()->completeTagSize();
if(ID3v2Tag()->header()->tagSize() <= 0)
d->tag.set(ID3v2Index, 0);
d->tag.set(FlacID3v2Index, 0);
else
d->hasID3v2 = true;
}
@@ -289,7 +394,7 @@ void FLAC::File::read(bool readProperties, Properties::ReadStyle propertiesStyle
d->ID3v1Location = findID3v1();
if(d->ID3v1Location >= 0) {
d->tag.set(ID3v1Index, new ID3v1::Tag(this, d->ID3v1Location));
d->tag.set(FlacID3v1Index, new ID3v1::Tag(this, d->ID3v1Location));
d->hasID3v1 = true;
}
@@ -301,27 +406,25 @@ void FLAC::File::read(bool readProperties, Properties::ReadStyle propertiesStyle
return;
if(d->hasXiphComment)
d->tag.set(XiphIndex, new Ogg::XiphComment(xiphCommentData()));
d->tag.set(FlacXiphIndex, new Ogg::XiphComment(d->xiphCommentData));
else
d->tag.set(XiphIndex, new Ogg::XiphComment);
d->tag.set(FlacXiphIndex, new Ogg::XiphComment);
if(readProperties)
d->properties = new Properties(streamInfoData(), streamLength(), propertiesStyle);
}
if(readProperties) {
ByteVector FLAC::File::streamInfoData()
{
return isValid() ? d->streamInfoData : ByteVector();
}
// First block should be the stream_info metadata
ByteVector FLAC::File::xiphCommentData() const
{
return (isValid() && d->hasXiphComment) ? d->xiphCommentData : ByteVector();
}
const ByteVector infoData = d->blocks.front()->render();
long FLAC::File::streamLength()
{
return d->streamLength;
long streamLength;
if(d->hasID3v1)
streamLength = d->ID3v1Location - d->streamStart;
else
streamLength = File::length() - d->streamStart;
d->properties = new Properties(infoData, streamLength);
}
}
void FLAC::File::scan()
@@ -366,7 +469,7 @@ void FLAC::File::scan()
char blockType = header[0] & 0x7f;
bool isLastBlock = (header[0] & 0x80) != 0;
uint length = header.mid(1, 3).toUInt();
uint length = header.toUInt(1U, 3U);
// First block should be the stream_info metadata
@@ -376,8 +479,7 @@ void FLAC::File::scan()
return;
}
d->streamInfoData = readBlock(length);
d->blocks.append(new UnknownMetadataBlock(blockType, d->streamInfoData));
d->blocks.append(new UnknownMetadataBlock(blockType, readBlock(length)));
nextBlockOffset += length + 4;
// Search through the remaining metadata
@@ -386,11 +488,17 @@ void FLAC::File::scan()
header = readBlock(4);
blockType = header[0] & 0x7f;
isLastBlock = (header[0] & 0x80) != 0;
length = header.mid(1, 3).toUInt();
length = header.toUInt(1U, 3U);
ByteVector data = readBlock(length);
if(length == 0 && blockType != MetadataBlock::Padding) {
debug("FLAC::File::scan() -- Zero-sized metadata block found");
setValid(false);
return;
}
const ByteVector data = readBlock(length);
if(data.size() != length) {
debug("FLAC::File::scan() -- FLAC stream corrupted");
debug("FLAC::File::scan() -- Failed to read a metadata block");
setValid(false);
return;
}
@@ -413,7 +521,7 @@ void FLAC::File::scan()
block = picture;
}
else {
debug("FLAC::File::scan() -- invalid picture found, discarting");
debug("FLAC::File::scan() -- invalid picture found, discarding");
delete picture;
}
}
@@ -441,10 +549,6 @@ void FLAC::File::scan()
// End of metadata, now comes the datastream
d->streamStart = nextBlockOffset;
d->streamLength = File::length() - d->streamStart;
if(d->hasID3v1)
d->streamLength -= 128;
d->scanned = true;
}
@@ -475,36 +579,3 @@ long FLAC::File::findID3v2()
return -1;
}
List<FLAC::Picture *> FLAC::File::pictureList()
{
List<Picture *> pictures;
for(uint i = 0; i < d->blocks.size(); i++) {
Picture *picture = dynamic_cast<Picture *>(d->blocks[i]);
if(picture) {
pictures.append(picture);
}
}
return pictures;
}
void FLAC::File::addPicture(Picture *picture)
{
d->blocks.append(picture);
}
void FLAC::File::removePictures()
{
List<MetadataBlock *> newBlocks;
for(uint i = 0; i < d->blocks.size(); i++) {
Picture *picture = dynamic_cast<Picture *>(d->blocks[i]);
if(picture) {
delete picture;
}
else {
newBlocks.append(d->blocks[i]);
}
}
d->blocks = newBlocks;
}

View File

@@ -29,6 +29,7 @@
#include "taglib_export.h"
#include "tfile.h"
#include "tlist.h"
#include "tag.h"
#include "flacpicture.h"
#include "flacproperties.h"
@@ -36,7 +37,6 @@
namespace TagLib {
class Tag;
namespace ID3v2 { class FrameFactory; class Tag; }
namespace ID3v1 { class Tag; }
namespace Ogg { class XiphComment; }
@@ -46,7 +46,7 @@ namespace TagLib {
/*!
* This is implementation of FLAC metadata for non-Ogg FLAC files. At some
* point when Ogg / FLAC is more common there will be a similar implementation
* under the Ogg hiearchy.
* under the Ogg hierarchy.
*
* This supports ID3v1, ID3v2 and Xiph style comments as well as reading stream
* properties from the file.
@@ -67,9 +67,10 @@ namespace TagLib {
{
public:
/*!
* Contructs a FLAC file from \a file. If \a readProperties is true the
* file's audio properties will also be read using \a propertiesStyle. If
* false, \a propertiesStyle is ignored.
* 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.
@@ -78,12 +79,13 @@ namespace TagLib {
Properties::ReadStyle propertiesStyle = Properties::Average);
/*!
* Contructs a FLAC file from \a file. If \a readProperties is true the
* file's audio properties will also be read using \a propertiesStyle. If
* false, \a propertiesStyle is ignored.
* Constructs an FLAC file from \a file. If \a readProperties is true the
* file's audio properties will also be read.
*
* If this file contains and ID3v2 tag the frames will be created using
* \a frameFactory.
*
* \note In the current implementation, \a propertiesStyle is ignored.
*/
// BIC: merge with the above constructor
File(FileName file, ID3v2::FrameFactory *frameFactory,
@@ -91,12 +93,16 @@ namespace TagLib {
Properties::ReadStyle propertiesStyle = Properties::Average);
/*!
* Contructs a FLAC file from \a file. If \a readProperties is true the
* file's audio properties will also be read using \a propertiesStyle. If
* false, \a propertiesStyle is ignored.
* Constructs a FLAC file from \a stream. If \a readProperties is true the
* file's audio properties will also be read.
*
* \note TagLib will *not* take ownership of the stream, the caller is
* responsible for deleting it after the File object.
*
* If this file contains and ID3v2 tag the frames will be created using
* \a frameFactory.
*
* \note In the current implementation, \a propertiesStyle is ignored.
*/
// BIC: merge with the above constructor
File(IOStream *stream, ID3v2::FrameFactory *frameFactory,
@@ -118,6 +124,25 @@ 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
* relates to the Xiph comment only.
* Ignores any changes to ID3v1 or ID3v2 comments since they are not allowed
* in the FLAC specification.
*/
PropertyMap setProperties(const PropertyMap &);
/*!
* Returns the FLAC::Properties for this file. If no audio properties
* were read then this will return a null pointer.
@@ -130,45 +155,66 @@ namespace TagLib {
* has no XiphComment, one will be constructed from the ID3-tags.
*
* This returns true if the save was successful.
*
* \warning In the current implementation, it's dangerous to call save()
* repeatedly. At worst it will corrupt the file.
*/
virtual bool save();
/*!
* Returns a pointer to the ID3v2 tag of the file.
*
* If \a create is false (the default) this will return a null pointer
* If \a create is false (the default) this returns a null pointer
* if there is no valid ID3v2 tag. If \a create is true it will create
* an ID3v2 tag if one does not exist.
* an ID3v2 tag if one does not exist and returns a valid pointer.
*
* \note The Tag <b>is still</b> owned by the FLAC::File and should not be
* \note This may return 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.
*
* \note The Tag <b>is still</b> owned by the MPEG::File and should not be
* deleted by the user. It will be deleted when the file (object) is
* destroyed.
*
* \see hasID3v2Tag()
*/
ID3v2::Tag *ID3v2Tag(bool create = false);
/*!
* Returns a pointer to the ID3v1 tag of the file.
*
* If \a create is false (the default) this will return a null pointer
* if there is no valid ID3v1 tag. If \a create is true it will create
* an ID3v1 tag if one does not exist.
* If \a create is false (the default) this returns a null pointer
* if there is no valid APE tag. If \a create is true it will create
* an APE tag if one does not exist and returns a valid pointer.
*
* \note The Tag <b>is still</b> owned by the FLAC::File and should not be
* \note This may return a valid pointer regardless of whether or not the
* file on disk has an ID3v1 tag. Use hasID3v1Tag() to check if the file
* on disk actually has an ID3v1 tag.
*
* \note The Tag <b>is still</b> owned by the MPEG::File and should not be
* deleted by the user. It will be deleted when the file (object) is
* destroyed.
*
* \see hasID3v1Tag()
*/
ID3v1::Tag *ID3v1Tag(bool create = false);
/*!
* Returns a pointer to the XiphComment for the file.
*
* If \a create is false (the default) this will return a null pointer
* If \a create is false (the default) this returns a null pointer
* if there is no valid XiphComment. If \a create is true it will create
* a XiphComment if one does not exist.
* a XiphComment if one does not exist and returns a valid pointer.
*
* \note This may return a valid pointer regardless of whether or not the
* file on disk has a XiphComment. Use hasXiphComment() to check if the
* file on disk actually has a XiphComment.
*
* \note The Tag <b>is still</b> owned by the FLAC::File and should not be
* deleted by the user. It will be deleted when the file (object) is
* destroyed.
*
* \see hasXiphComment()
*/
Ogg::XiphComment *xiphComment(bool create = false);
@@ -178,6 +224,7 @@ namespace TagLib {
* when
*
* \see ID3v2FrameFactory
* \deprecated This value should be passed in via the constructor
*/
void setID3v2FrameFactory(const ID3v2::FrameFactory *factory);
@@ -185,7 +232,7 @@ namespace TagLib {
* Returns the block of data used by FLAC::Properties for parsing the
* stream properties.
*
* \deprecated This method will not be public in a future release.
* \deprecated Always returns an empty vector.
*/
ByteVector streamInfoData(); // BIC: remove
@@ -193,7 +240,7 @@ namespace TagLib {
* Returns the length of the audio-stream, used by FLAC::Properties for
* calculating the bitrate.
*
* \deprecated This method will not be public in a future release.
* \deprecated Always returns zero.
*/
long streamLength(); // BIC: remove
@@ -202,6 +249,12 @@ namespace TagLib {
*/
List<Picture *> pictureList();
/*!
* Removes an attached picture. If \a del is true the picture's memory
* will be freed; if it is false, it must be deleted by the user.
*/
void removePicture(Picture *picture, bool del = true);
/*!
* Remove all attached images.
*/
@@ -215,16 +268,35 @@ namespace TagLib {
*/
void addPicture(Picture *picture);
/*!
* Returns whether or not the file on disk actually has a XiphComment.
*
* \see xiphComment()
*/
bool hasXiphComment() const;
/*!
* Returns whether or not the file on disk actually has an ID3v1 tag.
*
* \see ID3v1Tag()
*/
bool hasID3v1Tag() const;
/*!
* Returns whether or not the file on disk actually has an ID3v2 tag.
*
* \see ID3v2Tag()
*/
bool hasID3v2Tag() const;
private:
File(const File &);
File &operator=(const File &);
void read(bool readProperties, Properties::ReadStyle propertiesStyle);
void read(bool readProperties);
void scan();
long findID3v2();
long findID3v1();
ByteVector xiphCommentData() const;
long findPaddingBreak(long nextPageOffset, long targetOffset, bool *isLast);
class FilePrivate;
FilePrivate *d;

View File

@@ -23,17 +23,13 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <taglib.h>
#include <tdebug.h>
#include "flacmetadatablock.h"
using namespace TagLib;
class FLAC::MetadataBlock::MetadataBlockPrivate
class FLAC::MetadataBlock::MetadataBlockPrivate
{
public:
MetadataBlockPrivate() {}

View File

@@ -23,17 +23,13 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <taglib.h>
#include <tdebug.h>
#include "flacpicture.h"
using namespace TagLib;
class FLAC::Picture::PicturePrivate
class FLAC::Picture::PicturePrivate
{
public:
PicturePrivate() :
@@ -82,10 +78,10 @@ bool FLAC::Picture::parse(const ByteVector &data)
return false;
}
int pos = 0;
d->type = FLAC::Picture::Type(data.mid(pos, 4).toUInt());
uint pos = 0;
d->type = FLAC::Picture::Type(data.toUInt(pos));
pos += 4;
uint mimeTypeLength = data.mid(pos, 4).toUInt();
uint mimeTypeLength = data.toUInt(pos);
pos += 4;
if(pos + mimeTypeLength + 24 > data.size()) {
debug("Invalid picture block.");
@@ -93,7 +89,7 @@ bool FLAC::Picture::parse(const ByteVector &data)
}
d->mimeType = String(data.mid(pos, mimeTypeLength), String::UTF8);
pos += mimeTypeLength;
uint descriptionLength = data.mid(pos, 4).toUInt();
uint descriptionLength = data.toUInt(pos);
pos += 4;
if(pos + descriptionLength + 20 > data.size()) {
debug("Invalid picture block.");
@@ -101,15 +97,15 @@ bool FLAC::Picture::parse(const ByteVector &data)
}
d->description = String(data.mid(pos, descriptionLength), String::UTF8);
pos += descriptionLength;
d->width = data.mid(pos, 4).toUInt();
d->width = data.toUInt(pos);
pos += 4;
d->height = data.mid(pos, 4).toUInt();
d->height = data.toUInt(pos);
pos += 4;
d->colorDepth = data.mid(pos, 4).toUInt();
d->colorDepth = data.toUInt(pos);
pos += 4;
d->numColors = data.mid(pos, 4).toUInt();
d->numColors = data.toUInt(pos);
pos += 4;
uint dataLength = data.mid(pos, 4).toUInt();
uint dataLength = data.toUInt(pos);
pos += 4;
if(pos + dataLength > data.size()) {
debug("Invalid picture block.");
@@ -117,7 +113,7 @@ bool FLAC::Picture::parse(const ByteVector &data)
}
d->data = data.mid(pos, dataLength);
return true;
return true;
}
ByteVector FLAC::Picture::render() const

View File

@@ -34,24 +34,20 @@ using namespace TagLib;
class FLAC::Properties::PropertiesPrivate
{
public:
PropertiesPrivate(ByteVector d, long st, ReadStyle s) :
data(d),
streamLength(st),
style(s),
PropertiesPrivate() :
length(0),
bitrate(0),
sampleRate(0),
sampleWidth(0),
channels(0) {}
bitsPerSample(0),
channels(0),
sampleFrames(0) {}
ByteVector data;
long streamLength;
ReadStyle style;
int length;
int bitrate;
int sampleRate;
int sampleWidth;
int bitsPerSample;
int channels;
unsigned long long sampleFrames;
ByteVector signature;
};
@@ -59,16 +55,18 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
FLAC::Properties::Properties(ByteVector data, long streamLength, ReadStyle style) : AudioProperties(style)
FLAC::Properties::Properties(ByteVector data, long streamLength, ReadStyle style) :
AudioProperties(style),
d(new PropertiesPrivate())
{
d = new PropertiesPrivate(data, streamLength, style);
read();
read(data, streamLength);
}
FLAC::Properties::Properties(File *file, ReadStyle style) : AudioProperties(style)
FLAC::Properties::Properties(File *, ReadStyle style) :
AudioProperties(style),
d(new PropertiesPrivate())
{
d = new PropertiesPrivate(file->streamInfoData(), file->streamLength(), style);
read();
debug("FLAC::Properties::Properties() - This constructor is no longer used.");
}
FLAC::Properties::~Properties()
@@ -77,6 +75,16 @@ FLAC::Properties::~Properties()
}
int FLAC::Properties::length() const
{
return lengthInSeconds();
}
int FLAC::Properties::lengthInSeconds() const
{
return d->length / 1000;
}
int FLAC::Properties::lengthInMilliseconds() const
{
return d->length;
}
@@ -91,9 +99,14 @@ int FLAC::Properties::sampleRate() const
return d->sampleRate;
}
int FLAC::Properties::bitsPerSample() const
{
return d->bitsPerSample;
}
int FLAC::Properties::sampleWidth() const
{
return d->sampleWidth;
return bitsPerSample();
}
int FLAC::Properties::channels() const
@@ -101,6 +114,11 @@ int FLAC::Properties::channels() const
return d->channels;
}
unsigned long long FLAC::Properties::sampleFrames() const
{
return d->sampleFrames;
}
ByteVector FLAC::Properties::signature() const
{
return d->signature;
@@ -110,14 +128,14 @@ ByteVector FLAC::Properties::signature() const
// private members
////////////////////////////////////////////////////////////////////////////////
void FLAC::Properties::read()
void FLAC::Properties::read(const ByteVector &data, long streamLength)
{
if(d->data.size() < 18) {
if(data.size() < 18) {
debug("FLAC::Properties::read() - FLAC properties must contain at least 18 bytes.");
return;
}
int pos = 0;
uint pos = 0;
// Minimum block size (in samples)
pos += 2;
@@ -131,28 +149,28 @@ void FLAC::Properties::read()
// Maximum frame size (in bytes)
pos += 3;
uint flags = d->data.mid(pos, 4).toUInt(true);
d->sampleRate = flags >> 12;
d->channels = ((flags >> 9) & 7) + 1;
d->sampleWidth = ((flags >> 4) & 31) + 1;
const uint flags = data.toUInt(pos, true);
pos += 4;
d->sampleRate = flags >> 12;
d->channels = ((flags >> 9) & 7) + 1;
d->bitsPerSample = ((flags >> 4) & 31) + 1;
// The last 4 bits are the most significant 4 bits for the 36 bit
// stream length in samples. (Audio files measured in days)
uint highLength =d->sampleRate > 0 ? (((flags & 0xf) << 28) / d->sampleRate) << 4 : 0;
const ulonglong hi = flags & 0xf;
const ulonglong lo = data.toUInt(pos, true);
pos += 4;
d->length = d->sampleRate > 0 ?
(d->data.mid(pos, 4).toUInt(true)) / d->sampleRate + highLength : 0;
pos += 4;
d->sampleFrames = (hi << 32) | lo;
// Uncompressed bitrate:
if(d->sampleFrames > 0 && d->sampleRate > 0) {
const double length = d->sampleFrames * 1000.0 / d->sampleRate;
d->length = static_cast<int>(length + 0.5);
d->bitrate = static_cast<int>(streamLength * 8.0 / length + 0.5);
}
//d->bitrate = ((d->sampleRate * d->channels) / 1000) * d->sampleWidth;
// Real bitrate:
d->bitrate = d->length > 0 ? ((d->streamLength * 8UL) / d->length) / 1000 : 0;
d->signature = d->data.mid(pos, 32);
if(data.size() >= pos + 16)
d->signature = data.mid(pos, 16);
}

View File

@@ -64,22 +64,72 @@ namespace TagLib {
*/
virtual ~Properties();
// Reimplementations.
/*!
* Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second.
*
* \note This method is just an alias of lengthInSeconds().
*
* \deprecated
*/
virtual int length() const;
/*!
* Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second.
*
* \see lengthInMilliseconds()
*/
// BIC: make virtual
int lengthInSeconds() const;
/*!
* Returns the length of the file in milliseconds.
*
* \see lengthInSeconds()
*/
// BIC: make virtual
int lengthInMilliseconds() const;
/*!
* Returns the average bit rate of the file in kb/s.
*/
virtual int bitrate() const;
/*!
* Returns the sample rate in Hz.
*/
virtual int sampleRate() const;
/*!
* Returns the number of audio channels.
*/
virtual int channels() const;
/*!
* Returns the number of bits per audio sample as read from the FLAC
* identification header.
*/
int bitsPerSample() const;
/*!
* Returns the sample width as read from the FLAC identification
* header.
*
* \note This method is just an alias of bitsPerSample().
*
* \deprecated
*/
int sampleWidth() const;
/*!
* Return the number of sample frames.
*/
unsigned long long sampleFrames() const;
/*!
* Returns the MD5 signature of the uncompressed audio stream as read
* from the stream info header header.
* from the stream info header.
*/
ByteVector signature() const;
@@ -87,7 +137,7 @@ namespace TagLib {
Properties(const Properties &);
Properties &operator=(const Properties &);
void read();
void read(const ByteVector &data, long streamLength);
class PropertiesPrivate;
PropertiesPrivate *d;

View File

@@ -23,10 +23,6 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <taglib.h>
#include <tdebug.h>
#include <tstring.h>
@@ -34,7 +30,7 @@
using namespace TagLib;
class FLAC::UnknownMetadataBlock::UnknownMetadataBlockPrivate
class FLAC::UnknownMetadataBlock::UnknownMetadataBlockPrivate
{
public:
UnknownMetadataBlockPrivate() : code(0) {}

View File

@@ -23,6 +23,7 @@
#include "itfile.h"
#include "tdebug.h"
#include "modfileprivate.h"
#include "tpropertymap.h"
using namespace TagLib;
using namespace IT;
@@ -44,7 +45,8 @@ IT::File::File(FileName file, bool readProperties,
Mod::FileBase(file),
d(new FilePrivate(propertiesStyle))
{
read(readProperties);
if(isOpen())
read(readProperties);
}
IT::File::File(IOStream *stream, bool readProperties,
@@ -52,7 +54,8 @@ IT::File::File(IOStream *stream, bool readProperties,
Mod::FileBase(stream),
d(new FilePrivate(propertiesStyle))
{
read(readProperties);
if(isOpen())
read(readProperties);
}
IT::File::~File()
@@ -65,6 +68,16 @@ 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
{
return &d->properties;
@@ -114,10 +127,10 @@ bool IT::File::save()
ulong sampleOffset = 0;
if(!readU32L(sampleOffset))
return false;
seek(sampleOffset + 20);
if((i + instrumentCount) < lines.size())
if((TagLib::uint)(i + instrumentCount) < lines.size())
writeString(lines[i + instrumentCount], 25);
else
writeString(String::null, 25);
@@ -144,7 +157,7 @@ bool IT::File::save()
if(!readU16L(special))
return false;
long fileSize = this->length();
ulong fileSize = File::length();
if(special & Properties::MessageAttached) {
seek(54);
if(!readU16L(messageLength) || !readU32L(messageOffset))
@@ -160,7 +173,7 @@ bool IT::File::save()
writeU16L(special | 0x1);
}
if((messageOffset + messageLength) >= fileSize) {
if(messageOffset + messageLength >= fileSize) {
// append new message
seek(54);
writeU16L(message.size());
@@ -195,7 +208,7 @@ void IT::File::read(bool)
READ_U16L_AS(length);
READ_U16L_AS(instrumentCount);
READ_U16L_AS(sampleCount);
d->properties.setInstrumentCount(instrumentCount);
d->properties.setSampleCount(sampleCount);
READ_U16L(d->properties.setPatternCount);
@@ -240,10 +253,11 @@ void IT::File::read(bool)
// But this always gives 64 channels for all my files anyway.
// Strangely VLC does report other values. I wonder how VLC
// gets it's values.
if(pannings[i] < 128 && volumes[i] > 0) ++ channels;
if((unsigned char) pannings[i] < 128 && volumes[i] > 0)
++channels;
}
d->properties.setChannels(channels);
// real length might be shorter because of skips and terminator
ushort realLength = 0;
for(ushort i = 0; i < length; ++ i) {
@@ -275,11 +289,11 @@ void IT::File::read(bool)
READ_STRING_AS(instrumentName, 26);
comment.append(instrumentName);
}
for(ushort i = 0; i < sampleCount; ++ i) {
seek(192L + length + ((long)instrumentCount << 2) + ((long)i << 2));
READ_U32L_AS(sampleOffset);
seek(sampleOffset);
ByteVector sampleMagic = readBlock(4);
@@ -305,7 +319,7 @@ void IT::File::read(bool)
READ_BYTE_AS(vibratoRate);
READ_BYTE_AS(vibratoType);
*/
comment.append(sampleName);
}

View File

@@ -36,20 +36,27 @@ namespace TagLib {
class TAGLIB_EXPORT File : public Mod::FileBase {
public:
/*!
* Contructs a Impulse Tracker 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.
* Constructs a Impulse Tracker file from \a file.
*
* \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,
AudioProperties::ReadStyle propertiesStyle =
AudioProperties::Average);
/*!
* Contructs a Impulse Tracker 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.
* Constructs a Impulse Tracker file from \a stream.
*
* \note In the current implementation, both \a readProperties and
* \a propertiesStyle are ignored. The audio properties are always
* read.
*
* \note TagLib will *not* take ownership of the stream, the caller is
* responsible for deleting it after the File object.
*/
File(IOStream *stram, bool readProperties = true,
File(IOStream *stream, bool readProperties = true,
AudioProperties::ReadStyle propertiesStyle =
AudioProperties::Average);
@@ -60,6 +67,18 @@ 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.
@@ -74,6 +93,7 @@ namespace TagLib {
*/
bool save();
private:
File(const File &);
File &operator=(const File &);

View File

@@ -79,6 +79,16 @@ int IT::Properties::length() const
return 0;
}
int IT::Properties::lengthInSeconds() const
{
return 0;
}
int IT::Properties::lengthInMilliseconds() const
{
return 0;
}
int IT::Properties::bitrate() const
{
return 0;
@@ -94,7 +104,7 @@ int IT::Properties::channels() const
return d->channels;
}
ushort IT::Properties::lengthInPatterns() const
TagLib::ushort IT::Properties::lengthInPatterns() const
{
return d->lengthInPatterns;
}
@@ -104,37 +114,37 @@ bool IT::Properties::stereo() const
return d->flags & Stereo;
}
ushort IT::Properties::instrumentCount() const
TagLib::ushort IT::Properties::instrumentCount() const
{
return d->instrumentCount;
}
ushort IT::Properties::sampleCount() const
TagLib::ushort IT::Properties::sampleCount() const
{
return d->sampleCount;
}
ushort IT::Properties::patternCount() const
TagLib::ushort IT::Properties::patternCount() const
{
return d->patternCount;
}
ushort IT::Properties::version() const
TagLib::ushort IT::Properties::version() const
{
return d->version;
}
ushort IT::Properties::compatibleVersion() const
TagLib::ushort IT::Properties::compatibleVersion() const
{
return d->compatibleVersion;
}
ushort IT::Properties::flags() const
TagLib::ushort IT::Properties::flags() const
{
return d->flags;
}
ushort IT::Properties::special() const
TagLib::ushort IT::Properties::special() const
{
return d->special;
}

View File

@@ -50,11 +50,13 @@ namespace TagLib {
Properties(AudioProperties::ReadStyle propertiesStyle);
virtual ~Properties();
int length() const;
int bitrate() const;
int sampleRate() const;
int channels() const;
int length() const;
int lengthInSeconds() const;
int lengthInMilliseconds() const;
int bitrate() const;
int sampleRate() const;
int channels() const;
ushort lengthInPatterns() const;
bool stereo() const;
@@ -72,9 +74,7 @@ namespace TagLib {
uchar panningSeparation() const;
uchar pitchWheelDepth() const;
protected:
void setChannels(int channels);
void setLengthInPatterns(ushort lengthInPatterns);
void setInstrumentCount(ushort instrumentCount);
void setSampleCount (ushort sampleCount);

View File

@@ -23,6 +23,7 @@
#include "tstringlist.h"
#include "tdebug.h"
#include "modfileprivate.h"
#include "tpropertymap.h"
using namespace TagLib;
using namespace Mod;
@@ -44,7 +45,8 @@ Mod::File::File(FileName file, bool readProperties,
Mod::FileBase(file),
d(new FilePrivate(propertiesStyle))
{
read(readProperties);
if(isOpen())
read(readProperties);
}
Mod::File::File(IOStream *stream, bool readProperties,
@@ -52,7 +54,8 @@ Mod::File::File(IOStream *stream, bool readProperties,
Mod::FileBase(stream),
d(new FilePrivate(propertiesStyle))
{
read(readProperties);
if(isOpen())
read(readProperties);
}
Mod::File::~File()
@@ -70,6 +73,16 @@ Mod::Properties *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()) {

View File

@@ -33,57 +33,78 @@ namespace TagLib {
namespace Mod {
class TAGLIB_EXPORT File : public TagLib::Mod::FileBase {
public:
/*!
* Contructs a Protracker 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);
class TAGLIB_EXPORT File : public TagLib::Mod::FileBase
{
public:
/*!
* Constructs a Protracker file from \a file.
*
* \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,
AudioProperties::ReadStyle propertiesStyle =
AudioProperties::Average);
/*!
* Contructs a Protracker 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.
*/
File(IOStream *stream, bool readProperties = true,
AudioProperties::ReadStyle propertiesStyle =
AudioProperties::Average);
/*!
* Constructs a Protracker file from \a stream.
*
* \note In the current implementation, both \a readProperties and
* \a propertiesStyle are ignored. The audio properties are always
* read.
*
* \note TagLib will *not* take ownership of the stream, the caller is
* responsible for deleting it after the File object.
*/
File(IOStream *stream, bool readProperties = true,
AudioProperties::ReadStyle propertiesStyle =
AudioProperties::Average);
/*!
* Destroys this instance of the File.
*/
virtual ~File();
/*!
* Destroys this instance of the File.
*/
virtual ~File();
Mod::Tag *tag() const;
Mod::Tag *tag() const;
/*!
* Returns the Mod::Properties for this file. If no audio properties
* were read then this will return a null pointer.
*/
Mod::Properties *audioProperties() const;
/*!
* Implements the unified property interface -- export function.
* Forwards to Mod::Tag::properties().
*/
PropertyMap properties() const;
/*!
* Save the file.
* This is the same as calling save(AllTags);
*
* \note Saving Protracker tags is not supported.
*/
bool save();
/*!
* 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;
private:
File(const File &);
File &operator=(const File &);
/*!
* Save the file.
* This is the same as calling save(AllTags);
*
* \note Saving Protracker tags is not supported.
*/
bool save();
void read(bool readProperties);
private:
File(const File &);
File &operator=(const File &);
class FilePrivate;
FilePrivate *d;
void read(bool readProperties);
class FilePrivate;
FilePrivate *d;
};
}
}
#endif

View File

@@ -31,7 +31,9 @@
#include <algorithm>
namespace TagLib {
namespace Mod {
class TAGLIB_EXPORT FileBase : public TagLib::File
{
protected:
@@ -52,7 +54,9 @@ namespace TagLib {
bool readU16B(ushort &number);
bool readU32B(ulong &number);
};
}
}
#endif

View File

@@ -33,7 +33,7 @@ public:
lengthInPatterns(0)
{
}
int channels;
uint instrumentCount;
uchar lengthInPatterns;
@@ -55,6 +55,16 @@ int Mod::Properties::length() const
return 0;
}
int Mod::Properties::lengthInSeconds() const
{
return 0;
}
int Mod::Properties::lengthInMilliseconds() const
{
return 0;
}
int Mod::Properties::bitrate() const
{
return 0;
@@ -70,7 +80,7 @@ int Mod::Properties::channels() const
return d->channels;
}
uint Mod::Properties::instrumentCount() const
TagLib::uint Mod::Properties::instrumentCount() const
{
return d->instrumentCount;
}

View File

@@ -26,35 +26,42 @@
#include "audioproperties.h"
namespace TagLib {
namespace Mod {
class TAGLIB_EXPORT Properties : public AudioProperties {
friend class File;
class TAGLIB_EXPORT Properties : public AudioProperties
{
public:
Properties(AudioProperties::ReadStyle propertiesStyle);
virtual ~Properties();
int length() const;
int bitrate() const;
int sampleRate() const;
int channels() const;
uint instrumentCount() const;
int length() const;
int lengthInSeconds() const;
int lengthInMilliseconds() const;
int bitrate() const;
int sampleRate() const;
int channels() const;
uint instrumentCount() const;
uchar lengthInPatterns() const;
protected:
void setChannels(int channels);
void setInstrumentCount(uint sampleCount);
void setLengthInPatterns(uchar lengthInPatterns);
private:
friend class File;
Properties(const Properties&);
Properties &operator=(const Properties&);
class PropertiesPrivate;
PropertiesPrivate *d;
};
}
}
#endif

View File

@@ -20,6 +20,8 @@
***************************************************************************/
#include "modtag.h"
#include "tstringlist.h"
#include "tpropertymap.h"
using namespace TagLib;
using namespace Mod;
@@ -71,12 +73,12 @@ String Mod::Tag::genre() const
return String::null;
}
uint Mod::Tag::year() const
TagLib::uint Mod::Tag::year() const
{
return 0;
}
uint Mod::Tag::track() const
TagLib::uint Mod::Tag::track() const
{
return 0;
}
@@ -120,3 +122,47 @@ void Mod::Tag::setTrackerName(const String &trackerName)
{
d->trackerName = trackerName;
}
PropertyMap Mod::Tag::properties() const
{
PropertyMap properties;
properties["TITLE"] = d->title;
properties["COMMENT"] = d->comment;
if(!(d->trackerName.isNull()))
properties["TRACKERNAME"] = d->trackerName;
return properties;
}
PropertyMap Mod::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::null;
if(properties.contains("COMMENT")) {
d->comment = properties["COMMENT"].front();
oneValueSet.append("COMMENT");
} else
d->comment = String::null;
if(properties.contains("TRACKERNAME")) {
d->trackerName = properties["TRACKERNAME"].front();
oneValueSet.append("TRACKERNAME");
} else
d->trackerName = String::null;
// 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::ConstIterator 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

@@ -25,7 +25,9 @@
#include "tag.h"
namespace TagLib {
namespace Mod {
/*!
* Tags for module files (Mod, S3M, IT, XM).
*
@@ -95,7 +97,7 @@ namespace TagLib {
* Sets the title to \a title. If \a title is String::null then this
* value will be cleared.
*
* The length limits per file type are (1 characetr = 1 byte):
* The length limits per file type are (1 character = 1 byte):
* Mod 20 characters, S3M 27 characters, IT 25 characters and XM 20
* characters.
*/
@@ -124,7 +126,7 @@ namespace TagLib {
* an thus the line length in comments are limited. Too big comments
* will be truncated.
*
* The line length limits per file type are (1 characetr = 1 byte):
* The line length limits per file type are (1 character = 1 byte):
* Mod 22 characters, S3M 27 characters, IT 25 characters and XM 22
* characters.
*/
@@ -148,15 +150,31 @@ namespace TagLib {
/*!
* Sets the tracker name to \a trackerName. If \a trackerName is
* String::null then this value will be cleared.
*
*
* Note that only XM files support this tag. Setting the
* tracker name for other module file formats will be ignored.
*
*
* The length of this tag is limited to 20 characters (1 character
* = 1 byte).
*/
void setTrackerName(const String &trackerName);
/*!
* Implements the unified property interface -- export function.
* Since the module 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 module file tag, any tags besides
* COMMENT, TITLE and, if it is an XM file, TRACKERNAME, 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 &);
@@ -164,7 +182,9 @@ namespace TagLib {
class TagPrivate;
TagPrivate *d;
};
}
}
#endif

View File

@@ -27,6 +27,8 @@
#include <config.h>
#endif
#include <climits>
#include <tdebug.h>
#include <tstring.h>
#include "mp4atom.h"
@@ -52,22 +54,27 @@ MP4::Atom::Atom(File *file)
return;
}
length = header.mid(0, 4).toUInt();
length = header.toUInt();
if (length == 1) {
long long longLength = file->readBlock(8).toLongLong();
if (longLength >= 8 && longLength <= 0xFFFFFFFF) {
// The atom has a 64-bit length, but it's actually a 32-bit value
length = (long)longLength;
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 < 8) {
if(length < 8) {
debug("MP4: Invalid atom size");
length = 0;
file->seek(0, File::End);

View File

@@ -1,5 +1,5 @@
/**************************************************************************
copyright : (C) 2007 by Lukáš Lalinský
copyright : (C) 2007,2011 by Lukáš Lalinský
email : lalinsky@gmail.com
**************************************************************************/
@@ -40,6 +40,40 @@ namespace TagLib {
class Atom;
typedef TagLib::List<Atom *> AtomList;
enum AtomDataType
{
TypeImplicit = 0, // for use with tags for which no type needs to be indicated because only one type is allowed
TypeUTF8 = 1, // without any count or null terminator
TypeUTF16 = 2, // also known as UTF-16BE
TypeSJIS = 3, // deprecated unless it is needed for special Japanese characters
TypeHTML = 6, // the HTML file header specifies which HTML version
TypeXML = 7, // the XML header must identify the DTD or schemas
TypeUUID = 8, // also known as GUID; stored as 16 bytes in binary (valid as an ID)
TypeISRC = 9, // stored as UTF-8 text (valid as an ID)
TypeMI3P = 10, // stored as UTF-8 text (valid as an ID)
TypeGIF = 12, // (deprecated) a GIF image
TypeJPEG = 13, // a JPEG image
TypePNG = 14, // a PNG image
TypeURL = 15, // absolute, in UTF-8 characters
TypeDuration = 16, // in milliseconds, 32-bit integer
TypeDateTime = 17, // in UTC, counting seconds since midnight, January 1, 1904; 32 or 64-bits
TypeGenred = 18, // a list of enumerated values
TypeInteger = 21, // a signed big-endian integer with length one of { 1,2,3,4,8 } bytes
TypeRIAAPA = 24, // RIAA parental advisory; { -1=no, 1=yes, 0=unspecified }, 8-bit integer
TypeUPC = 25, // Universal Product Code, in text UTF-8 format (valid as an ID)
TypeBMP = 27, // Windows bitmap image
TypeUndefined = 255 // undefined
};
struct AtomData {
AtomData(AtomDataType type, ByteVector data) : type(type), locale(0), data(data) {}
AtomDataType type;
int locale;
ByteVector data;
};
typedef TagLib::List<AtomData> AtomDataList;
class Atom
{
public:

View File

@@ -23,12 +23,9 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <taglib.h>
#include <tdebug.h>
#include "trefcounter.h"
#include "mp4coverart.h"
using namespace TagLib;

View File

@@ -29,6 +29,7 @@
#include "tlist.h"
#include "tbytevector.h"
#include "taglib_export.h"
#include "mp4atom.h"
namespace TagLib {
@@ -41,8 +42,11 @@ namespace TagLib {
* This describes the image type.
*/
enum Format {
JPEG = 0x0D,
PNG = 0x0E
JPEG = TypeJPEG,
PNG = TypePNG,
BMP = TypeBMP,
GIF = TypeGIF,
Unknown = TypeImplicit,
};
CoverArt(Format format, const ByteVector &data);

View File

@@ -23,58 +23,66 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <tdebug.h>
#include <tstring.h>
#include <tpropertymap.h>
#include "mp4atom.h"
#include "mp4tag.h"
#include "mp4file.h"
using namespace TagLib;
namespace
{
bool checkValid(const MP4::AtomList &list)
{
for(MP4::AtomList::ConstIterator it = list.begin(); it != list.end(); ++it) {
if((*it)->length == 0)
return false;
if(!checkValid((*it)->children))
return false;
}
return true;
}
}
class MP4::File::FilePrivate
{
public:
FilePrivate() : tag(0), atoms(0), properties(0)
{
}
FilePrivate() :
tag(0),
atoms(0),
properties(0) {}
~FilePrivate()
{
if(atoms) {
delete atoms;
atoms = 0;
}
if(tag) {
delete tag;
tag = 0;
}
if(properties) {
delete properties;
properties = 0;
}
delete atoms;
delete tag;
delete properties;
}
MP4::Tag *tag;
MP4::Atoms *atoms;
MP4::Tag *tag;
MP4::Atoms *atoms;
MP4::Properties *properties;
};
MP4::File::File(FileName file, bool readProperties, AudioProperties::ReadStyle audioPropertiesStyle)
: TagLib::File(file)
MP4::File::File(FileName file, bool readProperties, AudioProperties::ReadStyle) :
TagLib::File(file),
d(new FilePrivate())
{
d = new FilePrivate;
read(readProperties, audioPropertiesStyle);
if(isOpen())
read(readProperties);
}
MP4::File::File(IOStream *stream, bool readProperties, AudioProperties::ReadStyle audioPropertiesStyle)
: TagLib::File(stream)
MP4::File::File(IOStream *stream, bool readProperties, AudioProperties::ReadStyle) :
TagLib::File(stream),
d(new FilePrivate())
{
d = new FilePrivate;
read(readProperties, audioPropertiesStyle);
if(isOpen())
read(readProperties);
}
MP4::File::~File()
@@ -88,32 +96,35 @@ 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::File::audioProperties() const
{
return d->properties;
}
bool
MP4::File::checkValid(const MP4::AtomList &list)
{
for(uint i = 0; i < list.size(); i++) {
if(list[i]->length == 0)
return false;
if(!checkValid(list[i]->children))
return false;
}
return true;
}
void
MP4::File::read(bool readProperties, Properties::ReadStyle audioPropertiesStyle)
MP4::File::read(bool readProperties)
{
if(!isValid())
return;
d->atoms = new Atoms(this);
if (!checkValid(d->atoms->atoms)) {
if(!checkValid(d->atoms->atoms)) {
setValid(false);
return;
}
@@ -127,7 +138,7 @@ MP4::File::read(bool readProperties, Properties::ReadStyle audioPropertiesStyle)
d->tag = new Tag(this, d->atoms);
if(readProperties) {
d->properties = new Properties(this, d->atoms, audioPropertiesStyle);
d->properties = new Properties(this, d->atoms);
}
}

View File

@@ -49,24 +49,25 @@ namespace TagLib {
{
public:
/*!
* Contructs a MP4 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.
* 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, both \a readProperties and
* \a propertiesStyle are ignored.
* \note In the current implementation, \a propertiesStyle is ignored.
*/
File(FileName file, bool readProperties = true, Properties::ReadStyle audioPropertiesStyle = Properties::Average);
File(FileName file, bool readProperties = true,
Properties::ReadStyle audioPropertiesStyle = Properties::Average);
/*!
* Contructs a MP4 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.
* Constructs an MP4 file from \a stream. If \a readProperties is true the
* file's audio properties will also be read.
*
* \note In the current implementation, both \a readProperties and
* \a propertiesStyle are 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);
File(IOStream *stream, bool readProperties = true,
Properties::ReadStyle audioPropertiesStyle = Properties::Average);
/*!
* Destroys this instance of the File.
@@ -85,6 +86,22 @@ 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.
*/
@@ -94,13 +111,14 @@ namespace TagLib {
* Save the file.
*
* This returns true if the save was successful.
*
* \warning In the current implementation, it's dangerous to call save()
* repeatedly. At worst it will corrupt the file.
*/
bool save();
private:
void read(bool readProperties, Properties::ReadStyle audioPropertiesStyle);
bool checkValid(const MP4::AtomList &list);
void read(bool readProperties);
class FilePrivate;
FilePrivate *d;

View File

@@ -23,12 +23,9 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <taglib.h>
#include <tdebug.h>
#include "trefcounter.h"
#include "mp4item.h"
using namespace TagLib;
@@ -36,15 +33,20 @@ using namespace TagLib;
class MP4::Item::ItemPrivate : public RefCounter
{
public:
ItemPrivate() : RefCounter(), valid(true) {}
ItemPrivate() : RefCounter(), valid(true), atomDataType(TypeUndefined) {}
bool valid;
AtomDataType atomDataType;
union {
bool m_bool;
int m_int;
IntPair m_intPair;
uchar m_byte;
uint m_uint;
long long m_longlong;
};
StringList m_stringList;
ByteVectorList m_byteVectorList;
MP4::CoverArtList m_coverArtList;
};
@@ -89,6 +91,24 @@ MP4::Item::Item(int value)
d->m_int = value;
}
MP4::Item::Item(uchar value)
{
d = new ItemPrivate;
d->m_byte = value;
}
MP4::Item::Item(uint value)
{
d = new ItemPrivate;
d->m_uint = value;
}
MP4::Item::Item(long long value)
{
d = new ItemPrivate;
d->m_longlong = value;
}
MP4::Item::Item(int value1, int value2)
{
d = new ItemPrivate;
@@ -96,6 +116,12 @@ MP4::Item::Item(int value1, int value2)
d->m_intPair.second = value2;
}
MP4::Item::Item(const ByteVectorList &value)
{
d = new ItemPrivate;
d->m_byteVectorList = value;
}
MP4::Item::Item(const StringList &value)
{
d = new ItemPrivate;
@@ -108,6 +134,16 @@ MP4::Item::Item(const MP4::CoverArtList &value)
d->m_coverArtList = value;
}
void MP4::Item::setAtomDataType(MP4::AtomDataType type)
{
d->atomDataType = type;
}
MP4::AtomDataType MP4::Item::atomDataType() const
{
return d->atomDataType;
}
bool
MP4::Item::toBool() const
{
@@ -120,6 +156,24 @@ MP4::Item::toInt() const
return d->m_int;
}
uchar
MP4::Item::toByte() const
{
return d->m_byte;
}
TagLib::uint
MP4::Item::toUInt() const
{
return d->m_uint;
}
long long
MP4::Item::toLongLong() const
{
return d->m_longlong;
}
MP4::Item::IntPair
MP4::Item::toIntPair() const
{
@@ -132,6 +186,12 @@ MP4::Item::toStringList() const
return d->m_stringList;
}
ByteVectorList
MP4::Item::toByteVectorList() const
{
return d->m_byteVectorList;
}
MP4::CoverArtList
MP4::Item::toCoverArtList() const
{

View File

@@ -47,15 +47,26 @@ namespace TagLib {
~Item();
Item(int value);
Item(uchar value);
Item(uint value);
Item(long long value);
Item(bool value);
Item(int first, int second);
Item(const StringList &value);
Item(const ByteVectorList &value);
Item(const CoverArtList &value);
void setAtomDataType(AtomDataType type);
AtomDataType atomDataType() const;
int toInt() const;
uchar toByte() const;
uint toUInt() const;
long long toLongLong() const;
bool toBool() const;
IntPair toIntPair() const;
StringList toStringList() const;
ByteVectorList toByteVectorList() const;
CoverArtList toCoverArtList() const;
bool isValid() const;

View File

@@ -23,10 +23,6 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <tdebug.h>
#include <tstring.h>
#include "mp4file.h"
@@ -38,7 +34,14 @@ using namespace TagLib;
class MP4::Properties::PropertiesPrivate
{
public:
PropertiesPrivate() : length(0), bitrate(0), sampleRate(0), channels(0), bitsPerSample(0), encrypted(false) {}
PropertiesPrivate() :
length(0),
bitrate(0),
sampleRate(0),
channels(0),
bitsPerSample(0),
encrypted(false),
codec(MP4::Properties::Unknown) {}
int length;
int bitrate;
@@ -46,101 +49,18 @@ public:
int channels;
int bitsPerSample;
bool encrypted;
Codec codec;
};
MP4::Properties::Properties(File *file, MP4::Atoms *atoms, ReadStyle style)
: AudioProperties(style)
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
MP4::Properties::Properties(File *file, MP4::Atoms *atoms, ReadStyle style) :
AudioProperties(style),
d(new PropertiesPrivate())
{
d = new PropertiesPrivate;
MP4::Atom *moov = atoms->find("moov");
if(!moov) {
debug("MP4: Atom 'moov' not found");
return;
}
MP4::Atom *trak = 0;
ByteVector data;
MP4::AtomList trakList = moov->findall("trak");
for (unsigned int i = 0; i < trakList.size(); i++) {
trak = trakList[i];
MP4::Atom *hdlr = trak->find("mdia", "hdlr");
if(!hdlr) {
debug("MP4: Atom 'trak.mdia.hdlr' not found");
return;
}
file->seek(hdlr->offset);
data = file->readBlock(hdlr->length);
if(data.mid(16, 4) == "soun") {
break;
}
trak = 0;
}
if (!trak) {
debug("MP4: No audio tracks");
return;
}
MP4::Atom *mdhd = trak->find("mdia", "mdhd");
if(!mdhd) {
debug("MP4: Atom 'trak.mdia.mdhd' not found");
return;
}
file->seek(mdhd->offset);
data = file->readBlock(mdhd->length);
if(data[8] == 0) {
unsigned int unit = data.mid(20, 4).toUInt();
unsigned int length = data.mid(24, 4).toUInt();
d->length = length / unit;
}
else {
long long unit = data.mid(28, 8).toLongLong();
long long length = data.mid(36, 8).toLongLong();
d->length = int(length / unit);
}
MP4::Atom *atom = trak->find("mdia", "minf", "stbl", "stsd");
if(!atom) {
return;
}
file->seek(atom->offset);
data = file->readBlock(atom->length);
if(data.mid(20, 4) == "mp4a") {
d->channels = data.mid(40, 2).toShort();
d->bitsPerSample = data.mid(42, 2).toShort();
d->sampleRate = data.mid(46, 4).toUInt();
if(data.mid(56, 4) == "esds" && data[64] == 0x03) {
long pos = 65;
if(data.mid(pos, 3) == "\x80\x80\x80") {
pos += 3;
}
pos += 4;
if(data[pos] == 0x04) {
pos += 1;
if(data.mid(pos, 3) == "\x80\x80\x80") {
pos += 3;
}
pos += 10;
d->bitrate = (data.mid(pos, 4).toUInt() + 500) / 1000;
}
}
}
else if (data.mid(20, 4) == "alac") {
if (atom->length == 88 && data.mid(56, 4) == "alac") {
d->bitsPerSample = data.at(69);
d->channels = data.at(73);
d->bitrate = data.mid(80, 4).toUInt() / 1000;
d->sampleRate = data.mid(84, 4).toUInt();
}
}
MP4::Atom *drms = atom->find("drms");
if(drms) {
d->encrypted = true;
}
read(file, atoms);
}
MP4::Properties::~Properties()
@@ -162,6 +82,18 @@ MP4::Properties::sampleRate() const
int
MP4::Properties::length() const
{
return lengthInSeconds();
}
int
MP4::Properties::lengthInSeconds() const
{
return d->length / 1000;
}
int
MP4::Properties::lengthInMilliseconds() const
{
return d->length;
}
@@ -184,3 +116,119 @@ MP4::Properties::isEncrypted() const
return d->encrypted;
}
MP4::Properties::Codec
MP4::Properties::codec() const
{
return d->codec;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void
MP4::Properties::read(File *file, Atoms *atoms)
{
MP4::Atom *moov = atoms->find("moov");
if(!moov) {
debug("MP4: Atom 'moov' not found");
return;
}
MP4::Atom *trak = 0;
ByteVector data;
const MP4::AtomList trakList = moov->findall("trak");
for(MP4::AtomList::ConstIterator it = trakList.begin(); it != trakList.end(); ++it) {
trak = *it;
MP4::Atom *hdlr = trak->find("mdia", "hdlr");
if(!hdlr) {
debug("MP4: Atom 'trak.mdia.hdlr' not found");
return;
}
file->seek(hdlr->offset);
data = file->readBlock(hdlr->length);
if(data.containsAt("soun", 16)) {
break;
}
trak = 0;
}
if(!trak) {
debug("MP4: No audio tracks");
return;
}
MP4::Atom *mdhd = trak->find("mdia", "mdhd");
if(!mdhd) {
debug("MP4: Atom 'trak.mdia.mdhd' not found");
return;
}
file->seek(mdhd->offset);
data = file->readBlock(mdhd->length);
const uint version = data[8];
long long unit;
long long length;
if(version == 1) {
if(data.size() < 36 + 8) {
debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected");
return;
}
unit = data.toLongLong(28U);
length = data.toLongLong(36U);
}
else {
if(data.size() < 24 + 4) {
debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected");
return;
}
unit = data.toUInt(20U);
length = data.toUInt(24U);
}
if(unit > 0 && length > 0)
d->length = static_cast<int>(length * 1000.0 / unit);
MP4::Atom *atom = trak->find("mdia", "minf", "stbl", "stsd");
if(!atom) {
return;
}
file->seek(atom->offset);
data = file->readBlock(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);
if(data.containsAt("esds", 56) && data[64] == 0x03) {
uint pos = 65;
if(data.containsAt("\x80\x80\x80", pos)) {
pos += 3;
}
pos += 4;
if(data[pos] == 0x04) {
pos += 1;
if(data.containsAt("\x80\x80\x80", pos)) {
pos += 3;
}
pos += 10;
d->bitrate = static_cast<int>((data.toUInt(pos) + 500) / 1000.0 + 0.5);
}
}
}
else if(data.containsAt("alac", 20)) {
if(atom->length == 88 && data.containsAt("alac", 56)) {
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);
}
}
MP4::Atom *drms = atom->find("drms");
if(drms) {
d->encrypted = true;
}
}

View File

@@ -40,17 +40,75 @@ namespace TagLib {
class TAGLIB_EXPORT Properties : public AudioProperties
{
public:
enum Codec {
Unknown = 0,
AAC,
ALAC
};
Properties(File *file, Atoms *atoms, ReadStyle style = Average);
virtual ~Properties();
/*!
* Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second.
*
* \note This method is just an alias of lengthInSeconds().
*
* \deprecated
*/
virtual int length() const;
/*!
* Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second.
*
* \see lengthInMilliseconds()
*/
// BIC: make virtual
int lengthInSeconds() const;
/*!
* Returns the length of the file in milliseconds.
*
* \see lengthInSeconds()
*/
// BIC: make virtual
int lengthInMilliseconds() const;
/*!
* Returns the average bit rate of the file in kb/s.
*/
virtual int bitrate() const;
/*!
* Returns the sample rate in Hz.
*/
virtual int sampleRate() const;
/*!
* Returns the number of audio channels.
*/
virtual int channels() const;
/*!
* Returns the number of bits per audio sample.
*/
virtual int bitsPerSample() const;
/*!
* Returns whether or not the file is encrypted.
*/
bool isEncrypted() const;
/*!
* Returns the codec used in the file.
*/
Codec codec() const;
private:
void read(File *file, Atoms *atoms);
class PropertiesPrivate;
PropertiesPrivate *d;
};

View File

@@ -1,5 +1,5 @@
/**************************************************************************
copyright : (C) 2007 by Lukáš Lalinský
copyright : (C) 2007,2011 by Lukáš Lalinský
email : lalinsky@gmail.com
**************************************************************************/
@@ -23,12 +23,9 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <tdebug.h>
#include <tstring.h>
#include <tpropertymap.h>
#include "mp4atom.h"
#include "mp4tag.h"
#include "id3v1genres.h"
@@ -42,7 +39,7 @@ public:
~TagPrivate() {}
TagLib::File *file;
Atoms *atoms;
ItemListMap items;
ItemMap items;
};
MP4::Tag::Tag()
@@ -66,25 +63,36 @@ MP4::Tag::Tag(TagLib::File *file, MP4::Atoms *atoms)
MP4::Atom *atom = ilst->children[i];
file->seek(atom->offset + 8);
if(atom->name == "----") {
parseFreeForm(atom, file);
parseFreeForm(atom);
}
else if(atom->name == "trkn" || atom->name == "disk") {
parseIntPair(atom, file);
parseIntPair(atom);
}
else if(atom->name == "cpil" || atom->name == "pgap" || atom->name == "pcst") {
parseBool(atom, file);
else if(atom->name == "cpil" || atom->name == "pgap" || atom->name == "pcst" ||
atom->name == "hdvd") {
parseBool(atom);
}
else if(atom->name == "tmpo") {
parseInt(atom, file);
parseInt(atom);
}
else if(atom->name == "tvsn" || atom->name == "tves" || atom->name == "cnID" ||
atom->name == "sfID" || atom->name == "atID" || atom->name == "geID") {
parseUInt(atom);
}
else if(atom->name == "plID") {
parseLongLong(atom);
}
else if(atom->name == "stik" || atom->name == "rtng" || atom->name == "akID") {
parseByte(atom);
}
else if(atom->name == "gnre") {
parseGnre(atom, file);
parseGnre(atom);
}
else if(atom->name == "covr") {
parseCovr(atom, file);
parseCovr(atom);
}
else {
parseText(atom, file);
parseText(atom);
}
}
}
@@ -94,17 +102,22 @@ MP4::Tag::~Tag()
delete d;
}
ByteVectorList
MP4::Tag::parseData(MP4::Atom *atom, TagLib::File *file, int expectedFlags, bool freeForm)
MP4::AtomDataList
MP4::Tag::parseData2(const MP4::Atom *atom, int expectedFlags, bool freeForm)
{
ByteVectorList result;
ByteVector data = file->readBlock(atom->length - 8);
AtomDataList result;
ByteVector data = d->file->readBlock(atom->length - 8);
int i = 0;
unsigned int pos = 0;
while(pos < data.size()) {
int length = data.mid(pos, 4).toUInt();
ByteVector name = data.mid(pos + 4, 4);
int flags = data.mid(pos + 8, 4).toUInt();
const int length = static_cast<int>(data.toUInt(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));
if(freeForm && i < 2) {
if(i == 0 && name != "mean") {
debug("MP4: Unexpected atom \"" + name + "\", expecting \"mean\"");
@@ -114,7 +127,7 @@ MP4::Tag::parseData(MP4::Atom *atom, TagLib::File *file, int expectedFlags, bool
debug("MP4: Unexpected atom \"" + name + "\", expecting \"name\"");
return result;
}
result.append(data.mid(pos + 12, length - 12));
result.append(AtomData(AtomDataType(flags), data.mid(pos + 12, length - 12)));
}
else {
if(name != "data") {
@@ -122,7 +135,7 @@ MP4::Tag::parseData(MP4::Atom *atom, TagLib::File *file, int expectedFlags, bool
return result;
}
if(expectedFlags == -1 || flags == expectedFlags) {
result.append(data.mid(pos + 16, length - 16));
result.append(AtomData(AtomDataType(flags), data.mid(pos + 16, length - 16)));
}
}
pos += length;
@@ -131,116 +144,183 @@ MP4::Tag::parseData(MP4::Atom *atom, TagLib::File *file, int expectedFlags, bool
return result;
}
void
MP4::Tag::parseInt(MP4::Atom *atom, TagLib::File *file)
ByteVectorList
MP4::Tag::parseData(const MP4::Atom *atom, int expectedFlags, bool freeForm)
{
ByteVectorList data = parseData(atom, file);
AtomDataList data = parseData2(atom, expectedFlags, freeForm);
ByteVectorList result;
for(uint i = 0; i < data.size(); i++) {
result.append(data[i].data);
}
return result;
}
void
MP4::Tag::parseInt(const MP4::Atom *atom)
{
ByteVectorList data = parseData(atom);
if(data.size()) {
d->items.insert(atom->name, (int)data[0].toShort());
addItem(atom->name, (int)data[0].toShort());
}
}
void
MP4::Tag::parseGnre(MP4::Atom *atom, TagLib::File *file)
MP4::Tag::parseUInt(const MP4::Atom *atom)
{
ByteVectorList data = parseData(atom, file);
ByteVectorList data = parseData(atom);
if(data.size()) {
addItem(atom->name, data[0].toUInt());
}
}
void
MP4::Tag::parseLongLong(const MP4::Atom *atom)
{
ByteVectorList data = parseData(atom);
if(data.size()) {
addItem(atom->name, data[0].toLongLong());
}
}
void
MP4::Tag::parseByte(const MP4::Atom *atom)
{
ByteVectorList data = parseData(atom);
if(data.size()) {
addItem(atom->name, (uchar)data[0].at(0));
}
}
void
MP4::Tag::parseGnre(const MP4::Atom *atom)
{
ByteVectorList data = parseData(atom);
if(data.size()) {
int idx = (int)data[0].toShort();
if(!d->items.contains("\251gen") && idx > 0) {
d->items.insert("\251gen", StringList(ID3v1::genre(idx - 1)));
if(idx > 0) {
addItem("\251gen", StringList(ID3v1::genre(idx - 1)));
}
}
}
void
MP4::Tag::parseIntPair(MP4::Atom *atom, TagLib::File *file)
MP4::Tag::parseIntPair(const MP4::Atom *atom)
{
ByteVectorList data = parseData(atom, file);
ByteVectorList data = parseData(atom);
if(data.size()) {
int a = data[0].mid(2, 2).toShort();
int b = data[0].mid(4, 2).toShort();
d->items.insert(atom->name, MP4::Item(a, b));
const int a = data[0].toShort(2U);
const int b = data[0].toShort(4U);
addItem(atom->name, MP4::Item(a, b));
}
}
void
MP4::Tag::parseBool(MP4::Atom *atom, TagLib::File *file)
MP4::Tag::parseBool(const MP4::Atom *atom)
{
ByteVectorList data = parseData(atom, file);
ByteVectorList data = parseData(atom);
if(data.size()) {
bool value = data[0].size() ? data[0][0] != '\0' : false;
d->items.insert(atom->name, value);
addItem(atom->name, value);
}
}
void
MP4::Tag::parseText(MP4::Atom *atom, TagLib::File *file, int expectedFlags)
MP4::Tag::parseText(const MP4::Atom *atom, int expectedFlags)
{
ByteVectorList data = parseData(atom, file, expectedFlags);
ByteVectorList data = parseData(atom, expectedFlags);
if(data.size()) {
StringList value;
for(unsigned int i = 0; i < data.size(); i++) {
value.append(String(data[i], String::UTF8));
}
d->items.insert(atom->name, value);
addItem(atom->name, value);
}
}
void
MP4::Tag::parseFreeForm(MP4::Atom *atom, TagLib::File *file)
MP4::Tag::parseFreeForm(const MP4::Atom *atom)
{
ByteVectorList data = parseData(atom, file, 1, true);
AtomDataList data = parseData2(atom, -1, true);
if(data.size() > 2) {
StringList value;
for(unsigned int i = 2; i < data.size(); i++) {
value.append(String(data[i], String::UTF8));
String name = "----:" + String(data[0].data, String::UTF8) + ':' + String(data[1].data, String::UTF8);
AtomDataType type = data[2].type;
for(uint i = 2; i < data.size(); i++) {
if(data[i].type != type) {
debug("MP4: We currently don't support values with multiple types");
break;
}
}
if(type == TypeUTF8) {
StringList value;
for(uint i = 2; i < data.size(); i++) {
value.append(String(data[i].data, String::UTF8));
}
Item item(value);
item.setAtomDataType(type);
addItem(name, item);
}
else {
ByteVectorList value;
for(uint i = 2; i < data.size(); i++) {
value.append(data[i].data);
}
Item item(value);
item.setAtomDataType(type);
addItem(name, item);
}
String name = "----:" + data[0] + ':' + data[1];
d->items.insert(name, value);
}
}
void
MP4::Tag::parseCovr(MP4::Atom *atom, TagLib::File *file)
MP4::Tag::parseCovr(const MP4::Atom *atom)
{
MP4::CoverArtList value;
ByteVector data = file->readBlock(atom->length - 8);
ByteVector data = d->file->readBlock(atom->length - 8);
unsigned int pos = 0;
while(pos < data.size()) {
int length = data.mid(pos, 4).toUInt();
ByteVector name = data.mid(pos + 4, 4);
int flags = data.mid(pos + 8, 4).toUInt();
const int length = static_cast<int>(data.toUInt(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));
if(name != "data") {
debug("MP4: Unexpected atom \"" + name + "\", expecting \"data\"");
break;
}
if(flags == MP4::CoverArt::PNG || flags == MP4::CoverArt::JPEG) {
if(flags == TypeJPEG || flags == TypePNG || flags == TypeBMP ||
flags == TypeGIF || flags == TypeImplicit) {
value.append(MP4::CoverArt(MP4::CoverArt::Format(flags),
data.mid(pos + 16, length - 16)));
}
else {
debug("MP4: Unknown covr format " + String::number(flags));
}
pos += length;
}
if(value.size() > 0)
d->items.insert(atom->name, value);
addItem(atom->name, value);
}
ByteVector
MP4::Tag::padIlst(const ByteVector &data, int length)
MP4::Tag::padIlst(const ByteVector &data, int length) const
{
if (length == -1) {
if(length == -1) {
length = ((data.size() + 1023) & ~1023) - data.size();
}
return renderAtom("free", ByteVector(length, '\1'));
}
ByteVector
MP4::Tag::renderAtom(const ByteVector &name, const ByteVector &data)
MP4::Tag::renderAtom(const ByteVector &name, const ByteVector &data) const
{
return ByteVector::fromUInt(data.size() + 8) + name + data;
}
ByteVector
MP4::Tag::renderData(const ByteVector &name, int flags, const ByteVectorList &data)
MP4::Tag::renderData(const ByteVector &name, int flags, const ByteVectorList &data) const
{
ByteVector result;
for(unsigned int i = 0; i < data.size(); i++) {
@@ -250,44 +330,68 @@ MP4::Tag::renderData(const ByteVector &name, int flags, const ByteVectorList &da
}
ByteVector
MP4::Tag::renderBool(const ByteVector &name, MP4::Item &item)
MP4::Tag::renderBool(const ByteVector &name, const MP4::Item &item) const
{
ByteVectorList data;
data.append(ByteVector(1, item.toBool() ? '\1' : '\0'));
return renderData(name, 0x15, data);
return renderData(name, TypeInteger, data);
}
ByteVector
MP4::Tag::renderInt(const ByteVector &name, MP4::Item &item)
MP4::Tag::renderInt(const ByteVector &name, const MP4::Item &item) const
{
ByteVectorList data;
data.append(ByteVector::fromShort(item.toInt()));
return renderData(name, 0x15, data);
return renderData(name, TypeInteger, data);
}
ByteVector
MP4::Tag::renderIntPair(const ByteVector &name, MP4::Item &item)
MP4::Tag::renderUInt(const ByteVector &name, const MP4::Item &item) const
{
ByteVectorList data;
data.append(ByteVector::fromUInt(item.toUInt()));
return renderData(name, TypeInteger, data);
}
ByteVector
MP4::Tag::renderLongLong(const ByteVector &name, const MP4::Item &item) const
{
ByteVectorList data;
data.append(ByteVector::fromLongLong(item.toLongLong()));
return renderData(name, TypeInteger, data);
}
ByteVector
MP4::Tag::renderByte(const ByteVector &name, const MP4::Item &item) const
{
ByteVectorList data;
data.append(ByteVector(1, item.toByte()));
return renderData(name, TypeInteger, data);
}
ByteVector
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(2, '\0'));
return renderData(name, 0x00, data);
return renderData(name, TypeImplicit, data);
}
ByteVector
MP4::Tag::renderIntPairNoTrailing(const ByteVector &name, MP4::Item &item)
MP4::Tag::renderIntPairNoTrailing(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));
return renderData(name, 0x00, data);
return renderData(name, TypeImplicit, data);
}
ByteVector
MP4::Tag::renderText(const ByteVector &name, MP4::Item &item, int flags)
MP4::Tag::renderText(const ByteVector &name, const MP4::Item &item, int flags) const
{
ByteVectorList data;
StringList value = item.toStringList();
@@ -298,7 +402,7 @@ MP4::Tag::renderText(const ByteVector &name, MP4::Item &item, int flags)
}
ByteVector
MP4::Tag::renderCovr(const ByteVector &name, MP4::Item &item)
MP4::Tag::renderCovr(const ByteVector &name, const MP4::Item &item) const
{
ByteVector data;
MP4::CoverArtList value = item.toCoverArtList();
@@ -310,7 +414,7 @@ MP4::Tag::renderCovr(const ByteVector &name, MP4::Item &item)
}
ByteVector
MP4::Tag::renderFreeForm(const String &name, MP4::Item &item)
MP4::Tag::renderFreeForm(const String &name, const MP4::Item &item) const
{
StringList header = StringList::split(name, ":");
if (header.size() != 3) {
@@ -320,9 +424,26 @@ MP4::Tag::renderFreeForm(const String &name, MP4::Item &item)
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)));
StringList value = item.toStringList();
for(unsigned int i = 0; i < value.size(); i++) {
data.append(renderAtom("data", ByteVector::fromUInt(1) + ByteVector(4, '\0') + value[i].data(String::UTF8)));
AtomDataType type = item.atomDataType();
if(type == TypeUndefined) {
if(!item.toStringList().isEmpty()) {
type = TypeUTF8;
}
else {
type = TypeImplicit;
}
}
if(type == TypeUTF8) {
StringList value = item.toStringList();
for(unsigned int i = 0; i < value.size(); i++) {
data.append(renderAtom("data", ByteVector::fromUInt(type) + ByteVector(4, '\0') + value[i].data(String::UTF8)));
}
}
else {
ByteVectorList value = item.toByteVectorList();
for(unsigned int i = 0; i < value.size(); i++) {
data.append(renderAtom("data", ByteVector::fromUInt(type) + ByteVector(4, '\0') + value[i]));
}
}
return renderAtom("----", data);
}
@@ -331,28 +452,38 @@ bool
MP4::Tag::save()
{
ByteVector data;
for(MP4::ItemListMap::Iterator i = d->items.begin(); i != d->items.end(); i++) {
const String name = i->first;
for(MP4::ItemMap::ConstIterator it = d->items.begin(); it != d->items.end(); ++it) {
const String name = it->first;
if(name.startsWith("----")) {
data.append(renderFreeForm(name, i->second));
data.append(renderFreeForm(name, it->second));
}
else if(name == "trkn") {
data.append(renderIntPair(name.data(String::Latin1), i->second));
data.append(renderIntPair(name.data(String::Latin1), it->second));
}
else if(name == "disk") {
data.append(renderIntPairNoTrailing(name.data(String::Latin1), i->second));
data.append(renderIntPairNoTrailing(name.data(String::Latin1), it->second));
}
else if(name == "cpil" || name == "pgap" || name == "pcst") {
data.append(renderBool(name.data(String::Latin1), i->second));
else if(name == "cpil" || name == "pgap" || name == "pcst" || name == "hdvd") {
data.append(renderBool(name.data(String::Latin1), it->second));
}
else if(name == "tmpo") {
data.append(renderInt(name.data(String::Latin1), i->second));
data.append(renderInt(name.data(String::Latin1), it->second));
}
else if(name == "tvsn" || name == "tves" || name == "cnID" ||
name == "sfID" || name == "atID" || name == "geID") {
data.append(renderUInt(name.data(String::Latin1), it->second));
}
else if(name == "plID") {
data.append(renderLongLong(name.data(String::Latin1), it->second));
}
else if(name == "stik" || name == "rtng" || name == "akID") {
data.append(renderByte(name.data(String::Latin1), it->second));
}
else if(name == "covr") {
data.append(renderCovr(name.data(String::Latin1), i->second));
data.append(renderCovr(name.data(String::Latin1), it->second));
}
else if(name.size() == 4){
data.append(renderText(name.data(String::Latin1), i->second));
data.append(renderText(name.data(String::Latin1), it->second));
}
else {
debug("MP4: Unknown item name \"" + name + "\"");
@@ -372,7 +503,7 @@ MP4::Tag::save()
}
void
MP4::Tag::updateParents(AtomList &path, long delta, int ignore)
MP4::Tag::updateParents(const AtomList &path, long delta, int ignore)
{
for(unsigned int i = 0; i < path.size() - ignore; i++) {
d->file->seek(path[i]->offset);
@@ -406,11 +537,11 @@ MP4::Tag::updateOffsets(long delta, long offset)
}
d->file->seek(atom->offset + 12);
ByteVector data = d->file->readBlock(atom->length - 12);
unsigned int count = data.mid(0, 4).toUInt();
unsigned int count = data.toUInt();
d->file->seek(atom->offset + 16);
int pos = 4;
uint pos = 4;
while(count--) {
long o = data.mid(pos, 4).toUInt();
long o = static_cast<long>(data.toUInt(pos));
if(o > offset) {
o += delta;
}
@@ -427,11 +558,11 @@ MP4::Tag::updateOffsets(long delta, long offset)
}
d->file->seek(atom->offset + 12);
ByteVector data = d->file->readBlock(atom->length - 12);
unsigned int count = data.mid(0, 4).toUInt();
unsigned int count = data.toUInt();
d->file->seek(atom->offset + 16);
int pos = 4;
uint pos = 4;
while(count--) {
long long o = data.mid(pos, 8).toLongLong();
long long o = data.toLongLong(pos);
if(o > offset) {
o += delta;
}
@@ -450,10 +581,10 @@ MP4::Tag::updateOffsets(long delta, long offset)
atom->offset += delta;
}
d->file->seek(atom->offset + 9);
ByteVector data = d->file->readBlock(atom->offset - 9);
unsigned int flags = (ByteVector(1, '\0') + data.mid(0, 3)).toUInt();
ByteVector data = d->file->readBlock(atom->length - 9);
const unsigned int flags = data.toUInt(0, 3, true);
if(flags & 1) {
long long o = data.mid(7, 8).toLongLong();
long long o = data.toLongLong(7U);
if(o > offset) {
o += delta;
}
@@ -465,10 +596,11 @@ MP4::Tag::updateOffsets(long delta, long offset)
}
void
MP4::Tag::saveNew(ByteVector &data)
MP4::Tag::saveNew(ByteVector data)
{
data = renderAtom("meta", TagLib::ByteVector(4, '\0') +
renderAtom("hdlr", TagLib::ByteVector(8, '\0') + TagLib::ByteVector("mdirappl") + TagLib::ByteVector(9, '\0')) +
data = renderAtom("meta", ByteVector(4, '\0') +
renderAtom("hdlr", ByteVector(8, '\0') + ByteVector("mdirappl") +
ByteVector(9, '\0')) +
data + padIlst(data));
AtomList path = d->atoms->path("moov", "udta");
@@ -485,18 +617,18 @@ MP4::Tag::saveNew(ByteVector &data)
}
void
MP4::Tag::saveExisting(ByteVector &data, AtomList &path)
MP4::Tag::saveExisting(ByteVector data, const AtomList &path)
{
MP4::Atom *ilst = path[path.size() - 1];
long offset = ilst->offset;
long length = ilst->length;
MP4::Atom *meta = path[path.size() - 2];
AtomList::Iterator index = meta->children.find(ilst);
AtomList::ConstIterator index = meta->children.find(ilst);
// check if there is an atom before 'ilst', and possibly use it as padding
if(index != meta->children.begin()) {
AtomList::Iterator prevIndex = index;
AtomList::ConstIterator prevIndex = index;
prevIndex--;
MP4::Atom *prev = *prevIndex;
if(prev->name == "free") {
@@ -505,7 +637,7 @@ MP4::Tag::saveExisting(ByteVector &data, AtomList &path)
}
}
// check if there is an atom after 'ilst', and possibly use it as padding
AtomList::Iterator nextIndex = index;
AtomList::ConstIterator nextIndex = index;
nextIndex++;
if(nextIndex != meta->children.end()) {
MP4::Atom *next = *nextIndex;
@@ -630,9 +762,198 @@ MP4::Tag::setTrack(uint value)
d->items["trkn"] = MP4::Item(value, 0);
}
MP4::ItemListMap &
MP4::Tag::itemListMap()
bool MP4::Tag::isEmpty() const
{
return d->items.isEmpty();
}
MP4::ItemMap &MP4::Tag::itemListMap()
{
return d->items;
}
const MP4::ItemMap &MP4::Tag::itemMap() const
{
return d->items;
}
MP4::Item MP4::Tag::item(const String &key) const
{
return d->items[key];
}
void MP4::Tag::setItem(const String &key, const Item &value)
{
d->items[key] = value;
}
void MP4::Tag::removeItem(const String &key)
{
d->items.erase(key);
}
bool MP4::Tag::contains(const String &key) const
{
return d->items.contains(key);
}
static const char *keyTranslation[][2] = {
{ "\251nam", "TITLE" },
{ "\251ART", "ARTIST" },
{ "\251alb", "ALBUM" },
{ "\251cmt", "COMMENT" },
{ "\251gen", "GENRE" },
{ "\251day", "DATE" },
{ "\251wrt", "COMPOSER" },
{ "\251grp", "GROUPING" },
{ "aART", "ALBUMARTIST" },
{ "trkn", "TRACKNUMBER" },
{ "disk", "DISCNUMBER" },
{ "cpil", "COMPILATION" },
{ "tmpo", "BPM" },
{ "cprt", "COPYRIGHT" },
{ "\251lyr", "LYRICS" },
{ "\251too", "ENCODEDBY" },
{ "soal", "ALBUMSORT" },
{ "soaa", "ALBUMARTISTSORT" },
{ "soar", "ARTISTSORT" },
{ "sonm", "TITLESORT" },
{ "soco", "COMPOSERSORT" },
{ "sosn", "SHOWSORT" },
{ "----:com.apple.iTunes:MusicBrainz Track Id", "MUSICBRAINZ_TRACKID" },
{ "----:com.apple.iTunes:MusicBrainz Artist Id", "MUSICBRAINZ_ARTISTID" },
{ "----:com.apple.iTunes:MusicBrainz Album Id", "MUSICBRAINZ_ALBUMID" },
{ "----:com.apple.iTunes:MusicBrainz Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID" },
{ "----:com.apple.iTunes:MusicBrainz Release Group Id", "MUSICBRAINZ_RELEASEGROUPID" },
{ "----:com.apple.iTunes:MusicBrainz Work Id", "MUSICBRAINZ_WORKID" },
{ "----:com.apple.iTunes:ASIN", "ASIN" },
{ "----:com.apple.iTunes:LABEL", "LABEL" },
{ "----:com.apple.iTunes:LYRICIST", "LYRICIST" },
{ "----:com.apple.iTunes:CONDUCTOR", "CONDUCTOR" },
{ "----:com.apple.iTunes:REMIXER", "REMIXER" },
{ "----:com.apple.iTunes:ENGINEER", "ENGINEER" },
{ "----:com.apple.iTunes:PRODUCER", "PRODUCER" },
{ "----:com.apple.iTunes:DJMIXER", "DJMIXER" },
{ "----:com.apple.iTunes:MIXER", "MIXER" },
{ "----:com.apple.iTunes:SUBTITLE", "SUBTITLE" },
{ "----:com.apple.iTunes:DISCSUBTITLE", "DISCSUBTITLE" },
{ "----:com.apple.iTunes:MOOD", "MOOD" },
{ "----:com.apple.iTunes:ISRC", "ISRC" },
{ "----:com.apple.iTunes:CATALOGNUMBER", "CATALOGNUMBER" },
{ "----:com.apple.iTunes:BARCODE", "BARCODE" },
{ "----:com.apple.iTunes:SCRIPT", "SCRIPT" },
{ "----:com.apple.iTunes:LANGUAGE", "LANGUAGE" },
{ "----:com.apple.iTunes:LICENSE", "LICENSE" },
{ "----:com.apple.iTunes:MEDIA", "MEDIA" },
};
PropertyMap MP4::Tag::properties() const
{
static Map<String, String> keyMap;
if(keyMap.isEmpty()) {
int numKeys = sizeof(keyTranslation) / sizeof(keyTranslation[0]);
for(int i = 0; i < numKeys; i++) {
keyMap[keyTranslation[i][0]] = keyTranslation[i][1];
}
}
PropertyMap props;
MP4::ItemMap::ConstIterator it = d->items.begin();
for(; it != d->items.end(); ++it) {
if(keyMap.contains(it->first)) {
String key = keyMap[it->first];
if(key == "TRACKNUMBER" || key == "DISCNUMBER") {
MP4::Item::IntPair ip = it->second.toIntPair();
String value = String::number(ip.first);
if(ip.second) {
value += "/" + String::number(ip.second);
}
props[key] = value;
}
else if(key == "BPM") {
props[key] = String::number(it->second.toInt());
}
else if(key == "COMPILATION") {
props[key] = String::number(it->second.toBool());
}
else {
props[key] = it->second.toStringList();
}
}
else {
props.unsupportedData().append(it->first);
}
}
return props;
}
void MP4::Tag::removeUnsupportedProperties(const StringList &props)
{
StringList::ConstIterator it = props.begin();
for(; it != props.end(); ++it)
d->items.erase(*it);
}
PropertyMap MP4::Tag::setProperties(const PropertyMap &props)
{
static Map<String, String> reverseKeyMap;
if(reverseKeyMap.isEmpty()) {
int numKeys = sizeof(keyTranslation) / sizeof(keyTranslation[0]);
for(int i = 0; i < numKeys; i++) {
reverseKeyMap[keyTranslation[i][1]] = keyTranslation[i][0];
}
}
PropertyMap origProps = properties();
PropertyMap::ConstIterator it = origProps.begin();
for(; it != origProps.end(); ++it) {
if(!props.contains(it->first) || props[it->first].isEmpty()) {
d->items.erase(reverseKeyMap[it->first]);
}
}
PropertyMap ignoredProps;
it = props.begin();
for(; it != props.end(); ++it) {
if(reverseKeyMap.contains(it->first)) {
String name = reverseKeyMap[it->first];
if(it->first == "TRACKNUMBER" || it->first == "DISCNUMBER") {
int first = 0, second = 0;
StringList parts = StringList::split(it->second.front(), "/");
if(parts.size() > 0) {
first = parts[0].toInt();
if(parts.size() > 1) {
second = parts[1].toInt();
}
d->items[name] = MP4::Item(first, second);
}
}
else if(it->first == "BPM") {
int value = it->second.front().toInt();
d->items[name] = MP4::Item(value);
}
else if(it->first == "COMPILATION") {
bool value = (it->second.front().toInt() != 0);
d->items[name] = MP4::Item(value);
}
else {
d->items[name] = it->second;
}
}
else {
ignoredProps.insert(it->first, it->second);
}
}
return ignoredProps;
}
void MP4::Tag::addItem(const String &name, const Item &value)
{
if(!d->items.contains(name)) {
d->items.insert(name, value);
}
else {
debug("MP4: Ignoring duplicate atom \"" + name + "\"");
}
}

View File

@@ -1,5 +1,5 @@
/**************************************************************************
copyright : (C) 2007 by Lukáš Lalinský
copyright : (C) 2007,2011 by Lukáš Lalinský
email : lalinsky@gmail.com
**************************************************************************/
@@ -39,7 +39,11 @@ namespace TagLib {
namespace MP4 {
/*!
* \deprecated
*/
typedef TagLib::Map<String, Item> ItemListMap;
typedef TagLib::Map<String, Item> ItemMap;
class TAGLIB_EXPORT Tag: public TagLib::Tag
{
@@ -65,34 +69,82 @@ namespace TagLib {
void setYear(uint value);
void setTrack(uint value);
ItemListMap &itemListMap();
virtual bool isEmpty() const;
/*!
* \deprecated Use the item() and setItem() API instead
*/
ItemMap &itemListMap();
/*!
* Returns a string-keyed map of the MP4::Items for this tag.
*/
const ItemMap &itemMap() const;
/*!
* \return The item, if any, corresponding to \a key.
*/
Item item(const String &key) const;
/*!
* Sets the value of \a key to \a value, overwriting any previous value.
*/
void setItem(const String &key, const Item &value);
/*!
* Removes the entry with \a key from the tag, or does nothing if it does
* not exist.
*/
void removeItem(const String &key);
/*!
* \return True if the tag contains an entry for \a key.
*/
bool contains(const String &key) const;
PropertyMap properties() const;
void removeUnsupportedProperties(const StringList& properties);
PropertyMap setProperties(const PropertyMap &properties);
private:
TagLib::ByteVectorList parseData(Atom *atom, TagLib::File *file, int expectedFlags = -1, bool freeForm = false);
void parseText(Atom *atom, TagLib::File *file, int expectedFlags = 1);
void parseFreeForm(Atom *atom, TagLib::File *file);
void parseInt(Atom *atom, TagLib::File *file);
void parseGnre(Atom *atom, TagLib::File *file);
void parseIntPair(Atom *atom, TagLib::File *file);
void parseBool(Atom *atom, TagLib::File *file);
void parseCovr(Atom *atom, TagLib::File *file);
AtomDataList parseData2(const Atom *atom, int expectedFlags = -1,
bool freeForm = false);
ByteVectorList parseData(const Atom *atom, int expectedFlags = -1,
bool freeForm = false);
void parseText(const Atom *atom, int expectedFlags = 1);
void parseFreeForm(const Atom *atom);
void parseInt(const Atom *atom);
void parseByte(const Atom *atom);
void parseUInt(const Atom *atom);
void parseLongLong(const Atom *atom);
void parseGnre(const Atom *atom);
void parseIntPair(const Atom *atom);
void parseBool(const Atom *atom);
void parseCovr(const Atom *atom);
TagLib::ByteVector padIlst(const ByteVector &data, int length = -1);
TagLib::ByteVector renderAtom(const ByteVector &name, const TagLib::ByteVector &data);
TagLib::ByteVector renderData(const ByteVector &name, int flags, const TagLib::ByteVectorList &data);
TagLib::ByteVector renderText(const ByteVector &name, Item &item, int flags = 1);
TagLib::ByteVector renderFreeForm(const String &name, Item &item);
TagLib::ByteVector renderBool(const ByteVector &name, Item &item);
TagLib::ByteVector renderInt(const ByteVector &name, Item &item);
TagLib::ByteVector renderIntPair(const ByteVector &name, Item &item);
TagLib::ByteVector renderIntPairNoTrailing(const ByteVector &name, Item &item);
TagLib::ByteVector renderCovr(const ByteVector &name, Item &item);
ByteVector padIlst(const ByteVector &data, int length = -1) const;
ByteVector renderAtom(const ByteVector &name, const ByteVector &data) const;
ByteVector renderData(const ByteVector &name, int flags,
const ByteVectorList &data) const;
ByteVector renderText(const ByteVector &name, const Item &item,
int flags = TypeUTF8) const;
ByteVector renderFreeForm(const String &name, const Item &item) const;
ByteVector renderBool(const ByteVector &name, const Item &item) const;
ByteVector renderInt(const ByteVector &name, const Item &item) const;
ByteVector renderByte(const ByteVector &name, const Item &item) const;
ByteVector renderUInt(const ByteVector &name, const Item &item) const;
ByteVector renderLongLong(const ByteVector &name, const Item &item) const;
ByteVector renderIntPair(const ByteVector &name, const Item &item) const;
ByteVector renderIntPairNoTrailing(const ByteVector &name, const Item &item) const;
ByteVector renderCovr(const ByteVector &name, const Item &item) const;
void updateParents(AtomList &path, long delta, int ignore = 0);
void updateParents(const AtomList &path, long delta, int ignore = 0);
void updateOffsets(long delta, long offset);
void saveNew(TagLib::ByteVector &data);
void saveExisting(TagLib::ByteVector &data, AtomList &path);
void saveNew(ByteVector data);
void saveExisting(ByteVector data, const AtomList &path);
void addItem(const String &name, const Item &value);
class TagPrivate;
TagPrivate *d;

View File

@@ -27,6 +27,7 @@
#include <tstring.h>
#include <tagunion.h>
#include <tdebug.h>
#include <tpropertymap.h>
#include "mpcfile.h"
#include "id3v1tag.h"
@@ -38,7 +39,7 @@ using namespace TagLib;
namespace
{
enum { APEIndex, ID3v1Index };
enum { MPCAPEIndex = 0, MPCID3v1Index = 1 };
}
class MPC::File::FilePrivate
@@ -52,7 +53,6 @@ public:
ID3v2Location(-1),
ID3v2Size(0),
properties(0),
scanned(false),
hasAPE(false),
hasID3v1(false),
hasID3v2(false) {}
@@ -75,7 +75,6 @@ public:
TagUnion tag;
Properties *properties;
bool scanned;
// These indicate whether the file *on disk* has these tags, not if
// this data structure does. This is used in computing offsets.
@@ -89,18 +88,20 @@ public:
// public members
////////////////////////////////////////////////////////////////////////////////
MPC::File::File(FileName file, bool readProperties,
Properties::ReadStyle propertiesStyle) : TagLib::File(file)
MPC::File::File(FileName file, bool readProperties, Properties::ReadStyle) :
TagLib::File(file),
d(new FilePrivate())
{
d = new FilePrivate;
read(readProperties, propertiesStyle);
if(isOpen())
read(readProperties);
}
MPC::File::File(IOStream *stream, bool readProperties,
Properties::ReadStyle propertiesStyle) : TagLib::File(stream)
MPC::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle) :
TagLib::File(stream),
d(new FilePrivate())
{
d = new FilePrivate;
read(readProperties, propertiesStyle);
if(isOpen())
read(readProperties);
}
MPC::File::~File()
@@ -113,6 +114,30 @@ TagLib::Tag *MPC::File::tag() const
return &d->tag;
}
PropertyMap MPC::File::properties() const
{
if(d->hasAPE)
return d->tag.access<APE::Tag>(MPCAPEIndex, false)->properties();
if(d->hasID3v1)
return d->tag.access<ID3v1::Tag>(MPCID3v1Index, false)->properties();
return PropertyMap();
}
void MPC::File::removeUnsupportedProperties(const StringList &properties)
{
if(d->hasAPE)
d->tag.access<APE::Tag>(MPCAPEIndex, false)->removeUnsupportedProperties(properties);
if(d->hasID3v1)
d->tag.access<ID3v1::Tag>(MPCID3v1Index, false)->removeUnsupportedProperties(properties);
}
PropertyMap MPC::File::setProperties(const PropertyMap &properties)
{
if(d->hasID3v1)
d->tag.access<APE::Tag>(MPCID3v1Index, false)->setProperties(properties);
return d->tag.access<APE::Tag>(MPCAPEIndex, true)->setProperties(properties);
}
MPC::Properties *MPC::File::audioProperties() const
{
return d->properties;
@@ -196,18 +221,18 @@ bool MPC::File::save()
ID3v1::Tag *MPC::File::ID3v1Tag(bool create)
{
return d->tag.access<ID3v1::Tag>(ID3v1Index, create);
return d->tag.access<ID3v1::Tag>(MPCID3v1Index, create);
}
APE::Tag *MPC::File::APETag(bool create)
{
return d->tag.access<APE::Tag>(APEIndex, create);
return d->tag.access<APE::Tag>(MPCAPEIndex, create);
}
void MPC::File::strip(int tags)
{
if(tags & ID3v1) {
d->tag.set(ID3v1Index, 0);
d->tag.set(MPCID3v1Index, 0);
APETag(true);
}
@@ -217,7 +242,7 @@ void MPC::File::strip(int tags)
}
if(tags & APE) {
d->tag.set(APEIndex, 0);
d->tag.set(MPCAPEIndex, 0);
if(!ID3v1Tag())
APETag(true);
@@ -229,30 +254,37 @@ void MPC::File::remove(int tags)
strip(tags);
}
bool MPC::File::hasID3v1Tag() const
{
return d->hasID3v1;
}
bool MPC::File::hasAPETag() const
{
return d->hasAPE;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void MPC::File::read(bool readProperties, Properties::ReadStyle /* propertiesStyle */)
void MPC::File::read(bool readProperties)
{
// Look for an ID3v1 tag
d->ID3v1Location = findID3v1();
if(d->ID3v1Location >= 0) {
d->tag.set(ID3v1Index, new ID3v1::Tag(this, d->ID3v1Location));
d->tag.set(MPCID3v1Index, new ID3v1::Tag(this, d->ID3v1Location));
d->hasID3v1 = true;
}
// Look for an APE tag
findAPE();
d->APELocation = findAPE();
if(d->APELocation >= 0) {
d->tag.set(APEIndex, new APE::Tag(this, d->APELocation));
d->tag.set(MPCAPEIndex, new APE::Tag(this, d->APELocation));
d->APESize = APETag()->footer()->completeTagSize();
d->APELocation = d->APELocation + APETag()->footer()->size() - d->APESize;
@@ -262,7 +294,7 @@ void MPC::File::read(bool readProperties, Properties::ReadStyle /* propertiesSty
if(!d->hasID3v1)
APETag(true);
// Look for and skip an ID3v2 tag
// Look for an ID3v2 tag
d->ID3v2Location = findID3v2();
@@ -273,16 +305,28 @@ void MPC::File::read(bool readProperties, Properties::ReadStyle /* propertiesSty
d->hasID3v2 = true;
}
if(d->hasID3v2)
seek(d->ID3v2Location + d->ID3v2Size);
else
seek(0);
// Look for MPC metadata
if(readProperties) {
d->properties = new Properties(readBlock(MPC::HeaderSize),
length() - d->ID3v2Size - d->APESize);
long streamLength;
if(d->hasAPE)
streamLength = d->APELocation;
else if(d->hasID3v1)
streamLength = d->ID3v1Location;
else
streamLength = length();
if(d->hasID3v2) {
seek(d->ID3v2Location + d->ID3v2Size);
streamLength -= (d->ID3v2Location + d->ID3v2Size);
}
else {
seek(0);
}
d->properties = new Properties(this, streamLength);
}
}

View File

@@ -28,9 +28,12 @@
#include "taglib_export.h"
#include "tfile.h"
#include "tag.h"
#include "mpcproperties.h"
#include "tlist.h"
namespace TagLib {
class Tag;
@@ -81,17 +84,22 @@ namespace TagLib {
};
/*!
* Contructs an MPC file from \a file. If \a readProperties is true the
* file's audio properties will also be read using \a propertiesStyle. If
* false, \a propertiesStyle is ignored.
* Constructs an MPC 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,
Properties::ReadStyle propertiesStyle = Properties::Average);
/*!
* Contructs an MPC file from \a file. If \a readProperties is true the
* file's audio properties will also be read using \a propertiesStyle. If
* false, \a propertiesStyle is ignored.
* Constructs an MPC 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,
Properties::ReadStyle propertiesStyle = Properties::Average);
@@ -107,6 +115,22 @@ 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 the APE
* tag will be converted to the PropertyMap.
*/
PropertyMap properties() const;
void removeUnsupportedProperties(const StringList &properties);
/*!
* Implements the unified property interface -- import function.
* Affects only the APEv2 tag which will be created if necessary.
* If an ID3v1 tag exists, it will be updated as well.
*/
PropertyMap setProperties(const PropertyMap &);
/*!
* Returns the MPC::Properties for this file. If no audio properties
* were read then this will return a null pointer.
@@ -115,34 +139,50 @@ namespace TagLib {
/*!
* Saves the file.
*
* This returns true if the save was successful.
*
* \warning In the current implementation, it's dangerous to call save()
* repeatedly. At worst it will corrupt the file.
*/
virtual bool save();
/*!
* Returns a pointer to the ID3v1 tag of the file.
*
* If \a create is false (the default) this will return a null pointer
* if there is no valid ID3v1 tag. If \a create is true it will create
* an ID3v1 tag if one does not exist. If there is already an APE tag, the
* new ID3v1 tag will be placed after it.
* If \a create is false (the default) this returns a null pointer
* if there is no valid APE tag. If \a create is true it will create
* an APE tag if one does not exist and returns a valid pointer.
*
* \note The Tag <b>is still</b> owned by the APE::File and should not be
* \note This may return a valid pointer regardless of whether or not the
* file on disk has an ID3v1 tag. Use hasID3v1Tag() to check if the file
* on disk actually has an ID3v1 tag.
*
* \note The Tag <b>is still</b> owned by the MPEG::File and should not be
* deleted by the user. It will be deleted when the file (object) is
* destroyed.
*
* \see hasID3v1Tag()
*/
ID3v1::Tag *ID3v1Tag(bool create = false);
/*!
* Returns a pointer to the APE tag of the file.
*
* If \a create is false (the default) this will return a null pointer
* If \a create is false (the default) this may return a null pointer
* if there is no valid APE tag. If \a create is true it will create
* a APE tag if one does not exist. If there is already an ID3v1 tag, thes
* new APE tag will be placed before it.
* an APE tag if one does not exist and returns a valid pointer. If
* there already be an ID3v1 tag, the new APE tag will be placed before it.
*
* \note The Tag <b>is still</b> owned by the APE::File and should not be
* \note This may return a valid pointer regardless of whether or not the
* file on disk has an APE tag. Use hasAPETag() to check if the file
* on disk actually has an APE tag.
*
* \note The Tag <b>is still</b> owned by the MPEG::File and should not be
* deleted by the user. It will be deleted when the file (object) is
* destroyed.
*
* \see hasAPETag()
*/
APE::Tag *APETag(bool create = false);
@@ -163,13 +203,25 @@ namespace TagLib {
*/
void remove(int tags = AllTags);
/*!
* Returns whether or not the file on disk actually has an ID3v1 tag.
*
* \see ID3v1Tag()
*/
bool hasID3v1Tag() const;
/*!
* Returns whether or not the file on disk actually has an APE tag.
*
* \see APETag()
*/
bool hasAPETag() const;
private:
File(const File &);
File &operator=(const File &);
void read(bool readProperties, Properties::ReadStyle propertiesStyle);
void scan();
void read(bool readProperties);
long findAPE();
long findID3v1();
long findID3v2();

View File

@@ -26,6 +26,7 @@
#include <tstring.h>
#include <tdebug.h>
#include <bitset>
#include <math.h>
#include "mpcproperties.h"
#include "mpcfile.h"
@@ -35,34 +36,57 @@ using namespace TagLib;
class MPC::Properties::PropertiesPrivate
{
public:
PropertiesPrivate(const ByteVector &d, long length, ReadStyle s) :
data(d),
streamLength(length),
style(s),
PropertiesPrivate() :
version(0),
length(0),
bitrate(0),
sampleRate(0),
channels(0) {}
channels(0),
totalFrames(0),
sampleFrames(0),
trackGain(0),
trackPeak(0),
albumGain(0),
albumPeak(0) {}
ByteVector data;
long streamLength;
ReadStyle style;
int version;
int length;
int bitrate;
int sampleRate;
int channels;
uint totalFrames;
uint sampleFrames;
uint trackGain;
uint trackPeak;
uint albumGain;
uint albumPeak;
String flags;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
MPC::Properties::Properties(const ByteVector &data, long streamLength, ReadStyle style) : AudioProperties(style)
MPC::Properties::Properties(const ByteVector &data, long streamLength, ReadStyle style) :
AudioProperties(style),
d(new PropertiesPrivate())
{
d = new PropertiesPrivate(data, streamLength, style);
read();
readSV7(data, streamLength);
}
MPC::Properties::Properties(File *file, long streamLength, ReadStyle style) :
AudioProperties(style),
d(new PropertiesPrivate())
{
ByteVector magic = file->readBlock(4);
if(magic == "MPCK") {
// Musepack version 8
readSV8(file, streamLength);
}
else {
// Musepack version 7 or older, fixed size header
readSV7(magic + file->readBlock(MPC::HeaderSize - 4), streamLength);
}
}
MPC::Properties::~Properties()
@@ -71,6 +95,16 @@ MPC::Properties::~Properties()
}
int MPC::Properties::length() const
{
return lengthInSeconds();
}
int MPC::Properties::lengthInSeconds() const
{
return d->length / 1000;
}
int MPC::Properties::lengthInMilliseconds() const
{
return d->length;
}
@@ -95,46 +129,241 @@ int MPC::Properties::mpcVersion() const
return d->version;
}
TagLib::uint MPC::Properties::totalFrames() const
{
return d->totalFrames;
}
TagLib::uint MPC::Properties::sampleFrames() const
{
return d->sampleFrames;
}
int MPC::Properties::trackGain() const
{
return d->trackGain;
}
int MPC::Properties::trackPeak() const
{
return d->trackPeak;
}
int MPC::Properties::albumGain() const
{
return d->albumGain;
}
int MPC::Properties::albumPeak() const
{
return d->albumPeak;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
static const unsigned short sftable [4] = { 44100, 48000, 37800, 32000 };
void MPC::Properties::read()
unsigned long readSize(File *file, TagLib::uint &sizeLength, bool &eof)
{
if(!d->data.startsWith("MP+"))
return;
sizeLength = 0;
eof = false;
d->version = d->data[3] & 15;
unsigned char tmp;
unsigned long size = 0;
unsigned int frames;
do {
const ByteVector b = file->readBlock(1);
if(b.isEmpty()) {
eof = true;
break;
}
if(d->version >= 7) {
frames = d->data.mid(4, 4).toUInt(false);
tmp = b[0];
size = (size << 7) | (tmp & 0x7F);
sizeLength++;
} while((tmp & 0x80));
return size;
}
std::bitset<32> flags(TAGLIB_CONSTRUCT_BITSET(d->data.mid(8, 4).toUInt(false)));
d->sampleRate = sftable[flags[17] * 2 + flags[16]];
d->channels = 2;
unsigned long readSize(const ByteVector &data, TagLib::uint &pos)
{
unsigned char tmp;
unsigned long size = 0;
do {
tmp = data[pos++];
size = (size << 7) | (tmp & 0x7F);
} while((tmp & 0x80) && (pos < data.size()));
return size;
}
namespace
{
// This array looks weird, but the same as original MusePack code found at:
// https://www.musepack.net/index.php?pg=src
const unsigned short sftable [8] = { 44100, 48000, 37800, 32000, 0, 0, 0, 0 };
}
void MPC::Properties::readSV8(File *file, long streamLength)
{
bool readSH = false, readRG = false;
while(!readSH && !readRG) {
const ByteVector packetType = file->readBlock(2);
uint packetSizeLength;
bool eof;
const unsigned long packetSize = readSize(file, packetSizeLength, eof);
if(eof) {
debug("MPC::Properties::readSV8() - Reached to EOF.");
break;
}
const unsigned long dataSize = packetSize - 2 - packetSizeLength;
const ByteVector data = file->readBlock(dataSize);
if(data.size() != dataSize) {
debug("MPC::Properties::readSV8() - dataSize doesn't match the actual data size.");
break;
}
if(packetType == "SH") {
// Stream Header
// http://trac.musepack.net/wiki/SV8Specification#StreamHeaderPacket
if(dataSize <= 5) {
debug("MPC::Properties::readSV8() - \"SH\" packet is too short to parse.");
break;
}
readSH = true;
TagLib::uint pos = 4;
d->version = data[pos];
pos += 1;
d->sampleFrames = readSize(data, pos);
if(pos > dataSize - 3) {
debug("MPC::Properties::readSV8() - \"SH\" packet is corrupt.");
break;
}
const ulong begSilence = readSize(data, pos);
if(pos > dataSize - 2) {
debug("MPC::Properties::readSV8() - \"SH\" packet is corrupt.");
break;
}
const ushort flags = data.toUShort(pos, true);
pos += 2;
d->sampleRate = sftable[(flags >> 13) & 0x07];
d->channels = ((flags >> 4) & 0x0F) + 1;
const uint frameCount = d->sampleFrames - begSilence;
if(frameCount > 0 && d->sampleRate > 0) {
const double length = frameCount * 1000.0 / d->sampleRate;
d->length = static_cast<int>(length + 0.5);
d->bitrate = static_cast<int>(streamLength * 8.0 / length + 0.5);
}
}
else if (packetType == "RG") {
// Replay Gain
// http://trac.musepack.net/wiki/SV8Specification#ReplaygainPacket
if(dataSize <= 9) {
debug("MPC::Properties::readSV8() - \"RG\" packet is too short to parse.");
break;
}
readRG = true;
const int replayGainVersion = data[0];
if(replayGainVersion == 1) {
d->trackGain = data.toShort(1, true);
d->trackPeak = data.toShort(3, true);
d->albumGain = data.toShort(5, true);
d->albumPeak = data.toShort(7, true);
}
}
else if(packetType == "SE") {
break;
}
else {
file->seek(dataSize, File::Current);
}
}
}
void MPC::Properties::readSV7(const ByteVector &data, long streamLength)
{
if(data.startsWith("MP+")) {
d->version = data[3] & 15;
if(d->version < 7)
return;
d->totalFrames = data.toUInt(4, false);
const uint flags = data.toUInt(8, false);
d->sampleRate = sftable[(flags >> 16) & 0x03];
d->channels = 2;
const uint gapless = data.toUInt(5, false);
d->trackGain = data.toShort(14, false);
d->trackPeak = data.toShort(12, false);
d->albumGain = data.toShort(18, false);
d->albumPeak = data.toShort(16, false);
// convert gain info
if(d->trackGain != 0) {
int tmp = (int)((64.82 - (short)d->trackGain / 100.) * 256. + .5);
if(tmp >= (1 << 16) || tmp < 0) tmp = 0;
d->trackGain = tmp;
}
if(d->albumGain != 0) {
int tmp = (int)((64.82 - d->albumGain / 100.) * 256. + .5);
if(tmp >= (1 << 16) || tmp < 0) tmp = 0;
d->albumGain = tmp;
}
if (d->trackPeak != 0)
d->trackPeak = (int)(log10((double)d->trackPeak) * 20 * 256 + .5);
if (d->albumPeak != 0)
d->albumPeak = (int)(log10((double)d->albumPeak) * 20 * 256 + .5);
bool trueGapless = (gapless >> 31) & 0x0001;
if(trueGapless) {
uint lastFrameSamples = (gapless >> 20) & 0x07FF;
d->sampleFrames = d->totalFrames * 1152 - lastFrameSamples;
}
else
d->sampleFrames = d->totalFrames * 1152 - 576;
}
else {
uint headerData = d->data.mid(0, 4).toUInt(false);
const uint headerData = data.toUInt(0, false);
d->bitrate = (headerData >> 23) & 0x01ff;
d->version = (headerData >> 11) & 0x03ff;
d->bitrate = (headerData >> 23) & 0x01ff;
d->version = (headerData >> 11) & 0x03ff;
d->sampleRate = 44100;
d->channels = 2;
d->channels = 2;
if(d->version >= 5)
frames = d->data.mid(4, 4).toUInt(false);
d->totalFrames = data.toUInt(4, false);
else
frames = d->data.mid(6, 2).toUInt(false);
d->totalFrames = data.toUShort(6, false);
d->sampleFrames = d->totalFrames * 1152 - 576;
}
uint samples = frames * 1152 - 576;
if(d->sampleFrames > 0 && d->sampleRate > 0) {
const double length = d->sampleFrames * 1000.0 / d->sampleRate;
d->length = static_cast<int>(length + 0.5);
d->length = d->sampleRate > 0 ? (samples + (d->sampleRate / 2)) / d->sampleRate : 0;
if(!d->bitrate)
d->bitrate = d->length > 0 ? ((d->streamLength * 8L) / d->length) / 1000 : 0;
if(d->bitrate == 0)
d->bitrate = static_cast<int>(streamLength * 8.0 / length + 0.5);
}
}

View File

@@ -50,31 +50,104 @@ namespace TagLib {
/*!
* Create an instance of MPC::Properties with the data read from the
* ByteVector \a data.
*
* This constructor is deprecated. It only works for MPC version up to 7.
*/
Properties(const ByteVector &data, long streamLength, ReadStyle style = Average);
/*!
* Create an instance of MPC::Properties with the data read directly
* from a MPC::File.
*/
Properties(File *file, long streamLength, ReadStyle style = Average);
/*!
* Destroys this MPC::Properties instance.
*/
virtual ~Properties();
// Reimplementations.
/*!
* Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second.
*
* \note This method is just an alias of lengthInSeconds().
*
* \deprecated
*/
virtual int length() const;
/*!
* Returns the length of the file in seconds. The length is rounded down to
* the nearest whole second.
*
* \see lengthInMilliseconds()
*/
// BIC: make virtual
int lengthInSeconds() const;
/*!
* Returns the length of the file in milliseconds.
*
* \see lengthInSeconds()
*/
// BIC: make virtual
int lengthInMilliseconds() const;
/*!
* Returns the average bit rate of the file in kb/s.
*/
virtual int bitrate() const;
/*!
* Returns the sample rate in Hz.
*/
virtual int sampleRate() const;
/*!
* Returns the number of audio channels.
*/
virtual int channels() const;
/*!
* Returns the version of the bitstream (SV4-SV7)
* Returns the version of the bitstream (SV4-SV8)
*/
int mpcVersion() const;
uint totalFrames() const;
uint sampleFrames() const;
/*!
* Returns the track gain as an integer value,
* to convert to dB: trackGain in dB = 64.82 - (trackGain / 256)
*/
int trackGain() const;
/*!
* Returns the track peak as an integer value,
* to convert to dB: trackPeak in dB = trackPeak / 256
* to convert to floating [-1..1]: trackPeak = 10^(trackPeak / 256 / 20)/32768
*/
int trackPeak() const;
/*!
* Returns the album gain as an integer value,
* to convert to dB: albumGain in dB = 64.82 - (albumGain / 256)
*/
int albumGain() const;
/*!
* Returns the album peak as an integer value,
* to convert to dB: albumPeak in dB = albumPeak / 256
* to convert to floating [-1..1]: albumPeak = 10^(albumPeak / 256 / 20)/32768
*/
int albumPeak() const;
private:
Properties(const Properties &);
Properties &operator=(const Properties &);
void read();
void readSV7(const ByteVector &data, long streamLength);
void readSV8(File *file, long streamLength);
class PropertiesPrivate;
PropertiesPrivate *d;

View File

@@ -30,7 +30,7 @@ using namespace TagLib;
namespace TagLib {
namespace ID3v1 {
static const int genresSize = 148;
static const int genresSize = 192;
static const String genres[] = {
"Blues",
"Classic Rock",
@@ -179,7 +179,51 @@ namespace TagLib {
"Thrash Metal",
"Anime",
"Jpop",
"Synthpop"
"Synthpop",
"Abstract",
"Art Rock",
"Baroque",
"Bhangra",
"Big Beat",
"Breakbeat",
"Chillout",
"Downtempo",
"Dub",
"EBM",
"Eclectic",
"Electro",
"Electroclash",
"Emo",
"Experimental",
"Garage",
"Global",
"IDM",
"Illbient",
"Industro-Goth",
"Jam Band",
"Krautrock",
"Leftfield",
"Lounge",
"Math Rock",
"New Romantic",
"Nu-Breakz",
"Post-Punk",
"Post-Rock",
"Psytrance",
"Shoegaze",
"Space Rock",
"Trop Rock",
"World Music",
"Neoclassical",
"Audiobook",
"Audio Theatre",
"Neue Deutsche Welle",
"Podcast",
"Indie Rock",
"G-Funk",
"Dubstep",
"Garage Rock",
"Psybient"
};
}
}

View File

@@ -49,7 +49,7 @@ namespace TagLib {
/*!
* Returns the name of the genre at \a index in the ID3v1 genre list. If
* \a index is out of range -- less than zero or greater than 146 -- a null
* \a index is out of range -- less than zero or greater than 191 -- a null
* string will be returned.
*/
String TAGLIB_EXPORT genre(int index);

View File

@@ -51,12 +51,17 @@ public:
static const StringHandler *stringHandler;
};
const ID3v1::StringHandler *ID3v1::Tag::TagPrivate::stringHandler = new StringHandler;
static const StringHandler defaultStringHandler;
const ID3v1::StringHandler *ID3v1::Tag::TagPrivate::stringHandler = &defaultStringHandler;
////////////////////////////////////////////////////////////////////////////////
// StringHandler implementation
////////////////////////////////////////////////////////////////////////////////
StringHandler::StringHandler()
{
}
String ID3v1::StringHandler::parse(const ByteVector &data) const
{
return String(data, String::Latin1).stripWhiteSpace();
@@ -177,20 +182,32 @@ void ID3v1::Tag::setGenre(const String &s)
d->genre = ID3v1::genreIndex(s);
}
void ID3v1::Tag::setYear(uint i)
void ID3v1::Tag::setYear(TagLib::uint i)
{
d->year = i > 0 ? String::number(i) : String::null;
}
void ID3v1::Tag::setTrack(uint i)
void ID3v1::Tag::setTrack(TagLib::uint i)
{
d->track = i < 256 ? i : 0;
}
TagLib::uint ID3v1::Tag::genreNumber() const
{
return d->genre;
}
void ID3v1::Tag::setGenreNumber(TagLib::uint i)
{
d->genre = i < 256 ? i : 255;
}
void ID3v1::Tag::setStringHandler(const StringHandler *handler)
{
delete TagPrivate::stringHandler;
TagPrivate::stringHandler = handler;
if (handler)
TagPrivate::stringHandler = handler;
else
TagPrivate::stringHandler = &defaultStringHandler;
}
////////////////////////////////////////////////////////////////////////////////

View File

@@ -62,6 +62,7 @@ namespace TagLib {
TAGLIB_IGNORE_MISSING_DESTRUCTOR
public:
// BIC: Add virtual destructor.
StringHandler();
/*!
* Decode a string from \a data. The default implementation assumes that
@@ -84,7 +85,7 @@ namespace TagLib {
//! The main class in the ID3v1 implementation
/*!
* This is an implementation of the ID3v1 format. ID3v1 is both the simplist
* This is an implementation of the ID3v1 format. ID3v1 is both the simplest
* and most common of tag formats but is rather limited. Because of its
* pervasiveness and the way that applications have been written around the
* fields that it provides, the generic TagLib::Tag API is a mirror of what is
@@ -139,20 +140,40 @@ namespace TagLib {
virtual String album() const;
virtual String comment() const;
virtual String genre() const;
virtual uint year() const;
virtual uint track() const;
virtual TagLib::uint year() const;
virtual TagLib::uint track() const;
virtual void setTitle(const String &s);
virtual void setArtist(const String &s);
virtual void setAlbum(const String &s);
virtual void setComment(const String &s);
virtual void setGenre(const String &s);
virtual void setYear(uint i);
virtual void setTrack(uint i);
virtual void setYear(TagLib::uint i);
virtual void setTrack(TagLib::uint i);
/*!
* Returns the genre in number.
*
* \note Normally 255 indicates that this tag contains no genre.
*/
TagLib::uint genreNumber() const;
/*!
* Sets the genre in number to \a i.
*
* \note Valid value is from 0 up to 255. Normally 255 indicates that
* this tag contains no genre.
*/
void setGenreNumber(TagLib::uint i);
/*!
* Sets the string handler that decides how the ID3v1 data will be
* converted to and from binary data.
* If the parameter \a handler is null, the previous handler is
* released and default ISO-8859-1 handler is restored.
*
* \note The caller is responsible for deleting the previous handler
* as needed after it is released.
*
* \see StringHandler
*/

View File

@@ -0,0 +1,306 @@
/***************************************************************************
copyright : (C) 2013 by Lukas Krejci
email : krejclu6@fel.cvut.cz
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <tbytevectorlist.h>
#include <tpropertymap.h>
#include <tdebug.h>
#include <stdio.h>
#include "chapterframe.h"
using namespace TagLib;
using namespace ID3v2;
class ChapterFrame::ChapterFramePrivate
{
public:
ChapterFramePrivate() :
tagHeader(0)
{
embeddedFrameList.setAutoDelete(true);
}
const ID3v2::Header *tagHeader;
ByteVector elementID;
TagLib::uint startTime;
TagLib::uint endTime;
TagLib::uint startOffset;
TagLib::uint endOffset;
FrameListMap embeddedFrameListMap;
FrameList embeddedFrameList;
};
////////////////////////////////////////////////////////////////////////////////
// public methods
////////////////////////////////////////////////////////////////////////////////
ChapterFrame::ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data) :
ID3v2::Frame(data)
{
d = new ChapterFramePrivate;
d->tagHeader = tagHeader;
setData(data);
}
ChapterFrame::ChapterFrame(const ByteVector &elementID,
TagLib::uint startTime, TagLib::uint endTime,
TagLib::uint startOffset, TagLib::uint endOffset,
const FrameList &embeddedFrames) :
ID3v2::Frame("CHAP")
{
d = new ChapterFramePrivate;
// setElementID has a workaround for a previously silly API where you had to
// specifically include the null byte.
setElementID(elementID);
d->startTime = startTime;
d->endTime = endTime;
d->startOffset = startOffset;
d->endOffset = endOffset;
for(FrameList::ConstIterator it = embeddedFrames.begin();
it != embeddedFrames.end(); ++it)
addEmbeddedFrame(*it);
}
ChapterFrame::~ChapterFrame()
{
delete d;
}
ByteVector ChapterFrame::elementID() const
{
return d->elementID;
}
TagLib::uint ChapterFrame::startTime() const
{
return d->startTime;
}
TagLib::uint ChapterFrame::endTime() const
{
return d->endTime;
}
TagLib::uint ChapterFrame::startOffset() const
{
return d->startOffset;
}
TagLib::uint ChapterFrame::endOffset() const
{
return d->endOffset;
}
void ChapterFrame::setElementID(const ByteVector &eID)
{
d->elementID = eID;
if(d->elementID.endsWith(char(0)))
d->elementID = d->elementID.mid(0, d->elementID.size() - 1);
}
void ChapterFrame::setStartTime(const TagLib::uint &sT)
{
d->startTime = sT;
}
void ChapterFrame::setEndTime(const TagLib::uint &eT)
{
d->endTime = eT;
}
void ChapterFrame::setStartOffset(const TagLib::uint &sO)
{
d->startOffset = sO;
}
void ChapterFrame::setEndOffset(const TagLib::uint &eO)
{
d->endOffset = eO;
}
const FrameListMap &ChapterFrame::embeddedFrameListMap() const
{
return d->embeddedFrameListMap;
}
const FrameList &ChapterFrame::embeddedFrameList() const
{
return d->embeddedFrameList;
}
const FrameList &ChapterFrame::embeddedFrameList(const ByteVector &frameID) const
{
return d->embeddedFrameListMap[frameID];
}
void ChapterFrame::addEmbeddedFrame(Frame *frame)
{
d->embeddedFrameList.append(frame);
d->embeddedFrameListMap[frame->frameID()].append(frame);
}
void ChapterFrame::removeEmbeddedFrame(Frame *frame, bool del)
{
// remove the frame from the frame list
FrameList::Iterator it = d->embeddedFrameList.find(frame);
d->embeddedFrameList.erase(it);
// ...and from the frame list map
it = d->embeddedFrameListMap[frame->frameID()].find(frame);
d->embeddedFrameListMap[frame->frameID()].erase(it);
// ...and delete as desired
if(del)
delete frame;
}
void ChapterFrame::removeEmbeddedFrames(const ByteVector &id)
{
FrameList l = d->embeddedFrameListMap[id];
for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it)
removeEmbeddedFrame(*it, true);
}
String ChapterFrame::toString() const
{
String s = String(d->elementID) +
": start time: " + String::number(d->startTime) +
", end time: " + String::number(d->endTime);
if(d->startOffset != 0xFFFFFFFF)
s += ", start offset: " + String::number(d->startOffset);
if(d->endOffset != 0xFFFFFFFF)
s += ", start offset: " + String::number(d->endOffset);
if(!d->embeddedFrameList.isEmpty()) {
StringList frameIDs;
for(FrameList::ConstIterator it = d->embeddedFrameList.begin();
it != d->embeddedFrameList.end(); ++it)
frameIDs.append((*it)->frameID());
s += ", sub-frames: [ " + frameIDs.toString(", ") + " ]";
}
return s;
}
PropertyMap ChapterFrame::asProperties() const
{
PropertyMap map;
map.unsupportedData().append(frameID() + String("/") + d->elementID);
return map;
}
ChapterFrame *ChapterFrame::findByElementID(const ID3v2::Tag *tag, const ByteVector &eID) // static
{
ID3v2::FrameList comments = tag->frameList("CHAP");
for(ID3v2::FrameList::ConstIterator it = comments.begin();
it != comments.end();
++it)
{
ChapterFrame *frame = dynamic_cast<ChapterFrame *>(*it);
if(frame && frame->elementID() == eID)
return frame;
}
return 0;
}
void ChapterFrame::parseFields(const ByteVector &data)
{
TagLib::uint size = data.size();
if(size < 18) {
debug("A CHAP frame must contain at least 18 bytes (1 byte element ID "
"terminated by null and 4x4 bytes for start and end time and offset).");
return;
}
int pos = 0;
TagLib::uint embPos = 0;
d->elementID = readStringField(data, String::Latin1, &pos).data(String::Latin1);
d->startTime = data.toUInt(pos, true);
pos += 4;
d->endTime = data.toUInt(pos, true);
pos += 4;
d->startOffset = data.toUInt(pos, true);
pos += 4;
d->endOffset = data.toUInt(pos, true);
pos += 4;
size -= pos;
// Embedded frames are optional
if(size < header()->size())
return;
while(embPos < size - header()->size()) {
Frame *frame = FrameFactory::instance()->createFrame(data.mid(pos + embPos), (d->tagHeader != 0));
if(!frame)
return;
// Checks to make sure that frame parsed correctly.
if(frame->size() <= 0) {
delete frame;
return;
}
embPos += frame->size() + header()->size();
addEmbeddedFrame(frame);
}
}
ByteVector ChapterFrame::renderFields() const
{
ByteVector data;
data.append(d->elementID);
data.append('\0');
data.append(ByteVector::fromUInt(d->startTime, true));
data.append(ByteVector::fromUInt(d->endTime, true));
data.append(ByteVector::fromUInt(d->startOffset, true));
data.append(ByteVector::fromUInt(d->endOffset, true));
FrameList l = d->embeddedFrameList;
for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it)
data.append((*it)->render());
return data;
}
ChapterFrame::ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data, Header *h) :
Frame(h)
{
d = new ChapterFramePrivate;
d->tagHeader = tagHeader;
parseFields(fieldData(data));
}

View File

@@ -0,0 +1,249 @@
/***************************************************************************
copyright : (C) 2013 by Lukas Krejci
email : krejclu6@fel.cvut.cz
***************************************************************************/
/***************************************************************************
* 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_CHAPTERFRAME
#define TAGLIB_CHAPTERFRAME
#include "id3v2tag.h"
#include "id3v2frame.h"
#include "taglib_export.h"
namespace TagLib {
namespace ID3v2 {
/*!
* This is an implementation of ID3v2 chapter frames. The purpose of this
* frame is to describe a single chapter within an audio file.
*/
//! An implementation of ID3v2 chapter frames
class TAGLIB_EXPORT ChapterFrame : public ID3v2::Frame
{
friend class FrameFactory;
public:
/*!
* Creates a chapter frame based on \a data. \a tagHeader is required as
* the internal frames are parsed based on the tag version.
*/
ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data);
/*!
* Creates a chapter frame with the element ID \a elementID, start time
* \a startTime, end time \a endTime, start offset \a startOffset,
* end offset \a endOffset and optionally a list of embedded frames,
* whose ownership will then be taken over by this Frame, in
* \a embeededFrames;
*
* All times are in milliseconds.
*/
ChapterFrame(const ByteVector &elementID,
uint startTime, uint endTime,
uint startOffset, uint endOffset,
const FrameList &embeddedFrames = FrameList());
/*!
* Destroys the frame.
*/
virtual ~ChapterFrame();
/*!
* Returns the element ID of the frame. Element ID
* is a null terminated string, however it's not human-readable.
*
* \see setElementID()
*/
ByteVector elementID() const;
/*!
* Returns time of chapter's start (in milliseconds).
*
* \see setStartTime()
*/
uint startTime() const;
/*!
* Returns time of chapter's end (in milliseconds).
*
* \see setEndTime()
*/
uint endTime() const;
/*!
* Returns zero based byte offset (count of bytes from the beginning
* of the audio file) of chapter's start.
*
* \note If returned value is 0xFFFFFFFF, start time should be used instead.
* \see setStartOffset()
*/
uint startOffset() const;
/*!
* Returns zero based byte offset (count of bytes from the beginning
* of the audio file) of chapter's end.
*
* \note If returned value is 0xFFFFFFFF, end time should be used instead.
* \see setEndOffset()
*/
uint endOffset() const;
/*!
* Sets the element ID of the frame to \a eID. If \a eID isn't
* null terminated, a null char is appended automatically.
*
* \see elementID()
*/
void setElementID(const ByteVector &eID);
/*!
* Sets time of chapter's start (in milliseconds) to \a sT.
*
* \see startTime()
*/
void setStartTime(const uint &sT);
/*!
* Sets time of chapter's end (in milliseconds) to \a eT.
*
* \see endTime()
*/
void setEndTime(const uint &eT);
/*!
* Sets zero based byte offset (count of bytes from the beginning
* of the audio file) of chapter's start to \a sO.
*
* \see startOffset()
*/
void setStartOffset(const uint &sO);
/*!
* Sets zero based byte offset (count of bytes from the beginning
* of the audio file) of chapter's end to \a eO.
*
* \see endOffset()
*/
void setEndOffset(const uint &eO);
/*!
* Returns a reference to the frame list map. This is an FrameListMap of
* all of the frames embedded in the CHAP frame.
*
* This is the most convenient structure for accessing the CHAP frame's
* embedded frames. Many frame types allow multiple instances of the same
* frame type so this is a map of lists. In most cases however there will
* only be a single frame of a certain type.
*
* \warning You should not modify this data structure directly, instead
* use addEmbeddedFrame() and removeEmbeddedFrame().
*
* \see embeddedFrameList()
*/
const FrameListMap &embeddedFrameListMap() const;
/*!
* Returns a reference to the embedded frame list. This is an FrameList
* of all of the frames embedded in the CHAP frame in the order that they
* were parsed.
*
* This can be useful if for example you want iterate over the CHAP frame's
* embedded frames in the order that they occur in the CHAP frame.
*
* \warning You should not modify this data structure directly, instead
* use addEmbeddedFrame() and removeEmbeddedFrame().
*/
const FrameList &embeddedFrameList() const;
/*!
* Returns the embedded frame list for frames with the id \a frameID
* or an empty list if there are no embedded frames of that type. This
* is just a convenience and is equivalent to:
*
* \code
* embeddedFrameListMap()[frameID];
* \endcode
*
* \see embeddedFrameListMap()
*/
const FrameList &embeddedFrameList(const ByteVector &frameID) const;
/*!
* Add an embedded frame to the CHAP frame. At this point the CHAP frame
* takes ownership of the embedded frame and will handle freeing its memory.
*
* \note Using this method will invalidate any pointers on the list
* returned by embeddedFrameList()
*/
void addEmbeddedFrame(Frame *frame);
/*!
* Remove an embedded frame from the CHAP frame. If \a del is true the frame's
* memory will be freed; if it is false, it must be deleted by the user.
*
* \note Using this method will invalidate any pointers on the list
* returned by embeddedFrameList()
*/
void removeEmbeddedFrame(Frame *frame, bool del = true);
/*!
* Remove all embedded frames of type \a id from the CHAP frame and free their
* memory.
*
* \note Using this method will invalidate any pointers on the list
* returned by embeddedFrameList()
*/
void removeEmbeddedFrames(const ByteVector &id);
virtual String toString() const;
PropertyMap asProperties() const;
/*!
* CHAP frames each have a unique element ID. This searches for a CHAP
* frame with the element ID \a eID and returns a pointer to it. This
* can be used to link CTOC and CHAP frames together.
*
* \see elementID()
*/
static ChapterFrame *findByElementID(const Tag *tag, const ByteVector &eID);
protected:
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
private:
ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data, Header *h);
ChapterFrame(const ChapterFrame &);
ChapterFrame &operator=(const ChapterFrame &);
class ChapterFramePrivate;
ChapterFramePrivate *d;
};
}
}
#endif

View File

@@ -29,6 +29,7 @@
#include <tstringlist.h>
#include "commentsframe.h"
#include "tpropertymap.h"
using namespace TagLib;
using namespace ID3v2;
@@ -109,6 +110,19 @@ void CommentsFrame::setTextEncoding(String::Type encoding)
d->textEncoding = encoding;
}
PropertyMap CommentsFrame::asProperties() const
{
String key = description().upper();
PropertyMap map;
if(key.isEmpty() || key == "COMMENT")
map.insert("COMMENT", text());
else if(key.isNull())
map.unsupportedData().append(L"COMM/" + description());
else
map.insert("COMMENT:" + key, text());
return map;
}
CommentsFrame *CommentsFrame::findByDescription(const ID3v2::Tag *tag, const String &d) // static
{
ID3v2::FrameList comments = tag->frameList("COMM");
@@ -144,8 +158,13 @@ void CommentsFrame::parseFields(const ByteVector &data)
ByteVectorList l = ByteVectorList::split(data.mid(4), textDelimiter(d->textEncoding), byteAlign, 2);
if(l.size() == 2) {
d->description = String(l.front(), d->textEncoding);
d->text = String(l.back(), d->textEncoding);
if(d->textEncoding == String::Latin1) {
d->description = Tag::latin1StringHandler()->parse(l.front());
d->text = Tag::latin1StringHandler()->parse(l.back());
} else {
d->description = String(l.front(), d->textEncoding);
d->text = String(l.back(), d->textEncoding);
}
}
}

View File

@@ -36,7 +36,7 @@ namespace TagLib {
//! An implementation of ID3v2 comments
/*!
* This implements the ID3v2 comment format. An ID3v2 comment concists of
* This implements the ID3v2 comment format. An ID3v2 comment consists of
* a language encoding, a description and a single text field.
*/
@@ -106,7 +106,7 @@ namespace TagLib {
/*!
* Sets the description of the comment to \a s.
*
* \see decription()
* \see description()
*/
void setDescription(const String &s);
@@ -136,9 +136,20 @@ namespace TagLib {
*/
void setTextEncoding(String::Type encoding);
/*!
* Parses this frame as PropertyMap with a single key.
* - if description() is empty or "COMMENT", the key will be "COMMENT"
* - if description() is not a valid PropertyMap key, the frame will be
* marked unsupported by an entry "COMM/<description>" in the unsupportedData()
* attribute of the returned map.
* - otherwise, the key will be "COMMENT:<description>"
* - The single value will be the frame's text().
*/
PropertyMap asProperties() const;
/*!
* Comments each have a unique description. This searches for a comment
* frame with the decription \a d and returns a pointer to it. If no
* frame with the description \a d and returns a pointer to it. If no
* frame is found that matches the given description null is returned.
*
* \see description()

View File

@@ -0,0 +1,144 @@
/***************************************************************************
copyright : (C) 2014 by Urs Fleisch
email : ufleisch@users.sourceforge.net
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include "eventtimingcodesframe.h"
#include <tbytevectorlist.h>
#include <id3v2tag.h>
#include <tdebug.h>
#include <tpropertymap.h>
using namespace TagLib;
using namespace ID3v2;
class EventTimingCodesFrame::EventTimingCodesFramePrivate
{
public:
EventTimingCodesFramePrivate() :
timestampFormat(EventTimingCodesFrame::AbsoluteMilliseconds) {}
EventTimingCodesFrame::TimestampFormat timestampFormat;
EventTimingCodesFrame::SynchedEventList synchedEvents;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
EventTimingCodesFrame::EventTimingCodesFrame() :
Frame("ETCO")
{
d = new EventTimingCodesFramePrivate;
}
EventTimingCodesFrame::EventTimingCodesFrame(const ByteVector &data) :
Frame(data)
{
d = new EventTimingCodesFramePrivate;
setData(data);
}
EventTimingCodesFrame::~EventTimingCodesFrame()
{
delete d;
}
String EventTimingCodesFrame::toString() const
{
return String();
}
EventTimingCodesFrame::TimestampFormat
EventTimingCodesFrame::timestampFormat() const
{
return d->timestampFormat;
}
EventTimingCodesFrame::SynchedEventList
EventTimingCodesFrame::synchedEvents() const
{
return d->synchedEvents;
}
void EventTimingCodesFrame::setTimestampFormat(
EventTimingCodesFrame::TimestampFormat f)
{
d->timestampFormat = f;
}
void EventTimingCodesFrame::setSynchedEvents(
const EventTimingCodesFrame::SynchedEventList &e)
{
d->synchedEvents = e;
}
////////////////////////////////////////////////////////////////////////////////
// protected members
////////////////////////////////////////////////////////////////////////////////
void EventTimingCodesFrame::parseFields(const ByteVector &data)
{
const int end = data.size();
if(end < 1) {
debug("An event timing codes frame must contain at least 1 byte.");
return;
}
d->timestampFormat = TimestampFormat(data[0]);
int pos = 1;
d->synchedEvents.clear();
while(pos + 4 < end) {
EventType type = EventType(uchar(data[pos++]));
uint time = data.toUInt(pos, true);
pos += 4;
d->synchedEvents.append(SynchedEvent(time, type));
}
}
ByteVector EventTimingCodesFrame::renderFields() const
{
ByteVector v;
v.append(char(d->timestampFormat));
for(SynchedEventList::ConstIterator it = d->synchedEvents.begin();
it != d->synchedEvents.end();
++it) {
const SynchedEvent &entry = *it;
v.append(char(entry.type));
v.append(ByteVector::fromUInt(entry.time));
}
return v;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
EventTimingCodesFrame::EventTimingCodesFrame(const ByteVector &data, Header *h)
: Frame(h)
{
d = new EventTimingCodesFramePrivate();
parseFields(fieldData(data));
}

View File

@@ -0,0 +1,185 @@
/***************************************************************************
copyright : (C) 2014 by Urs Fleisch
email : ufleisch@users.sourceforge.net
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifndef TAGLIB_EVENTTIMINGCODESFRAME_H
#define TAGLIB_EVENTTIMINGCODESFRAME_H
#include "id3v2frame.h"
#include "tlist.h"
namespace TagLib {
namespace ID3v2 {
//! ID3v2 event timing codes frame
/*!
* An implementation of ID3v2 event timing codes.
*/
class TAGLIB_EXPORT EventTimingCodesFrame : public Frame
{
friend class FrameFactory;
public:
/*!
* Specifies the timestamp format used.
*/
enum TimestampFormat {
//! The timestamp is of unknown format.
Unknown = 0x00,
//! The timestamp represents the number of MPEG frames since
//! the beginning of the audio stream.
AbsoluteMpegFrames = 0x01,
//! The timestamp represents the number of milliseconds since
//! the beginning of the audio stream.
AbsoluteMilliseconds = 0x02
};
/*!
* Event types defined in id3v2.4.0-frames.txt 4.5. Event timing codes.
*/
enum EventType {
Padding = 0x00,
EndOfInitialSilence = 0x01,
IntroStart = 0x02,
MainPartStart = 0x03,
OutroStart = 0x04,
OutroEnd = 0x05,
VerseStart = 0x06,
RefrainStart = 0x07,
InterludeStart = 0x08,
ThemeStart = 0x09,
VariationStart = 0x0a,
KeyChange = 0x0b,
TimeChange = 0x0c,
MomentaryUnwantedNoise = 0x0d,
SustainedNoise = 0x0e,
SustainedNoiseEnd = 0x0f,
IntroEnd = 0x10,
MainPartEnd = 0x11,
VerseEnd = 0x12,
RefrainEnd = 0x13,
ThemeEnd = 0x14,
Profanity = 0x15,
ProfanityEnd = 0x16,
NotPredefinedSynch0 = 0xe0,
NotPredefinedSynch1 = 0xe1,
NotPredefinedSynch2 = 0xe2,
NotPredefinedSynch3 = 0xe3,
NotPredefinedSynch4 = 0xe4,
NotPredefinedSynch5 = 0xe5,
NotPredefinedSynch6 = 0xe6,
NotPredefinedSynch7 = 0xe7,
NotPredefinedSynch8 = 0xe8,
NotPredefinedSynch9 = 0xe9,
NotPredefinedSynchA = 0xea,
NotPredefinedSynchB = 0xeb,
NotPredefinedSynchC = 0xec,
NotPredefinedSynchD = 0xed,
NotPredefinedSynchE = 0xee,
NotPredefinedSynchF = 0xef,
AudioEnd = 0xfd,
AudioFileEnds = 0xfe
};
/*!
* Single entry of time stamp and event.
*/
struct SynchedEvent {
SynchedEvent(uint ms, EventType t) : time(ms), type(t) {}
uint time;
EventType type;
};
/*!
* List of synchronized events.
*/
typedef TagLib::List<SynchedEvent> SynchedEventList;
/*!
* Construct an empty event timing codes frame.
*/
explicit EventTimingCodesFrame();
/*!
* Construct a event timing codes frame based on the data in \a data.
*/
explicit EventTimingCodesFrame(const ByteVector &data);
/*!
* Destroys this EventTimingCodesFrame instance.
*/
virtual ~EventTimingCodesFrame();
/*!
* Returns a null string.
*/
virtual String toString() const;
/*!
* Returns the timestamp format.
*/
TimestampFormat timestampFormat() const;
/*!
* Returns the events with the time stamps.
*/
SynchedEventList synchedEvents() const;
/*!
* Set the timestamp format.
*
* \see timestampFormat()
*/
void setTimestampFormat(TimestampFormat f);
/*!
* Sets the text with the time stamps.
*
* \see text()
*/
void setSynchedEvents(const SynchedEventList &e);
protected:
// Reimplementations.
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
private:
/*!
* The constructor used by the FrameFactory.
*/
EventTimingCodesFrame(const ByteVector &data, Header *h);
EventTimingCodesFrame(const EventTimingCodesFrame &);
EventTimingCodesFrame &operator=(const EventTimingCodesFrame &);
class EventTimingCodesFramePrivate;
EventTimingCodesFramePrivate *d;
};
}
}
#endif

View File

@@ -0,0 +1,162 @@
/***************************************************************************
copyright : (C) 2012 by Rupert Daniel
email : rupert@cancelmonday.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 <tdebug.h>
#include "ownershipframe.h"
#include <id3v2tag.h>
using namespace TagLib;
using namespace ID3v2;
class OwnershipFrame::OwnershipFramePrivate
{
public:
String pricePaid;
String datePurchased;
String seller;
String::Type textEncoding;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
OwnershipFrame::OwnershipFrame(String::Type encoding) : Frame("OWNE")
{
d = new OwnershipFramePrivate;
d->textEncoding = encoding;
}
OwnershipFrame::OwnershipFrame(const ByteVector &data) : Frame(data)
{
d = new OwnershipFramePrivate;
setData(data);
}
OwnershipFrame::~OwnershipFrame()
{
delete d;
}
String OwnershipFrame::toString() const
{
return "pricePaid=" + d->pricePaid + " datePurchased=" + d->datePurchased + " seller=" + d->seller;
}
String OwnershipFrame::pricePaid() const
{
return d->pricePaid;
}
void OwnershipFrame::setPricePaid(const String &s)
{
d->pricePaid = s;
}
String OwnershipFrame::datePurchased() const
{
return d->datePurchased;
}
void OwnershipFrame::setDatePurchased(const String &s)
{
d->datePurchased = s;
}
String OwnershipFrame::seller() const
{
return d->seller;
}
void OwnershipFrame::setSeller(const String &s)
{
d->seller = s;
}
String::Type OwnershipFrame::textEncoding() const
{
return d->textEncoding;
}
void OwnershipFrame::setTextEncoding(String::Type encoding)
{
d->textEncoding = encoding;
}
////////////////////////////////////////////////////////////////////////////////
// protected members
////////////////////////////////////////////////////////////////////////////////
void OwnershipFrame::parseFields(const ByteVector &data)
{
int pos = 0;
// Get the text encoding
d->textEncoding = String::Type(data[0]);
pos += 1;
// Read the price paid this is a null terminate string
d->pricePaid = readStringField(data, String::Latin1, &pos);
// If we don't have at least 8 bytes left then don't parse the rest of the
// data
if(data.size() - pos < 8) {
return;
}
// Read the date purchased YYYYMMDD
d->datePurchased = String(data.mid(pos, 8));
pos += 8;
// Read the seller
if(d->textEncoding == String::Latin1)
d->seller = Tag::latin1StringHandler()->parse(data.mid(pos));
else
d->seller = String(data.mid(pos), d->textEncoding);
}
ByteVector OwnershipFrame::renderFields() const
{
ByteVector v;
v.append(char(d->textEncoding));
v.append(d->pricePaid.data(String::Latin1));
v.append(textDelimiter(String::Latin1));
v.append(d->datePurchased.data(String::Latin1));
v.append(d->seller.data(d->textEncoding));
return v;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
OwnershipFrame::OwnershipFrame(const ByteVector &data, Header *h) : Frame(h)
{
d = new OwnershipFramePrivate;
parseFields(fieldData(data));
}

View File

@@ -0,0 +1,151 @@
/***************************************************************************
copyright : (C) 2012 by Rupert Daniel
email : rupert@cancelmonday.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_OWNERSHIPFRAME_H
#define TAGLIB_OWNERSHIPFRAME_H
#include "id3v2frame.h"
#include "taglib_export.h"
namespace TagLib {
namespace ID3v2 {
//! An implementation of ID3v2 "ownership"
/*!
* This implements the ID3v2 ownership (OWNE frame). It consists of
* a price paid, a date purchased (YYYYMMDD) and the name of the seller.
*/
class TAGLIB_EXPORT OwnershipFrame : public Frame
{
friend class FrameFactory;
public:
/*!
* Construct an empty ownership frame.
*/
explicit OwnershipFrame(String::Type encoding = String::Latin1);
/*!
* Construct a ownership based on the data in \a data.
*/
explicit OwnershipFrame(const ByteVector &data);
/*!
* Destroys this OwnershipFrame instance.
*/
virtual ~OwnershipFrame();
/*!
* Returns the text of this popularimeter.
*
* \see text()
*/
virtual String toString() const;
/*!
* Returns the date purchased.
*
* \see setDatePurchased()
*/
String datePurchased() const;
/*!
* Set the date purchased.
*
* \see datePurchased()
*/
void setDatePurchased(const String &datePurchased);
/*!
* Returns the price paid.
*
* \see setPricePaid()
*/
String pricePaid() const;
/*!
* Set the price paid.
*
* \see pricePaid()
*/
void setPricePaid(const String &pricePaid);
/*!
* Returns the seller.
*
* \see setSeller()
*/
String seller() const;
/*!
* Set the seller.
*
* \see seller()
*/
void setSeller(const String &seller);
/*!
* Returns the text encoding that will be used in rendering this frame.
* This defaults to the type that was either specified in the constructor
* or read from the frame when parsed.
*
* \see setTextEncoding()
* \see render()
*/
String::Type textEncoding() const;
/*!
* Sets the text encoding to be used when rendering this frame to
* \a encoding.
*
* \see textEncoding()
* \see render()
*/
void setTextEncoding(String::Type encoding);
protected:
// Reimplementations.
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
private:
/*!
* The constructor used by the FrameFactory.
*/
OwnershipFrame(const ByteVector &data, Header *h);
OwnershipFrame(const OwnershipFrame &);
OwnershipFrame &operator=(const OwnershipFrame &);
class OwnershipFramePrivate;
OwnershipFramePrivate *d;
};
}
}
#endif

View File

@@ -109,7 +109,7 @@ void PopularimeterFrame::parseFields(const ByteVector &data)
if(pos < size) {
d->rating = (unsigned char)(data[pos++]);
if(pos < size) {
d->counter = data.mid(pos, 4).toUInt();
d->counter = data.toUInt(static_cast<uint>(pos));
}
}
}

View File

@@ -36,7 +36,7 @@ namespace TagLib {
//! An implementation of ID3v2 "popularimeter"
/*!
* This implements the ID3v2 popularimeter (POPM frame). It concists of
* This implements the ID3v2 popularimeter (POPM frame). It consists of
* an email, a rating and an optional counter.
*/

View File

@@ -98,7 +98,7 @@ void PrivateFrame::parseFields(const ByteVector &data)
}
// Owner identifier is assumed to be Latin1
const int byteAlign = 1;
const int endOfOwner = data.find(textDelimiter(String::Latin1), 0, byteAlign);

View File

@@ -191,7 +191,7 @@ void RelativeVolumeFrame::parseFields(const ByteVector &data)
ChannelData &channel = d->channels[type];
channel.volumeAdjustment = data.mid(pos, 2).toShort();
channel.volumeAdjustment = data.toShort(static_cast<uint>(pos));
pos += 2;
channel.peakVolume.bitsRepresentingPeak = data[pos];

View File

@@ -140,7 +140,7 @@ namespace TagLib {
/*
* There was a terrible API goof here, and while this can't be changed to
* the way it appears below for binary compaibility reasons, let's at
* the way it appears below for binary compatibility reasons, let's at
* least pretend that it looks clean.
*/
@@ -149,7 +149,7 @@ namespace TagLib {
/*!
* Returns the relative volume adjustment "index". As indicated by the
* ID3v2 standard this is a 16-bit signed integer that reflects the
* decibils of adjustment when divided by 512.
* decibels of adjustment when divided by 512.
*
* This defaults to returning the value for the master volume channel if
* available and returns 0 if the specified channel does not exist.
@@ -161,7 +161,7 @@ namespace TagLib {
/*!
* Set the volume adjustment to \a index. As indicated by the ID3v2
* standard this is a 16-bit signed integer that reflects the decibils of
* standard this is a 16-bit signed integer that reflects the decibels of
* adjustment when divided by 512.
*
* By default this sets the value for the master volume.

View File

@@ -0,0 +1,243 @@
/***************************************************************************
copyright : (C) 2014 by Urs Fleisch
email : ufleisch@users.sourceforge.net
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include "synchronizedlyricsframe.h"
#include <tbytevectorlist.h>
#include <id3v2tag.h>
#include <tdebug.h>
#include <tpropertymap.h>
using namespace TagLib;
using namespace ID3v2;
class SynchronizedLyricsFrame::SynchronizedLyricsFramePrivate
{
public:
SynchronizedLyricsFramePrivate() :
textEncoding(String::Latin1),
timestampFormat(SynchronizedLyricsFrame::AbsoluteMilliseconds),
type(SynchronizedLyricsFrame::Lyrics) {}
String::Type textEncoding;
ByteVector language;
SynchronizedLyricsFrame::TimestampFormat timestampFormat;
SynchronizedLyricsFrame::Type type;
String description;
SynchronizedLyricsFrame::SynchedTextList synchedText;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
SynchronizedLyricsFrame::SynchronizedLyricsFrame(String::Type encoding) :
Frame("SYLT")
{
d = new SynchronizedLyricsFramePrivate;
d->textEncoding = encoding;
}
SynchronizedLyricsFrame::SynchronizedLyricsFrame(const ByteVector &data) :
Frame(data)
{
d = new SynchronizedLyricsFramePrivate;
setData(data);
}
SynchronizedLyricsFrame::~SynchronizedLyricsFrame()
{
delete d;
}
String SynchronizedLyricsFrame::toString() const
{
return d->description;
}
String::Type SynchronizedLyricsFrame::textEncoding() const
{
return d->textEncoding;
}
ByteVector SynchronizedLyricsFrame::language() const
{
return d->language;
}
SynchronizedLyricsFrame::TimestampFormat
SynchronizedLyricsFrame::timestampFormat() const
{
return d->timestampFormat;
}
SynchronizedLyricsFrame::Type SynchronizedLyricsFrame::type() const
{
return d->type;
}
String SynchronizedLyricsFrame::description() const
{
return d->description;
}
SynchronizedLyricsFrame::SynchedTextList
SynchronizedLyricsFrame::synchedText() const
{
return d->synchedText;
}
void SynchronizedLyricsFrame::setTextEncoding(String::Type encoding)
{
d->textEncoding = encoding;
}
void SynchronizedLyricsFrame::setLanguage(const ByteVector &languageEncoding)
{
d->language = languageEncoding.mid(0, 3);
}
void SynchronizedLyricsFrame::setTimestampFormat(
SynchronizedLyricsFrame::TimestampFormat f)
{
d->timestampFormat = f;
}
void SynchronizedLyricsFrame::setType(SynchronizedLyricsFrame::Type t)
{
d->type = t;
}
void SynchronizedLyricsFrame::setDescription(const String &s)
{
d->description = s;
}
void SynchronizedLyricsFrame::setSynchedText(
const SynchronizedLyricsFrame::SynchedTextList &t)
{
d->synchedText = t;
}
////////////////////////////////////////////////////////////////////////////////
// protected members
////////////////////////////////////////////////////////////////////////////////
void SynchronizedLyricsFrame::parseFields(const ByteVector &data)
{
const int end = data.size();
if(end < 7) {
debug("A synchronized lyrics frame must contain at least 7 bytes.");
return;
}
d->textEncoding = String::Type(data[0]);
d->language = data.mid(1, 3);
d->timestampFormat = TimestampFormat(data[4]);
d->type = Type(data[5]);
int pos = 6;
d->description = readStringField(data, d->textEncoding, &pos);
if(d->description.isNull())
return;
/*
* If UTF16 strings are found in SYLT frames, a BOM may only be
* present in the first string (content descriptor), and the strings of
* the synchronized text have no BOM. Here the BOM is read from
* the first string to have a specific encoding with endianness for the
* case of strings without BOM so that readStringField() will work.
*/
String::Type encWithEndianness = d->textEncoding;
if(d->textEncoding == String::UTF16) {
ushort bom = data.toUShort(6, true);
if(bom == 0xfffe) {
encWithEndianness = String::UTF16LE;
} else if(bom == 0xfeff) {
encWithEndianness = String::UTF16BE;
}
}
d->synchedText.clear();
while(pos < end) {
String::Type enc = d->textEncoding;
// If a UTF16 string has no BOM, use the encoding found above.
if(enc == String::UTF16 && pos + 1 < end) {
ushort bom = data.toUShort(pos, true);
if(bom != 0xfffe && bom != 0xfeff) {
enc = encWithEndianness;
}
}
String text = readStringField(data, enc, &pos);
if(text.isNull() || pos + 4 > end)
return;
uint time = data.toUInt(pos, true);
pos += 4;
d->synchedText.append(SynchedText(time, text));
}
}
ByteVector SynchronizedLyricsFrame::renderFields() const
{
ByteVector v;
String::Type encoding = d->textEncoding;
encoding = checkTextEncoding(d->description, encoding);
for(SynchedTextList::ConstIterator it = d->synchedText.begin();
it != d->synchedText.end();
++it) {
encoding = checkTextEncoding(it->text, encoding);
}
v.append(char(encoding));
v.append(d->language.size() == 3 ? d->language : "XXX");
v.append(char(d->timestampFormat));
v.append(char(d->type));
v.append(d->description.data(encoding));
v.append(textDelimiter(encoding));
for(SynchedTextList::ConstIterator it = d->synchedText.begin();
it != d->synchedText.end();
++it) {
const SynchedText &entry = *it;
v.append(entry.text.data(encoding));
v.append(textDelimiter(encoding));
v.append(ByteVector::fromUInt(entry.time));
}
return v;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
SynchronizedLyricsFrame::SynchronizedLyricsFrame(const ByteVector &data, Header *h)
: Frame(h)
{
d = new SynchronizedLyricsFramePrivate();
parseFields(fieldData(data));
}

View File

@@ -0,0 +1,231 @@
/***************************************************************************
copyright : (C) 2014 by Urs Fleisch
email : ufleisch@users.sourceforge.net
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifndef TAGLIB_SYNCHRONIZEDLYRICSFRAME_H
#define TAGLIB_SYNCHRONIZEDLYRICSFRAME_H
#include "id3v2frame.h"
#include "tlist.h"
namespace TagLib {
namespace ID3v2 {
//! ID3v2 synchronized lyrics frame
/*!
* An implementation of ID3v2 synchronized lyrics.
*/
class TAGLIB_EXPORT SynchronizedLyricsFrame : public Frame
{
friend class FrameFactory;
public:
/*!
* Specifies the timestamp format used.
*/
enum TimestampFormat {
//! The timestamp is of unknown format.
Unknown = 0x00,
//! The timestamp represents the number of MPEG frames since
//! the beginning of the audio stream.
AbsoluteMpegFrames = 0x01,
//! The timestamp represents the number of milliseconds since
//! the beginning of the audio stream.
AbsoluteMilliseconds = 0x02
};
/*!
* Specifies the type of text contained.
*/
enum Type {
//! The text is some other type of text.
Other = 0x00,
//! The text contains lyrical data.
Lyrics = 0x01,
//! The text contains a transcription.
TextTranscription = 0x02,
//! The text lists the movements in the piece.
Movement = 0x03,
//! The text describes events that occur.
Events = 0x04,
//! The text contains chord changes that occur in the music.
Chord = 0x05,
//! The text contains trivia or "pop up" information about the media.
Trivia = 0x06,
//! The text contains URLs for relevant webpages.
WebpageUrls = 0x07,
//! The text contains URLs for relevant images.
ImageUrls = 0x08
};
/*!
* Single entry of time stamp and lyrics text.
*/
struct SynchedText {
SynchedText(uint ms, String str) : time(ms), text(str) {}
uint time;
String text;
};
/*!
* List of synchronized lyrics.
*/
typedef TagLib::List<SynchedText> SynchedTextList;
/*!
* Construct an empty synchronized lyrics frame that will use the text
* encoding \a encoding.
*/
explicit SynchronizedLyricsFrame(String::Type encoding = String::Latin1);
/*!
* Construct a synchronized lyrics frame based on the data in \a data.
*/
explicit SynchronizedLyricsFrame(const ByteVector &data);
/*!
* Destroys this SynchronizedLyricsFrame instance.
*/
virtual ~SynchronizedLyricsFrame();
/*!
* Returns the description of this synchronized lyrics frame.
*
* \see description()
*/
virtual String toString() const;
/*!
* Returns the text encoding that will be used in rendering this frame.
* This defaults to the type that was either specified in the constructor
* or read from the frame when parsed.
*
* \see setTextEncoding()
* \see render()
*/
String::Type textEncoding() const;
/*!
* Returns the language encoding as a 3 byte encoding as specified by
* <a href="http://en.wikipedia.org/wiki/ISO_639">ISO-639-2</a>.
*
* \note Most taggers simply ignore this value.
*
* \see setLanguage()
*/
ByteVector language() const;
/*!
* Returns the timestamp format.
*/
TimestampFormat timestampFormat() const;
/*!
* Returns the type of text contained.
*/
Type type() const;
/*!
* Returns the description of this synchronized lyrics frame.
*
* \note Most taggers simply ignore this value.
*
* \see setDescription()
*/
String description() const;
/*!
* Returns the text with the time stamps.
*/
SynchedTextList synchedText() const;
/*!
* Sets the text encoding to be used when rendering this frame to
* \a encoding.
*
* \see textEncoding()
* \see render()
*/
void setTextEncoding(String::Type encoding);
/*!
* Set the language using the 3 byte language code from
* <a href="http://en.wikipedia.org/wiki/ISO_639">ISO-639-2</a> to
* \a languageCode.
*
* \see language()
*/
void setLanguage(const ByteVector &languageCode);
/*!
* Set the timestamp format.
*
* \see timestampFormat()
*/
void setTimestampFormat(TimestampFormat f);
/*!
* Set the type of text contained.
*
* \see type()
*/
void setType(Type t);
/*!
* Sets the description of the synchronized lyrics frame to \a s.
*
* \see description()
*/
void setDescription(const String &s);
/*!
* Sets the text with the time stamps.
*
* \see text()
*/
void setSynchedText(const SynchedTextList &t);
protected:
// Reimplementations.
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
private:
/*!
* The constructor used by the FrameFactory.
*/
SynchronizedLyricsFrame(const ByteVector &data, Header *h);
SynchronizedLyricsFrame(const SynchronizedLyricsFrame &);
SynchronizedLyricsFrame &operator=(const SynchronizedLyricsFrame &);
class SynchronizedLyricsFramePrivate;
SynchronizedLyricsFramePrivate *d;
};
}
}
#endif

View File

@@ -0,0 +1,338 @@
/***************************************************************************
copyright : (C) 2013 by Lukas Krejci
email : krejclu6@fel.cvut.cz
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <tbytevectorlist.h>
#include <tpropertymap.h>
#include <tdebug.h>
#include "tableofcontentsframe.h"
using namespace TagLib;
using namespace ID3v2;
class TableOfContentsFrame::TableOfContentsFramePrivate
{
public:
TableOfContentsFramePrivate() :
tagHeader(0)
{
embeddedFrameList.setAutoDelete(true);
}
const ID3v2::Header *tagHeader;
ByteVector elementID;
bool isTopLevel;
bool isOrdered;
ByteVectorList childElements;
FrameListMap embeddedFrameListMap;
FrameList embeddedFrameList;
};
namespace {
// These functions are needed to try to aim for backward compatibility with
// an API that previously (unreasonably) required null bytes to be appeneded
// at the end of identifiers explicitly by the API user.
// BIC: remove these
ByteVector &strip(ByteVector &b)
{
if(b.endsWith('\0'))
b.resize(b.size() - 1);
return b;
}
ByteVectorList &strip(ByteVectorList &l)
{
for(ByteVectorList::Iterator it = l.begin(); it != l.end(); ++it)
{
strip(*it);
}
return l;
}
}
////////////////////////////////////////////////////////////////////////////////
// public methods
////////////////////////////////////////////////////////////////////////////////
TableOfContentsFrame::TableOfContentsFrame(const ID3v2::Header *tagHeader, const ByteVector &data) :
ID3v2::Frame(data)
{
d = new TableOfContentsFramePrivate;
d->tagHeader = tagHeader;
setData(data);
}
TableOfContentsFrame::TableOfContentsFrame(const ByteVector &elementID,
const ByteVectorList &children,
const FrameList &embeddedFrames) :
ID3v2::Frame("CTOC")
{
d = new TableOfContentsFramePrivate;
d->elementID = elementID;
strip(d->elementID);
d->childElements = children;
for(FrameList::ConstIterator it = embeddedFrames.begin(); it != embeddedFrames.end(); ++it)
addEmbeddedFrame(*it);
}
TableOfContentsFrame::~TableOfContentsFrame()
{
delete d;
}
ByteVector TableOfContentsFrame::elementID() const
{
return d->elementID;
}
bool TableOfContentsFrame::isTopLevel() const
{
return d->isTopLevel;
}
bool TableOfContentsFrame::isOrdered() const
{
return d->isOrdered;
}
TagLib::uint TableOfContentsFrame::entryCount() const
{
return d->childElements.size();
}
ByteVectorList TableOfContentsFrame::childElements() const
{
return d->childElements;
}
void TableOfContentsFrame::setElementID(const ByteVector &eID)
{
d->elementID = eID;
strip(d->elementID);
}
void TableOfContentsFrame::setIsTopLevel(const bool &t)
{
d->isTopLevel = t;
}
void TableOfContentsFrame::setIsOrdered(const bool &o)
{
d->isOrdered = o;
}
void TableOfContentsFrame::setChildElements(const ByteVectorList &l)
{
d->childElements = l;
strip(d->childElements);
}
void TableOfContentsFrame::addChildElement(const ByteVector &cE)
{
d->childElements.append(cE);
strip(d->childElements);
}
void TableOfContentsFrame::removeChildElement(const ByteVector &cE)
{
ByteVectorList::Iterator it = d->childElements.find(cE);
if(it == d->childElements.end())
it = d->childElements.find(cE + ByteVector("\0"));
d->childElements.erase(it);
}
const FrameListMap &TableOfContentsFrame::embeddedFrameListMap() const
{
return d->embeddedFrameListMap;
}
const FrameList &TableOfContentsFrame::embeddedFrameList() const
{
return d->embeddedFrameList;
}
const FrameList &TableOfContentsFrame::embeddedFrameList(const ByteVector &frameID) const
{
return d->embeddedFrameListMap[frameID];
}
void TableOfContentsFrame::addEmbeddedFrame(Frame *frame)
{
d->embeddedFrameList.append(frame);
d->embeddedFrameListMap[frame->frameID()].append(frame);
}
void TableOfContentsFrame::removeEmbeddedFrame(Frame *frame, bool del)
{
// remove the frame from the frame list
FrameList::Iterator it = d->embeddedFrameList.find(frame);
d->embeddedFrameList.erase(it);
// ...and from the frame list map
it = d->embeddedFrameListMap[frame->frameID()].find(frame);
d->embeddedFrameListMap[frame->frameID()].erase(it);
// ...and delete as desired
if(del)
delete frame;
}
void TableOfContentsFrame::removeEmbeddedFrames(const ByteVector &id)
{
FrameList l = d->embeddedFrameListMap[id];
for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it)
removeEmbeddedFrame(*it, true);
}
String TableOfContentsFrame::toString() const
{
return String::null;
}
PropertyMap TableOfContentsFrame::asProperties() const
{
PropertyMap map;
map.unsupportedData().append(frameID() + String("/") + d->elementID);
return map;
}
TableOfContentsFrame *TableOfContentsFrame::findByElementID(const ID3v2::Tag *tag,
const ByteVector &eID) // static
{
ID3v2::FrameList tablesOfContents = tag->frameList("CTOC");
for(ID3v2::FrameList::ConstIterator it = tablesOfContents.begin();
it != tablesOfContents.end();
++it)
{
TableOfContentsFrame *frame = dynamic_cast<TableOfContentsFrame *>(*it);
if(frame && frame->elementID() == eID)
return frame;
}
return 0;
}
TableOfContentsFrame *TableOfContentsFrame::findTopLevel(const ID3v2::Tag *tag) // static
{
ID3v2::FrameList tablesOfContents = tag->frameList("CTOC");
for(ID3v2::FrameList::ConstIterator it = tablesOfContents.begin();
it != tablesOfContents.end();
++it)
{
TableOfContentsFrame *frame = dynamic_cast<TableOfContentsFrame *>(*it);
if(frame && frame->isTopLevel() == true)
return frame;
}
return 0;
}
void TableOfContentsFrame::parseFields(const ByteVector &data)
{
TagLib::uint size = data.size();
if(size < 6) {
debug("A CTOC frame must contain at least 6 bytes (1 byte element ID terminated by "
"null, 1 byte flags, 1 byte entry count and 1 byte child element ID terminated "
"by null.");
return;
}
int pos = 0;
TagLib::uint embPos = 0;
d->elementID = readStringField(data, String::Latin1, &pos).data(String::Latin1);
d->isTopLevel = (data.at(pos) & 2) > 0;
d->isOrdered = (data.at(pos++) & 1) > 0;
TagLib::uint entryCount = data.at(pos++);
for(TagLib::uint i = 0; i < entryCount; i++) {
ByteVector childElementID = readStringField(data, String::Latin1, &pos).data(String::Latin1);
d->childElements.append(childElementID);
}
size -= pos;
if(size < header()->size())
return;
while(embPos < size - header()->size()) {
Frame *frame = FrameFactory::instance()->createFrame(data.mid(pos + embPos), (d->tagHeader != 0));
if(!frame)
return;
// Checks to make sure that frame parsed correctly.
if(frame->size() <= 0) {
delete frame;
return;
}
embPos += frame->size() + header()->size();
addEmbeddedFrame(frame);
}
}
ByteVector TableOfContentsFrame::renderFields() const
{
ByteVector data;
data.append(d->elementID);
data.append('\0');
char flags = 0;
if(d->isTopLevel)
flags += 2;
if(d->isOrdered)
flags += 1;
data.append(flags);
data.append((char)(entryCount()));
ByteVectorList::ConstIterator it = d->childElements.begin();
while(it != d->childElements.end()) {
data.append(*it);
data.append('\0');
it++;
}
FrameList l = d->embeddedFrameList;
for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it)
data.append((*it)->render());
return data;
}
TableOfContentsFrame::TableOfContentsFrame(const ID3v2::Header *tagHeader,
const ByteVector &data, Header *h) :
Frame(h)
{
d = new TableOfContentsFramePrivate;
d->tagHeader = tagHeader;
parseFields(fieldData(data));
}

View File

@@ -0,0 +1,258 @@
/***************************************************************************
copyright : (C) 2013 by Lukas Krejci
email : krejclu6@fel.cvut.cz
***************************************************************************/
/***************************************************************************
* 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_TABLEOFCONTENTSFRAME
#define TAGLIB_TABLEOFCONTENTSFRAME
#include "id3v2tag.h"
#include "id3v2frame.h"
namespace TagLib {
namespace ID3v2 {
/*!
* This is an implementation of ID3v2 table of contents frames. Purpose
* of this frame is to allow a table of contents to be defined.
*/
//! An implementation of ID3v2 table of contents frames
class TAGLIB_EXPORT TableOfContentsFrame : public ID3v2::Frame
{
friend class FrameFactory;
public:
/*!
* Creates a table of contents frame based on \a data. \a tagHeader is
* required as the internal frames are parsed based on the tag version.
*/
TableOfContentsFrame(const ID3v2::Header *tagHeader, const ByteVector &data);
/*!
* Creates a table of contents frame with the element ID \a elementID,
* the child elements \a children and embedded frames, which become owned
* by this frame, in \a embeddedFrames.
*/
TableOfContentsFrame(const ByteVector &elementID,
const ByteVectorList &children = ByteVectorList(),
const FrameList &embeddedFrames = FrameList());
/*!
* Destroys the frame.
*/
~TableOfContentsFrame();
/*!
* Returns the elementID of the frame. Element ID
* is a null terminated string, however it's not human-readable.
*
* \see setElementID()
*/
ByteVector elementID() const;
/*!
* Returns true, if the frame is top-level (doesn't have
* any parent CTOC frame).
*
* \see setIsTopLevel()
*/
bool isTopLevel() const;
/*!
* Returns true, if the child elements list entries
* are ordered.
*
* \see setIsOrdered()
*/
bool isOrdered() const;
/*!
* Returns count of child elements of the frame. It always
* corresponds to size of child elements list.
*
* \see childElements()
*/
uint entryCount() const;
/*!
* Returns list of child elements of the frame.
*
* \see setChildElements()
*/
ByteVectorList childElements() const;
/*!
* Sets the elementID of the frame to \a eID. If \a eID isn't
* null terminated, a null char is appended automatically.
*
* \see elementID()
*/
void setElementID(const ByteVector &eID);
/*!
* Sets, if the frame is top-level (doesn't have
* any parent CTOC frame).
*
* \see isTopLevel()
*/
void setIsTopLevel(const bool &t);
/*!
* Sets, if the child elements list entries
* are ordered.
*
* \see isOrdered()
*/
void setIsOrdered(const bool &o);
/*!
* Sets list of child elements of the frame to \a l.
*
* \see childElements()
*/
void setChildElements(const ByteVectorList &l);
/*!
* Adds \a cE to list of child elements of the frame.
*
* \see childElements()
*/
void addChildElement(const ByteVector &cE);
/*!
* Removes \a cE to list of child elements of the frame.
*
* \see childElements()
*/
void removeChildElement(const ByteVector &cE);
/*!
* Returns a reference to the frame list map. This is an FrameListMap of
* all of the frames embedded in the CTOC frame.
*
* This is the most convenient structure for accessing the CTOC frame's
* embedded frames. Many frame types allow multiple instances of the same
* frame type so this is a map of lists. In most cases however there will
* only be a single frame of a certain type.
*
* \warning You should not modify this data structure directly, instead
* use addEmbeddedFrame() and removeEmbeddedFrame().
*
* \see embeddedFrameList()
*/
const FrameListMap &embeddedFrameListMap() const;
/*!
* Returns a reference to the embedded frame list. This is an FrameList
* of all of the frames embedded in the CTOC frame in the order that they
* were parsed.
*
* This can be useful if for example you want iterate over the CTOC frame's
* embedded frames in the order that they occur in the CTOC frame.
*
* \warning You should not modify this data structure directly, instead
* use addEmbeddedFrame() and removeEmbeddedFrame().
*/
const FrameList &embeddedFrameList() const;
/*!
* Returns the embedded frame list for frames with the id \a frameID
* or an empty list if there are no embedded frames of that type. This
* is just a convenience and is equivalent to:
*
* \code
* embeddedFrameListMap()[frameID];
* \endcode
*
* \see embeddedFrameListMap()
*/
const FrameList &embeddedFrameList(const ByteVector &frameID) const;
/*!
* Add an embedded frame to the CTOC frame. At this point the CTOC frame
* takes ownership of the embedded frame and will handle freeing its memory.
*
* \note Using this method will invalidate any pointers on the list
* returned by embeddedFrameList()
*/
void addEmbeddedFrame(Frame *frame);
/*!
* Remove an embedded frame from the CTOC frame. If \a del is true the frame's
* memory will be freed; if it is false, it must be deleted by the user.
*
* \note Using this method will invalidate any pointers on the list
* returned by embeddedFrameList()
*/
void removeEmbeddedFrame(Frame *frame, bool del = true);
/*!
* Remove all embedded frames of type \a id from the CTOC frame and free their
* memory.
*
* \note Using this method will invalidate any pointers on the list
* returned by embeddedFrameList()
*/
void removeEmbeddedFrames(const ByteVector &id);
virtual String toString() const;
PropertyMap asProperties() const;
/*!
* CTOC frames each have a unique element ID. This searches for a CTOC
* frame with the element ID \a eID and returns a pointer to it. This
* can be used to link together parent and child CTOC frames.
*
* \see elementID()
*/
static TableOfContentsFrame *findByElementID(const Tag *tag, const ByteVector &eID);
/*!
* CTOC frames each contain a flag that indicates, if CTOC frame is top-level (there isn't
* any frame, which contains this frame in its child elements list). Only a single frame
* within tag can be top-level. This searches for a top-level CTOC frame.
*
* \see isTopLevel()
*/
static TableOfContentsFrame *findTopLevel(const Tag *tag);
protected:
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;
private:
TableOfContentsFrame(const ID3v2::Header *tagHeader, const ByteVector &data, Header *h);
TableOfContentsFrame(const TableOfContentsFrame &);
TableOfContentsFrame &operator=(const TableOfContentsFrame &);
class TableOfContentsFramePrivate;
TableOfContentsFramePrivate *d;
};
}
}
#endif

View File

@@ -25,8 +25,9 @@
#include <tbytevectorlist.h>
#include <id3v2tag.h>
#include "textidentificationframe.h"
#include "tpropertymap.h"
#include "id3v1genres.h"
using namespace TagLib;
using namespace ID3v2;
@@ -57,6 +58,32 @@ TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data) :
setData(data);
}
TextIdentificationFrame *TextIdentificationFrame::createTIPLFrame(const PropertyMap &properties) // static
{
TextIdentificationFrame *frame = new TextIdentificationFrame("TIPL");
StringList l;
for(PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it){
l.append(it->first);
l.append(it->second.toString(",")); // comma-separated list of names
}
frame->setText(l);
return frame;
}
TextIdentificationFrame *TextIdentificationFrame::createTMCLFrame(const PropertyMap &properties) // static
{
TextIdentificationFrame *frame = new TextIdentificationFrame("TMCL");
StringList l;
for(PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it){
if(!it->first.startsWith(instrumentPrefix)) // should not happen
continue;
l.append(it->first.substr(instrumentPrefix.size()));
l.append(it->second.toString(","));
}
frame->setText(l);
return frame;
}
TextIdentificationFrame::~TextIdentificationFrame()
{
delete d;
@@ -92,6 +119,61 @@ void TextIdentificationFrame::setTextEncoding(String::Type encoding)
d->textEncoding = encoding;
}
// array of allowed TIPL prefixes and their corresponding key value
static const TagLib::uint involvedPeopleSize = 5;
static const char* involvedPeople[][2] = {
{"ARRANGER", "ARRANGER"},
{"ENGINEER", "ENGINEER"},
{"PRODUCER", "PRODUCER"},
{"DJ-MIX", "DJMIXER"},
{"MIX", "MIXER"},
};
const KeyConversionMap &TextIdentificationFrame::involvedPeopleMap() // static
{
static KeyConversionMap m;
if(m.isEmpty())
for(uint i = 0; i < involvedPeopleSize; ++i)
m.insert(involvedPeople[i][1], involvedPeople[i][0]);
return m;
}
PropertyMap TextIdentificationFrame::asProperties() const
{
if(frameID() == "TIPL")
return makeTIPLProperties();
if(frameID() == "TMCL")
return makeTMCLProperties();
PropertyMap map;
String tagName = frameIDToKey(frameID());
if(tagName.isNull()) {
map.unsupportedData().append(frameID());
return map;
}
StringList values = fieldList();
if(tagName == "GENRE") {
// Special case: Support ID3v1-style genre numbers. They are not officially supported in
// ID3v2, however it seems that still a lot of programs use them.
for(StringList::Iterator it = values.begin(); it != values.end(); ++it) {
bool ok = false;
int test = it->toInt(&ok); // test if the genre value is an integer
if(ok)
*it = ID3v1::genre(test);
}
} else if(tagName == "DATE") {
for(StringList::Iterator it = values.begin(); it != values.end(); ++it) {
// ID3v2 specifies ISO8601 timestamps which contain a 'T' as separator between date and time.
// Since this is unusual in other formats, the T is removed.
int tpos = it->find("T");
if(tpos != -1)
(*it)[tpos] = ' ';
}
}
PropertyMap ret;
ret.insert(tagName, values);
return ret;
}
////////////////////////////////////////////////////////////////////////////////
// TextIdentificationFrame protected members
////////////////////////////////////////////////////////////////////////////////
@@ -129,10 +211,12 @@ void TextIdentificationFrame::parseFields(const ByteVector &data)
// append those split values to the list and make sure that the new string's
// type is the same specified for this frame
for(ByteVectorList::Iterator it = l.begin(); it != l.end(); it++) {
for(ByteVectorList::ConstIterator it = l.begin(); it != l.end(); it++) {
if(!(*it).isEmpty()) {
String s(*it, d->textEncoding);
d->fieldList.append(s);
if(d->textEncoding == String::Latin1)
d->fieldList.append(Tag::latin1StringHandler()->parse(*it));
else
d->fieldList.append(String(*it, d->textEncoding));
}
}
}
@@ -170,6 +254,55 @@ TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data, Header
parseFields(fieldData(data));
}
PropertyMap TextIdentificationFrame::makeTIPLProperties() const
{
PropertyMap map;
if(fieldList().size() % 2 != 0){
// according to the ID3 spec, TIPL must contain an even number of entries
map.unsupportedData().append(frameID());
return map;
}
StringList l = fieldList();
for(StringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
bool found = false;
for(uint i = 0; i < involvedPeopleSize; ++i)
if(*it == involvedPeople[i][0]) {
map.insert(involvedPeople[i][1], (++it)->split(","));
found = true;
break;
}
if(!found){
// invalid involved role -> mark whole frame as unsupported in order to be consisten with writing
map.clear();
map.unsupportedData().append(frameID());
return map;
}
}
return map;
}
PropertyMap TextIdentificationFrame::makeTMCLProperties() const
{
PropertyMap map;
if(fieldList().size() % 2 != 0){
// according to the ID3 spec, TMCL must contain an even number of entries
map.unsupportedData().append(frameID());
return map;
}
StringList l = fieldList();
for(StringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
String instrument = it->upper();
if(instrument.isNull()) {
// instrument is not a valid key -> frame unsupported
map.clear();
map.unsupportedData().append(frameID());
return map;
}
map.insert(L"PERFORMER:" + instrument, (++it)->split(","));
}
return map;
}
////////////////////////////////////////////////////////////////////////////////
// UserTextIdentificationFrame public members
////////////////////////////////////////////////////////////////////////////////
@@ -191,6 +324,14 @@ UserTextIdentificationFrame::UserTextIdentificationFrame(const ByteVector &data)
checkFields();
}
UserTextIdentificationFrame::UserTextIdentificationFrame(const String &description, const StringList &values, String::Type encoding) :
TextIdentificationFrame("TXXX", encoding),
d(0)
{
setDescription(description);
setText(values);
}
String UserTextIdentificationFrame::toString() const
{
return "[" + description() + "] " + fieldList().toString();
@@ -238,11 +379,22 @@ void UserTextIdentificationFrame::setDescription(const String &s)
TextIdentificationFrame::setText(l);
}
PropertyMap UserTextIdentificationFrame::asProperties() const
{
PropertyMap map;
String tagName = txxxToKey(description());
StringList v = fieldList();
for(StringList::ConstIterator it = v.begin(); it != v.end(); ++it)
if(it != v.begin())
map.insert(tagName, *it);
return map;
}
UserTextIdentificationFrame *UserTextIdentificationFrame::find(
ID3v2::Tag *tag, const String &description) // static
{
FrameList l = tag->frameList("TXXX");
for(FrameList::Iterator it = l.begin(); it != l.end(); ++it) {
for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it) {
UserTextIdentificationFrame *f = dynamic_cast<UserTextIdentificationFrame *>(*it);
if(f && f->description() == description)
return f;

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