715 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
279 changed files with 14463 additions and 3827 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)
@@ -47,7 +53,7 @@ if (MSVC AND ENABLE_STATIC_RUNTIME)
endif()
set(TAGLIB_LIB_MAJOR_VERSION "1")
set(TAGLIB_LIB_MINOR_VERSION "8")
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}")
@@ -56,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 12)
set(TAGLIB_SOVERSION_CURRENT 16)
set(TAGLIB_SOVERSION_REVISION 0)
set(TAGLIB_SOVERSION_AGE 11)
set(TAGLIB_SOVERSION_AGE 15)
math(EXPR TAGLIB_SOVERSION_MAJOR "${TAGLIB_SOVERSION_CURRENT} - ${TAGLIB_SOVERSION_AGE}")
math(EXPR TAGLIB_SOVERSION_MINOR "${TAGLIB_SOVERSION_AGE}")
@@ -66,25 +72,42 @@ 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)
@@ -94,7 +117,7 @@ if(BUILD_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)
@@ -104,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()

101
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
@@ -46,15 +46,104 @@ the include folder to the project's User Header Search Paths.
Windows
-------
For building a static library on Windows with Visual Studio 2010, cd to
the TagLib folder then:
It's Windows ... Systems vary!
This means you need to adjust things to suit your system, especially paths.
cmake -DENABLE_STATIC=ON -DENABLE_STATIC_RUNTIME=ON -G "Visual Studio 10" ...
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.
CMake will create a Visual Studio solution, taglib.sln that you can open and
build as normal.
Unit Tests
----------

96
NEWS
View File

@@ -1,5 +1,97 @@
TagLib 1.8 BETA (Jul 14, 2012)
==============================
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.

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,12 @@ 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)
@@ -237,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

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
@@ -49,6 +52,8 @@ set(tag_HDRS
toolkit/tmap.h
toolkit/tmap.tcc
toolkit/tpropertymap.h
toolkit/trefcounter.h
toolkit/tdebuglistener.h
mpeg/mpegfile.h
mpeg/mpegproperties.h
mpeg/mpegheader.h
@@ -64,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
@@ -82,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
@@ -102,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
@@ -150,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
@@ -217,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
@@ -242,6 +265,7 @@ set(aiff_SRCS
set(wav_SRCS
riff/wav/wavfile.cpp
riff/wav/wavproperties.cpp
riff/wav/infotag.cpp
)
set(mod_SRCS
@@ -277,14 +301,33 @@ set(toolkit_SRCS
toolkit/tfilestream.cpp
toolkit/tdebug.cpp
toolkit/tpropertymap.cpp
toolkit/unicode.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
@@ -294,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
@@ -310,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,7 @@
#include <tdebug.h>
#include <tagunion.h>
#include <id3v1tag.h>
#include <id3v2header.h>
#include <tpropertymap.h>
#include "apefile.h"
@@ -47,7 +48,7 @@ using namespace TagLib;
namespace
{
enum { ApeAPEIndex, ApeID3v1Index };
enum { ApeAPEIndex = 0, ApeID3v1Index = 1 };
}
class APE::File::FilePrivate
@@ -57,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;
}
@@ -71,6 +77,10 @@ public:
long ID3v1Location;
ID3v2::Header *ID3v2Header;
long ID3v2Location;
uint ID3v2Size;
TagUnion tag;
Properties *properties;
@@ -80,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()
@@ -129,12 +142,9 @@ void APE::File::removeUnsupportedProperties(const StringList &properties)
PropertyMap APE::File::setProperties(const PropertyMap &properties)
{
if(d->hasAPE)
return d->tag.access<APE::Tag>(ApeAPEIndex, false)->setProperties(properties);
else if(d->hasID3v1)
return d->tag.access<ID3v1::Tag>(ApeID3v1Index, false)->setProperties(properties);
else
return d->tag.access<APE::Tag>(ApeAPEIndex, true)->setProperties(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
@@ -236,12 +246,33 @@ void APE::File::strip(int tags)
}
}
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();
@@ -268,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);
}
}
@@ -303,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);
@@ -125,10 +130,11 @@ namespace TagLib {
/*!
* Implements the unified property interface -- import function.
* As for the export, only one tag is taken into account. If the file
* has no tag at all, APE will be created.
* 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.
@@ -140,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);
@@ -180,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

@@ -177,19 +177,19 @@ void APE::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];

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

@@ -125,6 +125,7 @@ void APE::Item::setBinaryData(const ByteVector &value)
{
d->type = Binary;
d->value = value;
d->text.clear();
}
ByteVector APE::Item::value() const
@@ -137,31 +138,35 @@ 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->type = Text;
d->text = value;
d->type = Text;
d->text = value;
d->value.clear();
}
void APE::Item::setValues(const StringList &value)
{
d->type = Text;
d->text = value;
d->type = Text;
d->text = value;
d->value.clear();
}
void APE::Item::appendValue(const String &value)
{
d->type = Text;
d->text.append(value);
d->type = Text;
d->text.append(value);
d->value.clear();
}
void APE::Item::appendValues(const StringList &values)
{
d->type = Text;
d->text.append(values);
d->type = Text;
d->text.append(values);
d->value.clear();
}
int APE::Item::size() const
@@ -200,7 +205,10 @@ 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
@@ -229,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(Text == d->type)
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

@@ -97,7 +97,7 @@ namespace TagLib {
/*!
* Returns the binary value.
* If the item type is not \a Binary, the returned contents are undefined
* If the item type is not \a Binary, always returns an empty ByteVector.
*/
ByteVector binaryData() const;
@@ -152,8 +152,9 @@ 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;
@@ -163,7 +164,8 @@ namespace TagLib {
#endif
/*!
* Returns the list of text 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,22 +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),
sampleFrames(0),
file(file),
streamLength(streamLength) {}
sampleFrames(0) {}
int length;
int bitrate;
@@ -57,18 +57,24 @@ public:
int version;
int bitsPerSample;
uint sampleFrames;
File *file;
long streamLength;
};
////////////////////////////////////////////////////////////////////////////////
// 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()
@@ -77,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;
}
@@ -115,105 +131,100 @@ TagLib::uint APE::Properties::sampleFrames() const
// 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);
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);
d->sampleFrames = totalFrames > 0 ? (totalFrames - 1) * blocksPerFrame + finalFrameBlocks : 0;
d->length = d->sampleRate > 0 ? d->sampleFrames / d->sampleRate : 0;
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;
@@ -221,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,26 +51,73 @@ 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;
/*!
@@ -82,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

@@ -46,11 +46,12 @@ using namespace APE;
class APE::Tag::TagPrivate
{
public:
TagPrivate() : file(0), footerLocation(-1), tagLength(0) {}
TagPrivate() :
file(0),
footerLocation(-1) {}
TagLib::File *file;
long footerLocation;
long tagLength;
Footer footer;
@@ -61,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(TagLib::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;
@@ -89,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
@@ -189,7 +192,7 @@ PropertyMap APE::Tag::properties() const
PropertyMap properties;
ItemListMap::ConstIterator it = itemListMap().begin();
for(; it != itemListMap().end(); ++it) {
String tagName = PropertyMap::prepareKey(it->first);
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())
@@ -227,20 +230,23 @@ PropertyMap APE::Tag::setProperties(const PropertyMap &origProps)
StringList toRemove;
ItemListMap::ConstIterator remIt = itemListMap().begin();
for(; remIt != itemListMap().end(); ++remIt) {
String key = PropertyMap::prepareKey(remIt->first);
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::Iterator removeIt = toRemove.begin(); removeIt != toRemove.end(); removeIt++)
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(!(itemListMap().contains(tagName)) || !(itemListMap()[tagName].values() == it->second)) {
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 {
@@ -252,7 +258,21 @@ PropertyMap APE::Tag::setProperties(const PropertyMap &origProps)
}
}
}
return PropertyMap();
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
@@ -267,9 +287,7 @@ 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)
@@ -351,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

@@ -123,10 +123,17 @@ namespace TagLib {
/*!
* Implements the unified tag dictionary interface -- import function. The same
* comments as for the export function apply.
* 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.
*/
@@ -136,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.

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

@@ -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,188 +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;
~HeaderExtensionObject();
ByteVector guid();
List<ASF::File::FilePrivate::BaseObject *> objects;
HeaderExtensionObject();
ByteVector guid() const;
void parse(ASF::File *file, uint size);
ByteVector render(ASF::File *file);
};
ASF::File::HeaderExtensionObject::~HeaderExtensionObject()
class ASF::File::FilePrivate::CodecListObject : public ASF::File::FilePrivate::BaseObject
{
for(unsigned int i = 0; i < objects.size(); i++) {
delete objects[i];
}
}
public:
ByteVector guid() const;
void parse(ASF::File *file, uint size);
void ASF::File::BaseObject::parse(ASF::File *file, unsigned int 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));
@@ -243,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);
@@ -259,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));
@@ -267,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);
@@ -283,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));
@@ -291,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);
@@ -307,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));
@@ -315,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);
@@ -333,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;
@@ -348,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;
}
@@ -401,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()) {
@@ -487,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;
}
@@ -531,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,15 +23,14 @@
* 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;
@@ -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,8 +205,8 @@ namespace TagLib
/* THIS IS PRIVATE, DON'T TOUCH IT! */
void parse(const ByteVector& );
static Picture fromInvalid();
friend class Attribute;
#endif
private:
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;
}
@@ -79,6 +97,26 @@ 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
{
return d->encrypted;
@@ -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

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

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

@@ -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"
@@ -217,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")
@@ -252,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 == "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

@@ -60,7 +60,6 @@ public:
properties(0),
flacStart(0),
streamStart(0),
streamLength(0),
scanned(false),
hasXiphComment(false),
hasID3v2(false),
@@ -70,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;
@@ -85,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;
@@ -103,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()
@@ -164,14 +164,7 @@ void FLAC::File::removeUnsupportedProperties(const StringList &unsupported)
PropertyMap FLAC::File::setProperties(const PropertyMap &properties)
{
if(d->hasXiphComment)
return d->tag.access<Ogg::XiphComment>(FlacXiphIndex, false)->setProperties(properties);
else if(d->hasID3v2)
return d->tag.access<ID3v2::Tag>(FlacID3v2Index, false)->setProperties(properties);
else if(d->hasID3v1)
return d->tag.access<ID3v1::Tag>(FlacID3v1Index, false)->setProperties(properties);
else
return d->tag.access<Ogg::XiphComment>(FlacXiphIndex, true)->setProperties(properties);
return d->tag.access<Ogg::XiphComment>(FlacXiphIndex, true)->setProperties(properties);
}
FLAC::Properties *FLAC::File::audioProperties() const
@@ -179,7 +172,6 @@ FLAC::Properties *FLAC::File::audioProperties() const
return d->properties;
}
bool FLAC::File::save()
{
if(readOnly()) {
@@ -238,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
@@ -266,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;
@@ -297,219 +297,16 @@ void FLAC::File::setID3v2FrameFactory(const ID3v2::FrameFactory *factory)
d->ID3v2FrameFactory = factory;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void FLAC::File::read(bool readProperties, Properties::ReadStyle propertiesStyle)
{
// Look for an ID3v2 tag
d->ID3v2Location = findID3v2();
if(d->ID3v2Location >= 0) {
d->tag.set(FlacID3v2Index, new ID3v2::Tag(this, d->ID3v2Location, d->ID3v2FrameFactory));
d->ID3v2OriginalSize = ID3v2Tag()->header()->completeTagSize();
if(ID3v2Tag()->header()->tagSize() <= 0)
d->tag.set(FlacID3v2Index, 0);
else
d->hasID3v2 = true;
}
// Look for an ID3v1 tag
d->ID3v1Location = findID3v1();
if(d->ID3v1Location >= 0) {
d->tag.set(FlacID3v1Index, new ID3v1::Tag(this, d->ID3v1Location));
d->hasID3v1 = true;
}
// Look for FLAC metadata, including vorbis comments
scan();
if(!isValid())
return;
if(d->hasXiphComment)
d->tag.set(FlacXiphIndex, new Ogg::XiphComment(xiphCommentData()));
else
d->tag.set(FlacXiphIndex, new Ogg::XiphComment);
if(readProperties)
d->properties = new Properties(streamInfoData(), streamLength(), propertiesStyle);
}
ByteVector FLAC::File::streamInfoData()
{
return isValid() ? d->streamInfoData : ByteVector();
}
ByteVector FLAC::File::xiphCommentData() const
{
return (isValid() && d->hasXiphComment) ? d->xiphCommentData : ByteVector();
debug("FLAC::File::streamInfoData() -- This function is obsolete. Returning an empty ByteVector.");
return ByteVector();
}
long FLAC::File::streamLength()
{
return d->streamLength;
}
void FLAC::File::scan()
{
// Scan the metadata pages
if(d->scanned)
return;
if(!isValid())
return;
long nextBlockOffset;
if(d->hasID3v2)
nextBlockOffset = find("fLaC", d->ID3v2Location + d->ID3v2OriginalSize);
else
nextBlockOffset = find("fLaC");
if(nextBlockOffset < 0) {
debug("FLAC::File::scan() -- FLAC stream not found");
setValid(false);
return;
}
nextBlockOffset += 4;
d->flacStart = nextBlockOffset;
seek(nextBlockOffset);
ByteVector header = readBlock(4);
// Header format (from spec):
// <1> Last-metadata-block flag
// <7> BLOCK_TYPE
// 0 : STREAMINFO
// 1 : PADDING
// ..
// 4 : VORBIS_COMMENT
// ..
// <24> Length of metadata to follow
char blockType = header[0] & 0x7f;
bool isLastBlock = (header[0] & 0x80) != 0;
uint length = header.mid(1, 3).toUInt();
// First block should be the stream_info metadata
if(blockType != MetadataBlock::StreamInfo) {
debug("FLAC::File::scan() -- invalid FLAC stream");
setValid(false);
return;
}
d->streamInfoData = readBlock(length);
d->blocks.append(new UnknownMetadataBlock(blockType, d->streamInfoData));
nextBlockOffset += length + 4;
// Search through the remaining metadata
while(!isLastBlock) {
header = readBlock(4);
blockType = header[0] & 0x7f;
isLastBlock = (header[0] & 0x80) != 0;
length = header.mid(1, 3).toUInt();
ByteVector data = readBlock(length);
if(data.size() != length) {
debug("FLAC::File::scan() -- FLAC stream corrupted");
setValid(false);
return;
}
MetadataBlock *block = 0;
// Found the vorbis-comment
if(blockType == MetadataBlock::VorbisComment) {
if(!d->hasXiphComment) {
d->xiphCommentData = data;
d->hasXiphComment = true;
}
else {
debug("FLAC::File::scan() -- multiple Vorbis Comment blocks found, using the first one");
}
}
else if(blockType == MetadataBlock::Picture) {
FLAC::Picture *picture = new FLAC::Picture();
if(picture->parse(data)) {
block = picture;
}
else {
debug("FLAC::File::scan() -- invalid picture found, discarting");
delete picture;
}
}
if(!block) {
block = new UnknownMetadataBlock(blockType, data);
}
if(block->code() != MetadataBlock::Padding) {
d->blocks.append(block);
}
else {
delete block;
}
nextBlockOffset += length + 4;
if(nextBlockOffset >= File::length()) {
debug("FLAC::File::scan() -- FLAC stream corrupted");
setValid(false);
return;
}
seek(nextBlockOffset);
}
// End of metadata, now comes the datastream
d->streamStart = nextBlockOffset;
d->streamLength = File::length() - d->streamStart;
if(d->hasID3v1)
d->streamLength -= 128;
d->scanned = true;
}
long FLAC::File::findID3v1()
{
if(!isValid())
return -1;
seek(-128, End);
long p = tell();
if(readBlock(3) == ID3v1::Tag::fileIdentifier())
return p;
return -1;
}
long FLAC::File::findID3v2()
{
if(!isValid())
return -1;
seek(0);
if(readBlock(3) == ID3v2::Header::fileIdentifier())
return 0;
return -1;
debug("FLAC::File::streamLength() -- This function is obsolete. Returning zero.");
return 0;
}
List<FLAC::Picture *> FLAC::File::pictureList()
@@ -555,3 +352,230 @@ void FLAC::File::removePictures()
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)
{
// Look for an ID3v2 tag
d->ID3v2Location = findID3v2();
if(d->ID3v2Location >= 0) {
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(FlacID3v2Index, 0);
else
d->hasID3v2 = true;
}
// Look for an ID3v1 tag
d->ID3v1Location = findID3v1();
if(d->ID3v1Location >= 0) {
d->tag.set(FlacID3v1Index, new ID3v1::Tag(this, d->ID3v1Location));
d->hasID3v1 = true;
}
// Look for FLAC metadata, including vorbis comments
scan();
if(!isValid())
return;
if(d->hasXiphComment)
d->tag.set(FlacXiphIndex, new Ogg::XiphComment(d->xiphCommentData));
else
d->tag.set(FlacXiphIndex, new Ogg::XiphComment);
if(readProperties) {
// First block should be the stream_info metadata
const ByteVector infoData = d->blocks.front()->render();
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()
{
// Scan the metadata pages
if(d->scanned)
return;
if(!isValid())
return;
long nextBlockOffset;
if(d->hasID3v2)
nextBlockOffset = find("fLaC", d->ID3v2Location + d->ID3v2OriginalSize);
else
nextBlockOffset = find("fLaC");
if(nextBlockOffset < 0) {
debug("FLAC::File::scan() -- FLAC stream not found");
setValid(false);
return;
}
nextBlockOffset += 4;
d->flacStart = nextBlockOffset;
seek(nextBlockOffset);
ByteVector header = readBlock(4);
// Header format (from spec):
// <1> Last-metadata-block flag
// <7> BLOCK_TYPE
// 0 : STREAMINFO
// 1 : PADDING
// ..
// 4 : VORBIS_COMMENT
// ..
// <24> Length of metadata to follow
char blockType = header[0] & 0x7f;
bool isLastBlock = (header[0] & 0x80) != 0;
uint length = header.toUInt(1U, 3U);
// First block should be the stream_info metadata
if(blockType != MetadataBlock::StreamInfo) {
debug("FLAC::File::scan() -- invalid FLAC stream");
setValid(false);
return;
}
d->blocks.append(new UnknownMetadataBlock(blockType, readBlock(length)));
nextBlockOffset += length + 4;
// Search through the remaining metadata
while(!isLastBlock) {
header = readBlock(4);
blockType = header[0] & 0x7f;
isLastBlock = (header[0] & 0x80) != 0;
length = header.toUInt(1U, 3U);
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() -- Failed to read a metadata block");
setValid(false);
return;
}
MetadataBlock *block = 0;
// Found the vorbis-comment
if(blockType == MetadataBlock::VorbisComment) {
if(!d->hasXiphComment) {
d->xiphCommentData = data;
d->hasXiphComment = true;
}
else {
debug("FLAC::File::scan() -- multiple Vorbis Comment blocks found, using the first one");
}
}
else if(blockType == MetadataBlock::Picture) {
FLAC::Picture *picture = new FLAC::Picture();
if(picture->parse(data)) {
block = picture;
}
else {
debug("FLAC::File::scan() -- invalid picture found, discarding");
delete picture;
}
}
if(!block) {
block = new UnknownMetadataBlock(blockType, data);
}
if(block->code() != MetadataBlock::Padding) {
d->blocks.append(block);
}
else {
delete block;
}
nextBlockOffset += length + 4;
if(nextBlockOffset >= File::length()) {
debug("FLAC::File::scan() -- FLAC stream corrupted");
setValid(false);
return;
}
seek(nextBlockOffset);
}
// End of metadata, now comes the datastream
d->streamStart = nextBlockOffset;
d->scanned = true;
}
long FLAC::File::findID3v1()
{
if(!isValid())
return -1;
seek(-128, End);
long p = tell();
if(readBlock(3) == ID3v1::Tag::fileIdentifier())
return p;
return -1;
}
long FLAC::File::findID3v2()
{
if(!isValid())
return -1;
seek(0);
if(readBlock(3) == ID3v2::Header::fileIdentifier())
return 0;
return -1;
}

View File

@@ -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,
@@ -130,8 +136,10 @@ namespace TagLib {
/*!
* Implements the unified property interface -- import function.
* As with the export, only one tag is taken into account. If the file
* has no tag at all, a XiphComment will be created.
* 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 &);
@@ -147,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);
@@ -195,6 +224,7 @@ namespace TagLib {
* when
*
* \see ID3v2FrameFactory
* \deprecated This value should be passed in via the constructor
*/
void setID3v2FrameFactory(const ID3v2::FrameFactory *factory);
@@ -202,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
@@ -210,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
@@ -238,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,10 +23,6 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <taglib.h>
#include <tdebug.h>
#include "flacmetadatablock.h"

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 "flacpicture.h"
@@ -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.");

View File

@@ -34,24 +34,18 @@ 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),
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;
@@ -61,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()
@@ -79,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;
}
@@ -93,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
@@ -117,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;
@@ -138,32 +149,28 @@ void FLAC::Properties::read()
// Maximum frame size (in bytes)
pos += 3;
uint flags = d->data.mid(pos, 4).toUInt(true);
const uint flags = data.toUInt(pos, true);
pos += 4;
d->sampleRate = flags >> 12;
d->channels = ((flags >> 9) & 7) + 1;
d->sampleWidth = ((flags >> 4) & 31) + 1;
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)
unsigned long long hi = flags & 0xf;
unsigned long long lo = d->data.mid(pos, 4).toUInt(true);
const ulonglong hi = flags & 0xf;
const ulonglong lo = data.toUInt(pos, true);
pos += 4;
d->sampleFrames = (hi << 32) | lo;
if(d->sampleRate > 0)
d->length = int(d->sampleFrames / d->sampleRate);
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);
}
// Uncompressed bitrate:
//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,27 +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
* 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;
@@ -92,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>

View File

@@ -45,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,
@@ -53,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()
@@ -128,7 +130,7 @@ bool IT::File::save()
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);

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);

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

@@ -51,10 +51,12 @@ 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;

View File

@@ -45,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,
@@ -53,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()

View File

@@ -37,18 +37,25 @@ namespace TagLib {
{
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.
* 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.
* 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 =

View File

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

@@ -35,12 +35,14 @@ 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;
uint instrumentCount() const;
uint instrumentCount() const;
uchar lengthInPatterns() const;
void setChannels(int channels);

View File

@@ -158,7 +158,7 @@ PropertyMap Mod::Tag::setProperties(const PropertyMap &origProps)
// for each tag that has been set above, remove the first entry in the corresponding
// value list. The others will be returned as unsupported by this format.
for(StringList::Iterator it = oneValueSet.begin(); it != oneValueSet.end(); ++it) {
for(StringList::ConstIterator it = oneValueSet.begin(); it != oneValueSet.end(); ++it) {
if(properties[*it].size() == 1)
properties.erase(*it);
else

View File

@@ -97,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.
*/
@@ -126,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.
*/
@@ -169,7 +169,7 @@ namespace TagLib {
* 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
* returened. Additionally, if the map contains tags with multiple values,
* returned. Additionally, if the map contains tags with multiple values,
* all but the first will be contained in the returned map of unsupported
* properties.
*/

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

@@ -59,7 +59,7 @@ namespace TagLib {
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 ingteger
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

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

@@ -42,10 +42,11 @@ namespace TagLib {
* This describes the image type.
*/
enum Format {
JPEG = TypeJPEG,
PNG = TypePNG,
BMP = TypeBMP,
GIF = TypeGIF
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;

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,110 +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);
uint version = data[8];
if(version == 1) {
if (data.size() < 36 + 8) {
debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected");
return;
}
long long unit = data.mid(28, 8).toLongLong();
long long length = data.mid(36, 8).toLongLong();
d->length = unit ? int(length / unit) : 0;
}
else {
if (data.size() < 24 + 4) {
debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected");
return;
}
unsigned int unit = data.mid(20, 4).toUInt();
unsigned int length = data.mid(24, 4).toUInt();
d->length = unit ? length / unit : 0;
}
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()
@@ -171,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;
}
@@ -193,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

@@ -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,36 +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" ||
atom->name == "hdvd") {
parseBool(atom, file);
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, file);
parseUInt(atom);
}
else if(atom->name == "plID") {
parseLongLong(atom, file);
parseLongLong(atom);
}
else if(atom->name == "stik" || atom->name == "rtng" || atom->name == "akID") {
parseByte(atom, file);
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);
}
}
}
@@ -106,16 +103,21 @@ MP4::Tag::~Tag()
}
MP4::AtomDataList
MP4::Tag::parseData2(MP4::Atom *atom, TagLib::File *file, int expectedFlags, bool freeForm)
MP4::Tag::parseData2(const MP4::Atom *atom, int expectedFlags, bool freeForm)
{
AtomDataList result;
ByteVector data = file->readBlock(atom->length - 8);
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\"");
@@ -143,9 +145,9 @@ MP4::Tag::parseData2(MP4::Atom *atom, TagLib::File *file, int expectedFlags, boo
}
ByteVectorList
MP4::Tag::parseData(MP4::Atom *atom, TagLib::File *file, int expectedFlags, bool freeForm)
MP4::Tag::parseData(const MP4::Atom *atom, int expectedFlags, bool freeForm)
{
AtomDataList data = parseData2(atom, file, expectedFlags, freeForm);
AtomDataList data = parseData2(atom, expectedFlags, freeForm);
ByteVectorList result;
for(uint i = 0; i < data.size(); i++) {
result.append(data[i].data);
@@ -154,91 +156,91 @@ MP4::Tag::parseData(MP4::Atom *atom, TagLib::File *file, int expectedFlags, bool
}
void
MP4::Tag::parseInt(MP4::Atom *atom, TagLib::File *file)
MP4::Tag::parseInt(const MP4::Atom *atom)
{
ByteVectorList data = parseData(atom, file);
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::parseUInt(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()) {
d->items.insert(atom->name, data[0].toUInt());
addItem(atom->name, data[0].toUInt());
}
}
void
MP4::Tag::parseLongLong(MP4::Atom *atom, TagLib::File *file)
MP4::Tag::parseLongLong(const MP4::Atom *atom)
{
ByteVectorList data = parseData(atom, file);
ByteVectorList data = parseData(atom);
if(data.size()) {
d->items.insert(atom->name, data[0].toLongLong());
addItem(atom->name, data[0].toLongLong());
}
}
void
MP4::Tag::parseByte(MP4::Atom *atom, TagLib::File *file)
MP4::Tag::parseByte(const MP4::Atom *atom)
{
ByteVectorList data = parseData(atom, file);
ByteVectorList data = parseData(atom);
if(data.size()) {
d->items.insert(atom->name, (uchar)data[0].at(0));
addItem(atom->name, (uchar)data[0].at(0));
}
}
void
MP4::Tag::parseGnre(MP4::Atom *atom, TagLib::File *file)
MP4::Tag::parseGnre(const MP4::Atom *atom)
{
ByteVectorList data = parseData(atom, file);
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)
{
AtomDataList data = parseData2(atom, file, -1, true);
AtomDataList data = parseData2(atom, -1, true);
if(data.size() > 2) {
String name = "----:" + String(data[0].data, String::UTF8) + ':' + String(data[1].data, String::UTF8);
AtomDataType type = data[2].type;
@@ -255,7 +257,7 @@ MP4::Tag::parseFreeForm(MP4::Atom *atom, TagLib::File *file)
}
Item item(value);
item.setAtomDataType(type);
d->items.insert(name, item);
addItem(name, item);
}
else {
ByteVectorList value;
@@ -264,52 +266,61 @@ MP4::Tag::parseFreeForm(MP4::Atom *atom, TagLib::File *file)
}
Item item(value);
item.setAtomDataType(type);
d->items.insert(name, item);
addItem(name, item);
}
}
}
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 == TypeJPEG || flags == TypePNG || flags == TypeBMP || flags == TypeGIF) {
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++) {
@@ -319,7 +330,7 @@ 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'));
@@ -327,7 +338,7 @@ MP4::Tag::renderBool(const ByteVector &name, MP4::Item &item)
}
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()));
@@ -335,7 +346,7 @@ MP4::Tag::renderInt(const ByteVector &name, MP4::Item &item)
}
ByteVector
MP4::Tag::renderUInt(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()));
@@ -343,7 +354,7 @@ MP4::Tag::renderUInt(const ByteVector &name, MP4::Item &item)
}
ByteVector
MP4::Tag::renderLongLong(const ByteVector &name, MP4::Item &item)
MP4::Tag::renderLongLong(const ByteVector &name, const MP4::Item &item) const
{
ByteVectorList data;
data.append(ByteVector::fromLongLong(item.toLongLong()));
@@ -351,7 +362,7 @@ MP4::Tag::renderLongLong(const ByteVector &name, MP4::Item &item)
}
ByteVector
MP4::Tag::renderByte(const ByteVector &name, MP4::Item &item)
MP4::Tag::renderByte(const ByteVector &name, const MP4::Item &item) const
{
ByteVectorList data;
data.append(ByteVector(1, item.toByte()));
@@ -359,7 +370,7 @@ MP4::Tag::renderByte(const ByteVector &name, MP4::Item &item)
}
ByteVector
MP4::Tag::renderIntPair(const ByteVector &name, MP4::Item &item)
MP4::Tag::renderIntPair(const ByteVector &name, const MP4::Item &item) const
{
ByteVectorList data;
data.append(ByteVector(2, '\0') +
@@ -370,7 +381,7 @@ MP4::Tag::renderIntPair(const ByteVector &name, MP4::Item &item)
}
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') +
@@ -380,7 +391,7 @@ MP4::Tag::renderIntPairNoTrailing(const ByteVector &name, MP4::Item &item)
}
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();
@@ -391,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();
@@ -403,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) {
@@ -441,38 +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" || name == "hdvd") {
data.append(renderBool(name.data(String::Latin1), i->second));
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), i->second));
data.append(renderUInt(name.data(String::Latin1), it->second));
}
else if(name == "plID") {
data.append(renderLongLong(name.data(String::Latin1), i->second));
data.append(renderLongLong(name.data(String::Latin1), it->second));
}
else if(name == "stik" || name == "rtng" || name == "akID") {
data.append(renderByte(name.data(String::Latin1), i->second));
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 + "\"");
@@ -492,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);
@@ -526,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;
}
@@ -547,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;
}
@@ -570,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;
}
@@ -585,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");
@@ -605,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") {
@@ -625,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;
@@ -750,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

@@ -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,41 +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:
AtomDataList parseData2(Atom *atom, TagLib::File *file, int expectedFlags = -1, bool freeForm = false);
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 parseByte(Atom *atom, TagLib::File *file);
void parseUInt(Atom *atom, TagLib::File *file);
void parseLongLong(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 = TypeUTF8);
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 renderByte(const ByteVector &name, Item &item);
TagLib::ByteVector renderUInt(const ByteVector &name, Item &item);
TagLib::ByteVector renderLongLong(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

@@ -39,7 +39,7 @@ using namespace TagLib;
namespace
{
enum { MPCAPEIndex, MPCID3v1Index };
enum { MPCAPEIndex = 0, MPCID3v1Index = 1 };
}
class MPC::File::FilePrivate
@@ -53,7 +53,6 @@ public:
ID3v2Location(-1),
ID3v2Size(0),
properties(0),
scanned(false),
hasAPE(false),
hasID3v1(false),
hasID3v2(false) {}
@@ -76,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.
@@ -90,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()
@@ -133,15 +133,11 @@ void MPC::File::removeUnsupportedProperties(const StringList &properties)
PropertyMap MPC::File::setProperties(const PropertyMap &properties)
{
if(d->hasAPE)
return d->tag.access<APE::Tag>(MPCAPEIndex, false)->setProperties(properties);
else if(d->hasID3v1)
return d->tag.access<ID3v1::Tag>(MPCID3v1Index, false)->setProperties(properties);
else
return d->tag.access<APE::Tag>(APE, true)->setProperties(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;
@@ -258,12 +254,21 @@ 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
@@ -276,8 +281,6 @@ void MPC::File::read(bool readProperties, Properties::ReadStyle /* propertiesSty
// Look for an APE tag
findAPE();
d->APELocation = findAPE();
if(d->APELocation >= 0) {
@@ -291,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();
@@ -302,15 +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(this, 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

@@ -84,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);
@@ -121,8 +126,8 @@ namespace TagLib {
/*!
* Implements the unified property interface -- import function.
* As with the export, only one tag is taken into account. If the file
* has no tag at all, an APE tag will be created.
* 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 &);
@@ -134,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);
@@ -182,12 +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

@@ -36,9 +36,7 @@ using namespace TagLib;
class MPC::Properties::PropertiesPrivate
{
public:
PropertiesPrivate(long length, ReadStyle s) :
streamLength(length),
style(s),
PropertiesPrivate() :
version(0),
length(0),
bitrate(0),
@@ -51,8 +49,6 @@ public:
albumGain(0),
albumPeak(0) {}
long streamLength;
ReadStyle style;
int version;
int length;
int bitrate;
@@ -71,23 +67,25 @@ public:
// 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(streamLength, style);
readSV7(data);
readSV7(data, streamLength);
}
MPC::Properties::Properties(File *file, long streamLength, ReadStyle style) : AudioProperties(style)
MPC::Properties::Properties(File *file, long streamLength, ReadStyle style) :
AudioProperties(style),
d(new PropertiesPrivate())
{
d = new PropertiesPrivate(streamLength, style);
ByteVector magic = file->readBlock(4);
if(magic == "MPCK") {
// Musepack version 8
readSV8(file);
readSV8(file, streamLength);
}
else {
// Musepack version 7 or older, fixed size header
readSV7(magic + file->readBlock(MPC::HeaderSize - 4));
readSV7(magic + file->readBlock(MPC::HeaderSize - 4), streamLength);
}
}
@@ -97,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;
}
@@ -155,83 +163,126 @@ int MPC::Properties::albumPeak() const
// private members
////////////////////////////////////////////////////////////////////////////////
unsigned long readSize(File *file, TagLib::uint &sizelength)
unsigned long readSize(File *file, TagLib::uint &sizeLength, bool &eof)
{
sizeLength = 0;
eof = false;
unsigned char tmp;
unsigned long size = 0;
do {
ByteVector b = file->readBlock(1);
const ByteVector b = file->readBlock(1);
if(b.isEmpty()) {
eof = true;
break;
}
tmp = b[0];
size = (size << 7) | (tmp & 0x7F);
sizelength++;
sizeLength++;
} while((tmp & 0x80));
return size;
}
unsigned long readSize(const ByteVector &data, TagLib::uint &sizelength)
unsigned long readSize(const ByteVector &data, TagLib::uint &pos)
{
unsigned char tmp;
unsigned long size = 0;
unsigned long pos = 0;
do {
tmp = data[pos++];
size = (size << 7) | (tmp & 0x7F);
sizelength++;
} while((tmp & 0x80) && (pos < data.size()));
return size;
}
static const unsigned short sftable [4] = { 44100, 48000, 37800, 32000 };
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)
void MPC::Properties::readSV8(File *file, long streamLength)
{
bool readSH = false, readRG = false;
while(!readSH && !readRG) {
ByteVector packetType = file->readBlock(2);
uint packetSizeLength = 0;
unsigned long packetSize = readSize(file, packetSizeLength);
unsigned long dataSize = packetSize - 2 - packetSizeLength;
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
ByteVector data = file->readBlock(dataSize);
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.mid(pos), pos);
ulong begSilence = readSize(data.mid(pos), pos);
d->sampleFrames = readSize(data, pos);
if(pos > dataSize - 3) {
debug("MPC::Properties::readSV8() - \"SH\" packet is corrupt.");
break;
}
std::bitset<16> flags(TAGLIB_CONSTRUCT_BITSET(data.mid(pos, 2).toUShort(true)));
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[15] * 4 + flags[14] * 2 + flags[13]];
d->channels = flags[7] * 8 + flags[6] * 4 + flags[5] * 2 + flags[4] + 1;
d->sampleRate = sftable[(flags >> 13) & 0x07];
d->channels = ((flags >> 4) & 0x0F) + 1;
if((d->sampleFrames - begSilence) != 0)
d->bitrate = d->streamLength * 8.0 * d->sampleRate / (d->sampleFrames - begSilence);
d->bitrate = d->bitrate / 1000;
d->length = (d->sampleFrames - begSilence) / d->sampleRate;
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
ByteVector data = file->readBlock(dataSize);
if(dataSize <= 9) {
debug("MPC::Properties::readSV8() - \"RG\" packet is too short to parse.");
break;
}
readRG = true;
int replayGainVersion = data[0];
const int replayGainVersion = data[0];
if(replayGainVersion == 1) {
d->trackGain = data.mid(1, 2).toUInt(true);
d->trackPeak = data.mid(3, 2).toUInt(true);
d->albumGain = data.mid(5, 2).toUInt(true);
d->albumPeak = data.mid(7, 2).toUInt(true);
d->trackGain = data.toShort(1, true);
d->trackPeak = data.toShort(3, true);
d->albumGain = data.toShort(5, true);
d->albumPeak = data.toShort(7, true);
}
}
@@ -245,25 +296,25 @@ void MPC::Properties::readSV8(File *file)
}
}
void MPC::Properties::readSV7(const ByteVector &data)
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.mid(4, 4).toUInt(false);
d->totalFrames = data.toUInt(4, false);
std::bitset<32> flags(TAGLIB_CONSTRUCT_BITSET(data.mid(8, 4).toUInt(false)));
d->sampleRate = sftable[flags[17] * 2 + flags[16]];
d->channels = 2;
const uint flags = data.toUInt(8, false);
d->sampleRate = sftable[(flags >> 16) & 0x03];
d->channels = 2;
uint gapless = data.mid(5, 4).toUInt(false);
const uint gapless = data.toUInt(5, false);
d->trackGain = data.mid(14,2).toShort(false);
d->trackPeak = data.mid(12,2).toUInt(false);
d->albumGain = data.mid(18,2).toShort(false);
d->albumPeak = data.mid(16,2).toUInt(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) {
@@ -279,10 +330,10 @@ void MPC::Properties::readSV7(const ByteVector &data)
}
if (d->trackPeak != 0)
d->trackPeak = (int)(log10(d->trackPeak) * 20 * 256 + .5);
d->trackPeak = (int)(log10((double)d->trackPeak) * 20 * 256 + .5);
if (d->albumPeak != 0)
d->albumPeak = (int)(log10(d->albumPeak) * 20 * 256 + .5);
d->albumPeak = (int)(log10((double)d->albumPeak) * 20 * 256 + .5);
bool trueGapless = (gapless >> 31) & 0x0001;
if(trueGapless) {
@@ -293,24 +344,26 @@ void MPC::Properties::readSV7(const ByteVector &data)
d->sampleFrames = d->totalFrames * 1152 - 576;
}
else {
uint headerData = 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)
d->totalFrames = data.mid(4, 4).toUInt(false);
d->totalFrames = data.toUInt(4, false);
else
d->totalFrames = data.mid(6, 2).toUInt(false);
d->totalFrames = data.toUShort(6, false);
d->sampleFrames = d->totalFrames * 1152 - 576;
}
d->length = d->sampleRate > 0 ? (d->sampleFrames + (d->sampleRate / 2)) / d->sampleRate : 0;
if(d->sampleFrames > 0 && d->sampleRate > 0) {
const double length = d->sampleFrames * 1000.0 / d->sampleRate;
d->length = static_cast<int>(length + 0.5);
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

@@ -66,17 +66,53 @@ 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 version of the bitstream (SV4-SV8)
*/
int mpcVersion() const;
uint totalFrames() const;
uint sampleFrames() const;
@@ -110,8 +146,8 @@ namespace TagLib {
Properties(const Properties &);
Properties &operator=(const Properties &);
void readSV7(const ByteVector &data);
void readSV8(File *file);
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

@@ -182,22 +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)
{
if(TagPrivate::stringHandler != &defaultStringHandler)
delete TagPrivate::stringHandler;
TagPrivate::stringHandler = handler;
if (handler)
TagPrivate::stringHandler = handler;
else
TagPrivate::stringHandler = &defaultStringHandler;
}
////////////////////////////////////////////////////////////////////////////////

View File

@@ -85,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
@@ -140,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

@@ -112,7 +112,7 @@ void CommentsFrame::setTextEncoding(String::Type encoding)
PropertyMap CommentsFrame::asProperties() const
{
String key = PropertyMap::prepareKey(description());
String key = description().upper();
PropertyMap map;
if(key.isEmpty() || key == "COMMENT")
map.insert("COMMENT", text());
@@ -158,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);
@@ -149,7 +149,7 @@ namespace TagLib {
/*!
* 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

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

@@ -211,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));
}
}
}
@@ -289,7 +291,7 @@ PropertyMap TextIdentificationFrame::makeTMCLProperties() const
}
StringList l = fieldList();
for(StringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
String instrument = PropertyMap::prepareKey(*it);
String instrument = it->upper();
if(instrument.isNull()) {
// instrument is not a valid key -> frame unsupported
map.clear();
@@ -379,18 +381,12 @@ void UserTextIdentificationFrame::setDescription(const String &s)
PropertyMap UserTextIdentificationFrame::asProperties() const
{
String tagName = description();
PropertyMap map;
String key = map.prepareKey(tagName);
if(key.isNull()) // this frame's description is not a valid PropertyMap key -> add to unsupported list
map.unsupportedData().append(L"TXXX/" + description());
else {
StringList v = fieldList();
for(StringList::ConstIterator it = v.begin(); it != v.end(); ++it)
if(*it != description())
map.insert(key, *it);
}
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;
}
@@ -398,7 +394,7 @@ 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;

View File

@@ -234,7 +234,7 @@ namespace TagLib {
* This description identifies the frame and must be unique.
*/
//! An ID3v2 custom text identification frame implementationx
//! An ID3v2 custom text identification frame implementation
class TAGLIB_EXPORT UserTextIdentificationFrame : public TextIdentificationFrame
{

View File

@@ -24,8 +24,10 @@
***************************************************************************/
#include <tbytevectorlist.h>
#include <tpropertymap.h>
#include <tdebug.h>
#include "id3v2tag.h"
#include "uniquefileidentifierframe.h"
using namespace TagLib;
@@ -87,6 +89,34 @@ String UniqueFileIdentifierFrame::toString() const
return String::null;
}
PropertyMap UniqueFileIdentifierFrame::asProperties() const
{
PropertyMap map;
if(d->owner == "http://musicbrainz.org") {
map.insert("MUSICBRAINZ_TRACKID", String(d->identifier));
}
else {
map.unsupportedData().append(frameID() + String("/") + d->owner);
}
return map;
}
UniqueFileIdentifierFrame *UniqueFileIdentifierFrame::findByOwner(const ID3v2::Tag *tag, const String &o) // static
{
ID3v2::FrameList comments = tag->frameList("UFID");
for(ID3v2::FrameList::ConstIterator it = comments.begin();
it != comments.end();
++it)
{
UniqueFileIdentifierFrame *frame = dynamic_cast<UniqueFileIdentifierFrame *>(*it);
if(frame && frame->owner() == o)
return frame;
}
return 0;
}
void UniqueFileIdentifierFrame::parseFields(const ByteVector &data)
{
if(data.size() < 1) {

View File

@@ -46,7 +46,7 @@ namespace TagLib {
public:
/*!
* Creates a uniqe file identifier frame based on \a data.
* Creates a unique file identifier frame based on \a data.
*/
UniqueFileIdentifierFrame(const ByteVector &data);
@@ -94,6 +94,16 @@ namespace TagLib {
virtual String toString() const;
PropertyMap asProperties() const;
/*!
* UFID frames each have a unique owner. This searches for a UFID
* frame with the owner \a o and returns a pointer to it.
*
* \see owner()
*/
static UniqueFileIdentifierFrame *findByOwner(const Tag *tag, const String &o);
protected:
virtual void parseFields(const ByteVector &data);
virtual ByteVector renderFields() const;

View File

@@ -116,7 +116,7 @@ void UnsynchronizedLyricsFrame::setTextEncoding(String::Type encoding)
PropertyMap UnsynchronizedLyricsFrame::asProperties() const
{
PropertyMap map;
String key = PropertyMap::prepareKey(description());
String key = description().upper();
if(key.isEmpty() || key.upper() == "LYRICS")
map.insert("LYRICS", text());
else if(key.isNull())
@@ -158,8 +158,13 @@ void UnsynchronizedLyricsFrame::parseFields(const ByteVector &data)
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);
}
}
}

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