282 Commits

Author SHA1 Message Date
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
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
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
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
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
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
177 changed files with 6450 additions and 1767 deletions

3
.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

7
.travis.yml Normal file
View File

@@ -0,0 +1,7 @@
language: cpp
compiler:
- gcc
- clang
install: sudo apt-get install 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

@@ -47,7 +47,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 "9")
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 +56,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 14)
set(TAGLIB_SOVERSION_REVISION 0)
set(TAGLIB_SOVERSION_AGE 11)
set(TAGLIB_SOVERSION_AGE 13)
math(EXPR TAGLIB_SOVERSION_MAJOR "${TAGLIB_SOVERSION_CURRENT} - ${TAGLIB_SOVERSION_AGE}")
math(EXPR TAGLIB_SOVERSION_MINOR "${TAGLIB_SOVERSION_AGE}")
@@ -66,8 +66,15 @@ 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(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 WIN32 AND NOT BUILD_FRAMEWORK)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/taglib.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/taglib.pc )
@@ -75,13 +82,18 @@ if(NOT WIN32 AND NOT BUILD_FRAMEWORK)
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()
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)

View File

@@ -5,19 +5,222 @@ include(CheckFunctionExists)
include(CheckLibraryExists)
include(CheckTypeSize)
include(CheckCXXSourceCompiles)
include(TestBigEndian)
# Check if the size of integral 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()
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()
# Determine the CPU byte order.
test_big_endian(IS_BIG_ENDIAN)
if(NOT IS_BIG_ENDIAN)
set(SYSTEM_BYTEORDER 1)
else()
set(SYSTEM_BYTEORDER 2)
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.
# GCC's __builtin_bswap* should be checked individually
# because some of them can be missing depends on the GCC version.
check_cxx_source_compiles("
int main() {
__builtin_bswap16(0);
return 0;
}
" HAVE_GCC_BYTESWAP_16)
check_cxx_source_compiles("
int main() {
__builtin_bswap32(0);
return 0;
}
" HAVE_GCC_BYTESWAP_32)
check_cxx_source_compiles("
int main() {
__builtin_bswap64(0);
return 0;
}
" HAVE_GCC_BYTESWAP_64)
if(NOT HAVE_GCC_BYTESWAP_16 OR NOT HAVE_GCC_BYTESWAP_32 OR NOT HAVE_GCC_BYTESWAP_64)
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 sprintf.
check_cxx_source_compiles("
#include <cstdio>
int main() { char buf[20]; snprintf(buf, 20, \"%d\", 1); return 0; }
" HAVE_SNPRINTF)
if(NOT HAVE_SNPRINTF)
check_cxx_source_compiles("
#include <cstdio>
int main() { char buf[20]; sprintf_s(buf, \"%d\", 1); return 0; }
" HAVE_SPRINTF_S)
endif()
# Determine whether your compiler supports codecvt.
check_cxx_source_compiles("
#include <codecvt>
int main() {
std::codecvt_utf8_utf16<wchar_t> x;
return 0;
}
" HAVE_STD_CODECVT)
# Check for libz using the cmake supplied FindZLIB.cmake
# check for libz using the cmake supplied FindZLIB.cmake
find_package(ZLIB)
if(ZLIB_FOUND)
set(HAVE_ZLIB 1)
set(HAVE_ZLIB 1)
else()
set(HAVE_ZLIB 0)
set(HAVE_ZLIB 0)
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)
message(STATUS "CppUnit not found, disabling tests.")
set(BUILD_TESTS OFF)
endif()

97
INSTALL
View File

@@ -46,15 +46,102 @@ 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.
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
----------

41
NEWS
View File

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

@@ -19,10 +19,6 @@
* USA *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <fileref.h>
#include <tfile.h>

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

37
config.h.cmake Normal file
View File

@@ -0,0 +1,37 @@
/* config.h. Generated by cmake from config.h.cmake */
/* Indicates the byte order of your target system */
/* 1 if little-endian, 2 if big-endian. */
#cmakedefine SYSTEM_BYTEORDER ${SYSTEM_BYTEORDER}
/* Defined if your compiler supports some byte swap functions */
#cmakedefine HAVE_GCC_BYTESWAP_16 1
#cmakedefine HAVE_GCC_BYTESWAP_32 1
#cmakedefine HAVE_GCC_BYTESWAP_64 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 codecvt */
#cmakedefine HAVE_STD_CODECVT 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 sprintf */
#cmakedefine HAVE_SNPRINTF 1
#cmakedefine HAVE_SPRINTF_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,10 +23,12 @@
*/
#include <iostream>
#include <iomanip>
#include <stdio.h>
#include <fileref.h>
#include <tag.h>
#include <tpropertymap.h>
using namespace std;
@@ -49,7 +51,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 +59,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()) {

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

18
taglib/CMakeLists.txt Normal file → Executable file
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
@@ -49,6 +50,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
@@ -65,6 +68,7 @@ set(tag_HDRS
mpeg/id3v2/frames/attachedpictureframe.h
mpeg/id3v2/frames/commentsframe.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
@@ -82,6 +86,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 +108,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
@@ -151,6 +158,7 @@ set(frames_SRCS
mpeg/id3v2/frames/attachedpictureframe.cpp
mpeg/id3v2/frames/commentsframe.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
@@ -217,6 +225,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 +255,7 @@ set(aiff_SRCS
set(wav_SRCS
riff/wav/wavfile.cpp
riff/wav/wavproperties.cpp
riff/wav/infotag.cpp
)
set(mod_SRCS
@@ -277,6 +291,8 @@ set(toolkit_SRCS
toolkit/tfilestream.cpp
toolkit/tdebug.cpp
toolkit/tpropertymap.cpp
toolkit/trefcounter.cpp
toolkit/tdebuglistener.cpp
toolkit/unicode.cpp
)
@@ -284,7 +300,7 @@ 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}
tag.cpp
tagunion.cpp
fileref.cpp

View File

@@ -47,7 +47,7 @@ using namespace TagLib;
namespace
{
enum { ApeAPEIndex, ApeID3v1Index };
enum { ApeAPEIndex = 0, ApeID3v1Index = 1 };
}
class APE::File::FilePrivate
@@ -90,14 +90,16 @@ APE::File::File(FileName file, bool readProperties,
Properties::ReadStyle propertiesStyle) : TagLib::File(file)
{
d = new FilePrivate;
read(readProperties, propertiesStyle);
if(isOpen())
read(readProperties, propertiesStyle);
}
APE::File::File(IOStream *stream, bool readProperties,
Properties::ReadStyle propertiesStyle) : TagLib::File(stream)
{
d = new FilePrivate;
read(readProperties, propertiesStyle);
if(isOpen())
read(readProperties, propertiesStyle);
}
APE::File::~File()
@@ -129,12 +131,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,6 +235,16 @@ void APE::File::strip(int tags)
}
}
bool APE::File::hasAPETag() const
{
return d->hasAPE;
}
bool APE::File::hasID3v1Tag() const
{
return d->hasID3v1;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////

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 pontentially 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.
@@ -146,27 +152,38 @@ namespace TagLib {
/*!
* 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,6 +197,20 @@ 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 &);

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

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

@@ -125,10 +125,10 @@ void APE::Properties::read()
// Then we read the header common for all versions of APE
d->file->seek(offset);
ByteVector commonHeader=d->file->readBlock(6);
ByteVector commonHeader = d->file->readBlock(6);
if(!commonHeader.startsWith("MAC "))
return;
d->version = commonHeader.mid(4).toUInt(false);
d->version = commonHeader.toUShort(4, false);
if(d->version >= 3980) {
analyzeCurrent();
@@ -182,7 +182,7 @@ void APE::Properties::analyzeCurrent()
// Read the descriptor
d->file->seek(2, File::Current);
ByteVector descriptor = d->file->readBlock(44);
uint descriptorBytes = descriptor.mid(0,4).toUInt(false);
const uint descriptorBytes = descriptor.toUInt(0, false);
if ((descriptorBytes - 52) > 0)
d->file->seek(descriptorBytes - 52, File::Current);
@@ -191,14 +191,14 @@ void APE::Properties::analyzeCurrent()
ByteVector header = d->file->readBlock(24);
// 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->channels = header.toShort(18, false);
d->sampleRate = header.toUInt(20, false);
d->bitsPerSample = header.toShort(16, false);
//d->compressionLevel =
uint totalFrames = header.mid(12, 4).toUInt(false);
uint blocksPerFrame = header.mid(4, 4).toUInt(false);
uint finalFrameBlocks = header.mid(8, 4).toUInt(false);
const uint totalFrames = header.toUInt(12, false);
const uint blocksPerFrame = header.toUInt(4, false);
const uint finalFrameBlocks = header.toUInt(8, 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;
@@ -207,13 +207,13 @@ void APE::Properties::analyzeCurrent()
void APE::Properties::analyzeOld()
{
ByteVector header = d->file->readBlock(26);
uint totalFrames = header.mid(18, 4).toUInt(false);
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,10 +221,11 @@ 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->channels = header.toShort(4, false);
d->sampleRate = header.toUInt(6, false);
const uint finalFrameBlocks = header.toUInt(22, false);
const 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;
}

View File

@@ -189,7 +189,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,7 +227,7 @@ 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);
@@ -238,9 +238,12 @@ PropertyMap APE::Tag::setProperties(const PropertyMap &origProps)
// 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 +255,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

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.
*/

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 "asfattribute.h"
#include "asffile.h"

View File

@@ -23,12 +23,9 @@
* 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"
@@ -186,7 +183,8 @@ ByteVector ASF::File::FilePropertiesObject::guid()
void ASF::File::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));
file->d->properties->setLength(
(int)(data.toLongLong(40, false) / 10000000L - data.toLongLong(56, false) / 1000L));
}
ByteVector ASF::File::StreamPropertiesObject::guid()
@@ -197,9 +195,9 @@ ByteVector ASF::File::StreamPropertiesObject::guid()
void ASF::File::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);
file->d->properties->setChannels(data.toShort(56, false));
file->d->properties->setSampleRate(data.toUInt(58, false));
file->d->properties->setBitrate(data.toUInt(62, false) * 8 / 1000);
}
ByteVector ASF::File::ContentDescriptionObject::guid()
@@ -348,7 +346,7 @@ 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;
}
@@ -372,14 +370,16 @@ ASF::File::File(FileName file, bool readProperties, Properties::ReadStyle proper
: TagLib::File(file)
{
d = new FilePrivate;
read(readProperties, propertiesStyle);
if(isOpen())
read(readProperties, propertiesStyle);
}
ASF::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle propertiesStyle)
: TagLib::File(stream)
{
d = new FilePrivate;
read(readProperties, propertiesStyle);
if(isOpen())
read(readProperties, propertiesStyle);
}
ASF::File::~File()
@@ -401,6 +401,21 @@ 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;
@@ -535,7 +550,7 @@ bool ASF::File::save()
data.append(d->objects[i]->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;
}

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.
*/
@@ -97,7 +116,6 @@ namespace TagLib {
virtual bool save();
private:
int readBYTE(bool *ok = 0);
int readWORD(bool *ok = 0);
unsigned int readDWORD(bool *ok = 0);

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 "asfattribute.h"
#include "asffile.h"
#include "asfpicture.h"
@@ -149,7 +146,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

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

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;
@@ -196,3 +193,162 @@ bool ASF::Tag::isEmpty() const
d->attributeListMap.isEmpty();
}
static const char *keyTranslation[][2] = {
{ "WM/AlbumTitle", "ALBUM" },
{ "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

@@ -176,6 +176,10 @@ namespace TagLib {
*/
void addAttribute(const String &name, const Attribute &attribute);
PropertyMap properties() const;
void removeUnsupportedProperties(const StringList& properties);
PropertyMap setProperties(const PropertyMap &properties);
private:
class TagPrivate;

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,6 +257,8 @@ 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")

0
taglib/fileref.h Normal file → Executable file
View File

View File

@@ -70,7 +70,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;
@@ -108,7 +109,8 @@ FLAC::File::File(FileName file, bool readProperties,
TagLib::File(file)
{
d = new FilePrivate;
read(readProperties, propertiesStyle);
if(isOpen())
read(readProperties, propertiesStyle);
}
FLAC::File::File(FileName file, ID3v2::FrameFactory *frameFactory,
@@ -117,7 +119,8 @@ FLAC::File::File(FileName file, ID3v2::FrameFactory *frameFactory,
{
d = new FilePrivate;
d->ID3v2FrameFactory = frameFactory;
read(readProperties, propertiesStyle);
if(isOpen())
read(readProperties, propertiesStyle);
}
FLAC::File::File(IOStream *stream, ID3v2::FrameFactory *frameFactory,
@@ -126,7 +129,8 @@ FLAC::File::File(IOStream *stream, ID3v2::FrameFactory *frameFactory,
{
d = new FilePrivate;
d->ID3v2FrameFactory = frameFactory;
read(readProperties, propertiesStyle);
if(isOpen())
read(readProperties, propertiesStyle);
}
FLAC::File::~File()
@@ -164,14 +168,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
@@ -243,7 +240,7 @@ bool FLAC::File::save()
}
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
@@ -402,7 +399,7 @@ void FLAC::File::scan()
char blockType = header[0] & 0x7f;
bool isLastBlock = (header[0] & 0x80) != 0;
uint length = header.mid(1, 3).toUInt();
uint length = header.toUInt(1U, 3U);
// First block should be the stream_info metadata
@@ -422,10 +419,10 @@ void FLAC::File::scan()
header = readBlock(4);
blockType = header[0] & 0x7f;
isLastBlock = (header[0] & 0x80) != 0;
length = header.mid(1, 3).toUInt();
length = header.toUInt(1U, 3U);
ByteVector data = readBlock(length);
if(data.size() != length) {
if(data.size() != length || length == 0) {
debug("FLAC::File::scan() -- FLAC stream corrupted");
setValid(false);
return;
@@ -555,3 +552,17 @@ 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;
}

View 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 APE 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 &);
@@ -153,39 +161,57 @@ namespace TagLib {
/*!
* 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);
@@ -238,6 +264,27 @@ 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 &);

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

@@ -124,7 +124,7 @@ void FLAC::Properties::read()
return;
}
int pos = 0;
uint pos = 0;
// Minimum block size (in samples)
pos += 2;
@@ -138,7 +138,7 @@ void FLAC::Properties::read()
// Maximum frame size (in bytes)
pos += 3;
uint flags = d->data.mid(pos, 4).toUInt(true);
uint flags = d->data.toUInt(pos, true);
pos += 4;
d->sampleRate = flags >> 12;
@@ -149,7 +149,7 @@ void FLAC::Properties::read()
// 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);
unsigned long long lo = d->data.toUInt(pos, true);
pos += 4;
d->sampleFrames = (hi << 32) | lo;

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

@@ -94,7 +94,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 +104,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

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

@@ -70,7 +70,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

@@ -23,10 +23,6 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <tdebug.h>
#include <tstring.h>
#include "mp4atom.h"
@@ -52,10 +48,10 @@ 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();
const 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;

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,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 "mp4file.h"
@@ -67,14 +64,16 @@ MP4::File::File(FileName file, bool readProperties, AudioProperties::ReadStyle a
: TagLib::File(file)
{
d = new FilePrivate;
read(readProperties, audioPropertiesStyle);
if(isOpen())
read(readProperties, audioPropertiesStyle);
}
MP4::File::File(IOStream *stream, bool readProperties, AudioProperties::ReadStyle audioPropertiesStyle)
: TagLib::File(stream)
{
d = new FilePrivate;
read(readProperties, audioPropertiesStyle);
if(isOpen())
read(readProperties, audioPropertiesStyle);
}
MP4::File::~File()
@@ -88,6 +87,21 @@ 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
{

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.
*/

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"
@@ -96,8 +92,8 @@ MP4::Properties::Properties(File *file, MP4::Atoms *atoms, ReadStyle style)
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();
const long long unit = data.toLongLong(28U);
const long long length = data.toLongLong(36U);
d->length = unit ? int(length / unit) : 0;
}
else {
@@ -105,8 +101,8 @@ MP4::Properties::Properties(File *file, MP4::Atoms *atoms, ReadStyle style)
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();
const unsigned int unit = data.toUInt(20U);
const unsigned int length = data.toUInt(24U);
d->length = unit ? length / unit : 0;
}
@@ -118,11 +114,11 @@ MP4::Properties::Properties(File *file, MP4::Atoms *atoms, ReadStyle style)
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();
d->channels = data.toShort(40U);
d->bitsPerSample = data.toShort(42U);
d->sampleRate = data.toUInt(46U);
if(data.mid(56, 4) == "esds" && data[64] == 0x03) {
long pos = 65;
uint pos = 65;
if(data.mid(pos, 3) == "\x80\x80\x80") {
pos += 3;
}
@@ -133,16 +129,16 @@ MP4::Properties::Properties(File *file, MP4::Atoms *atoms, ReadStyle style)
pos += 3;
}
pos += 10;
d->bitrate = (data.mid(pos, 4).toUInt() + 500) / 1000;
d->bitrate = (data.toUInt(pos) + 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();
d->channels = data.at(73);
d->bitrate = data.toUInt(80U) / 1000;
d->sampleRate = data.toUInt(84U);
}
}

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"
@@ -113,9 +110,9 @@ MP4::Tag::parseData2(MP4::Atom *atom, TagLib::File *file, int expectedFlags, boo
int i = 0;
unsigned int pos = 0;
while(pos < data.size()) {
int length = data.mid(pos, 4).toUInt();
const int length = static_cast<int>(data.toUInt(pos));
ByteVector name = data.mid(pos + 4, 4);
int flags = data.mid(pos + 8, 4).toUInt();
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\"");
@@ -158,7 +155,7 @@ MP4::Tag::parseInt(MP4::Atom *atom, TagLib::File *file)
{
ByteVectorList data = parseData(atom, file);
if(data.size()) {
d->items.insert(atom->name, (int)data[0].toShort());
addItem(atom->name, (int)data[0].toShort());
}
}
@@ -167,7 +164,7 @@ MP4::Tag::parseUInt(MP4::Atom *atom, TagLib::File *file)
{
ByteVectorList data = parseData(atom, file);
if(data.size()) {
d->items.insert(atom->name, data[0].toUInt());
addItem(atom->name, data[0].toUInt());
}
}
@@ -176,7 +173,7 @@ MP4::Tag::parseLongLong(MP4::Atom *atom, TagLib::File *file)
{
ByteVectorList data = parseData(atom, file);
if(data.size()) {
d->items.insert(atom->name, data[0].toLongLong());
addItem(atom->name, data[0].toLongLong());
}
}
@@ -185,7 +182,7 @@ MP4::Tag::parseByte(MP4::Atom *atom, TagLib::File *file)
{
ByteVectorList data = parseData(atom, file);
if(data.size()) {
d->items.insert(atom->name, (uchar)data[0].at(0));
addItem(atom->name, (uchar)data[0].at(0));
}
}
@@ -195,8 +192,8 @@ MP4::Tag::parseGnre(MP4::Atom *atom, TagLib::File *file)
ByteVectorList data = parseData(atom, file);
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)));
}
}
}
@@ -206,9 +203,9 @@ MP4::Tag::parseIntPair(MP4::Atom *atom, TagLib::File *file)
{
ByteVectorList data = parseData(atom, file);
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));
}
}
@@ -218,7 +215,7 @@ MP4::Tag::parseBool(MP4::Atom *atom, TagLib::File *file)
ByteVectorList data = parseData(atom, file);
if(data.size()) {
bool value = data[0].size() ? data[0][0] != '\0' : false;
d->items.insert(atom->name, value);
addItem(atom->name, value);
}
}
@@ -231,7 +228,7 @@ MP4::Tag::parseText(MP4::Atom *atom, TagLib::File *file, int expectedFlags)
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);
}
}
@@ -255,7 +252,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,7 +261,7 @@ MP4::Tag::parseFreeForm(MP4::Atom *atom, TagLib::File *file)
}
Item item(value);
item.setAtomDataType(type);
d->items.insert(name, item);
addItem(name, item);
}
}
}
@@ -276,21 +273,24 @@ MP4::Tag::parseCovr(MP4::Atom *atom, TagLib::File *file)
ByteVector data = file->readBlock(atom->length - 8);
unsigned int pos = 0;
while(pos < data.size()) {
int length = data.mid(pos, 4).toUInt();
const int length = static_cast<int>(data.toUInt(pos));
ByteVector name = data.mid(pos + 4, 4);
int flags = data.mid(pos + 8, 4).toUInt();
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
@@ -526,11 +526,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 +547,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 +570,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;
}
@@ -756,3 +756,162 @@ MP4::Tag::itemListMap()
return d->items;
}
static const char *keyTranslation[][2] = {
{ "\251nam", "TITLE" },
{ "\251ART", "ARTIST" },
{ "\251alb", "ALBUM" },
{ "\251cmt", "COMMENT" },
{ "\251gen", "GENRE" },
{ "\251day", "DATE" },
{ "\251wrt", "COMPOSER" },
{ "\251grp", "GROUPING" },
{ "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::ItemListMap::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

@@ -67,6 +67,10 @@ namespace TagLib {
ItemListMap &itemListMap();
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);
@@ -101,6 +105,8 @@ namespace TagLib {
void saveNew(TagLib::ByteVector &data);
void saveExisting(TagLib::ByteVector &data, 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
@@ -94,14 +94,16 @@ MPC::File::File(FileName file, bool readProperties,
Properties::ReadStyle propertiesStyle) : TagLib::File(file)
{
d = new FilePrivate;
read(readProperties, propertiesStyle);
if(isOpen())
read(readProperties, propertiesStyle);
}
MPC::File::File(IOStream *stream, bool readProperties,
Properties::ReadStyle propertiesStyle) : TagLib::File(stream)
{
d = new FilePrivate;
read(readProperties, propertiesStyle);
if(isOpen())
read(readProperties, propertiesStyle);
}
MPC::File::~File()
@@ -133,15 +135,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,6 +256,15 @@ 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

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 &);
@@ -140,28 +145,39 @@ namespace TagLib {
/*!
* 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,6 +198,20 @@ 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 &);

View File

@@ -207,14 +207,14 @@ void MPC::Properties::readSV8(File *file)
d->sampleFrames = readSize(data.mid(pos), pos);
ulong begSilence = readSize(data.mid(pos), pos);
std::bitset<16> flags(TAGLIB_CONSTRUCT_BITSET(data.mid(pos, 2).toUShort(true)));
std::bitset<16> flags(TAGLIB_CONSTRUCT_BITSET(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;
if((d->sampleFrames - begSilence) != 0)
d->bitrate = d->streamLength * 8.0 * d->sampleRate / (d->sampleFrames - begSilence);
d->bitrate = (int)(d->streamLength * 8.0 * d->sampleRate / (d->sampleFrames - begSilence));
d->bitrate = d->bitrate / 1000;
d->length = (d->sampleFrames - begSilence) / d->sampleRate;
@@ -228,10 +228,10 @@ void MPC::Properties::readSV8(File *file)
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);
}
}
@@ -252,18 +252,18 @@ void MPC::Properties::readSV7(const ByteVector &data)
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)));
std::bitset<32> flags(TAGLIB_CONSTRUCT_BITSET(data.toUInt(8, false)));
d->sampleRate = sftable[flags[17] * 2 + flags[16]];
d->channels = 2;
uint gapless = data.mid(5, 4).toUInt(false);
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 +279,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,7 +293,7 @@ void MPC::Properties::readSV7(const ByteVector &data)
d->sampleFrames = d->totalFrames * 1152 - 576;
}
else {
uint headerData = data.mid(0, 4).toUInt(false);
uint headerData = data.toUInt(0, false);
d->bitrate = (headerData >> 23) & 0x01ff;
d->version = (headerData >> 11) & 0x03ff;
@@ -301,9 +301,9 @@ void MPC::Properties::readSV7(const ByteVector &data)
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;
}

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

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

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

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

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

@@ -213,8 +213,10 @@ void TextIdentificationFrame::parseFields(const ByteVector &data)
for(ByteVectorList::Iterator 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;
}

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

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

View File

@@ -156,7 +156,7 @@ void UserUrlLinkFrame::setDescription(const String &s)
PropertyMap UserUrlLinkFrame::asProperties() const
{
PropertyMap map;
String key = PropertyMap::prepareKey(description());
String key = description().upper();
if(key.isEmpty() || key.upper() == "URL")
map.insert("URL", url());
else if(key.isNull())

View File

@@ -36,6 +36,7 @@
#include <tdebug.h>
#include <tstringlist.h>
#include "id3v2tag.h"
#include "id3v2frame.h"
#include "id3v2synchdata.h"
#include "tpropertymap.h"
@@ -43,6 +44,7 @@
#include "frames/urllinkframe.h"
#include "frames/unsynchronizedlyricsframe.h"
#include "frames/commentsframe.h"
#include "frames/uniquefileidentifierframe.h"
#include "frames/unknownframe.h"
using namespace TagLib;
@@ -71,7 +73,7 @@ namespace
return false;
for(ByteVector::ConstIterator it = frameID.begin(); it != frameID.end(); it++) {
if( (*it < 'A' || *it > 'Z') && (*it < '1' || *it > '9') ) {
if( (*it < 'A' || *it > 'Z') && (*it < '0' || *it > '9') ) {
return false;
}
}
@@ -119,16 +121,20 @@ Frame *Frame::createTextualFrame(const String &key, const StringList &values) //
TextIdentificationFrame *frame = new TextIdentificationFrame(frameID, String::UTF8);
frame->setText(values);
return frame;
} else if(values.size() == 1){ // URL frame (not WXXX); support only one value
} else if((frameID[0] == 'W') && (values.size() == 1)){ // URL frame (not WXXX); support only one value
UrlLinkFrame* frame = new UrlLinkFrame(frameID);
frame->setUrl(values.front());
return frame;
}
}
if(key == "MUSICBRAINZ_TRACKID" && values.size() == 1) {
UniqueFileIdentifierFrame *frame = new UniqueFileIdentifierFrame("http://musicbrainz.org", values.front().data(String::UTF8));
return frame;
}
// now we check if it's one of the "special" cases:
// -LYRICS: depending on the number of values, use USLT or TXXX (with description=LYRICS)
if((key == "LYRICS" || key.startsWith(lyricsPrefix)) && values.size() == 1){
UnsynchronizedLyricsFrame *frame = new UnsynchronizedLyricsFrame();
UnsynchronizedLyricsFrame *frame = new UnsynchronizedLyricsFrame(String::UTF8);
frame->setDescription(key == "LYRICS" ? key : key.substr(lyricsPrefix.size()));
frame->setText(values.front());
return frame;
@@ -143,12 +149,14 @@ Frame *Frame::createTextualFrame(const String &key, const StringList &values) //
// -COMMENT: depending on the number of values, use COMM or TXXX (with description=COMMENT)
if((key == "COMMENT" || key.startsWith(commentPrefix)) && values.size() == 1){
CommentsFrame *frame = new CommentsFrame(String::UTF8);
frame->setDescription(key == "COMMENT" ? key : key.substr(commentPrefix.size()));
if (key != "COMMENT"){
frame->setDescription(key.substr(commentPrefix.size()));
}
frame->setText(values.front());
return frame;
}
// if non of the above cases apply, we use a TXXX frame with the key as description
return new UserTextIdentificationFrame(key, values, String::UTF8);
return new UserTextIdentificationFrame(keyToTXXX(key), values, String::UTF8);
}
Frame::~Frame()
@@ -273,7 +281,11 @@ String Frame::readStringField(const ByteVector &data, String::Type encoding, int
if(end < *position)
return String::null;
String str = String(data.mid(*position, end - *position), encoding);
String str;
if(encoding == String::Latin1)
str = Tag::latin1StringHandler()->parse(data.mid(*position, end - *position));
else
str = String(data.mid(*position, end - *position), encoding);
*position = end + delimiter.size();
@@ -343,7 +355,7 @@ static const char *frameTranslation[][2] = {
{ "TLAN", "LANGUAGE" },
{ "TLEN", "LENGTH" },
//{ "TMCL", "MUSICIANCREDITS" }, handled separately
{ "TMED", "MEDIATYPE" },
{ "TMED", "MEDIA" },
{ "TMOO", "MOOD" },
{ "TOAL", "ORIGINALALBUM" },
{ "TOFN", "ORIGINALFILENAME" },
@@ -356,7 +368,7 @@ static const char *frameTranslation[][2] = {
{ "TPE4", "REMIXER" }, // could also be ARRANGER
{ "TPOS", "DISCNUMBER" },
{ "TPRO", "PRODUCEDNOTICE" },
{ "TPUB", "PUBLISHER" },
{ "TPUB", "LABEL" },
{ "TRCK", "TRACKNUMBER" },
{ "TRSN", "RADIOSTATION" },
{ "TRSO", "RADIOSTATIONOWNER" },
@@ -380,6 +392,18 @@ static const char *frameTranslation[][2] = {
//{ "USLT", "LYRICS" }, handled specially
};
static const TagLib::uint txxxFrameTranslationSize = 7;
static const char *txxxFrameTranslation[][2] = {
{ "MusicBrainz Album Id", "MUSICBRAINZ_ALBUMID" },
{ "MusicBrainz Artist Id", "MUSICBRAINZ_ARTISTID" },
{ "MusicBrainz Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID" },
{ "MusicBrainz Release Group Id", "MUSICBRAINZ_RELEASEGROUPID" },
{ "MusicBrainz Work Id", "MUSICBRAINZ_WORKID" },
{ "Acoustid Id", "ACOUSTID_ID" },
{ "Acoustid Fingerprint", "ACOUSTID_FINGERPRINT" },
{ "MusicIP PUID", "MUSICIP_PUID" },
};
Map<ByteVector, String> &idMap()
{
static Map<ByteVector, String> m;
@@ -389,6 +413,18 @@ Map<ByteVector, String> &idMap()
return m;
}
Map<String, String> &txxxMap()
{
static Map<String, String> m;
if(m.isEmpty()) {
for(size_t i = 0; i < txxxFrameTranslationSize; ++i) {
String key = String(txxxFrameTranslation[i][0]).upper();
m[key] = txxxFrameTranslation[i][1];
}
}
return m;
}
// list of deprecated frames and their successors
static const TagLib::uint deprecatedFramesSize = 4;
static const char *deprecatedFrames[][2] = {
@@ -428,6 +464,26 @@ ByteVector Frame::keyToFrameID(const String &s)
return ByteVector::null;
}
String Frame::txxxToKey(const String &description)
{
Map<String, String> &m = txxxMap();
String d = description.upper();
if(m.contains(d))
return m[d];
return d;
}
String Frame::keyToTXXX(const String &s)
{
static Map<String, String> m;
if(m.isEmpty())
for(size_t i = 0; i < txxxFrameTranslationSize; ++i)
m[txxxFrameTranslation[i][1]] = txxxFrameTranslation[i][0];
if(m.contains(s.upper()))
return m[s];
return s;
}
PropertyMap Frame::asProperties() const
{
if(dynamic_cast< const UnknownFrame *>(this)) {
@@ -449,6 +505,8 @@ PropertyMap Frame::asProperties() const
return dynamic_cast< const CommentsFrame* >(this)->asProperties();
else if(id == "USLT")
return dynamic_cast< const UnsynchronizedLyricsFrame* >(this)->asProperties();
else if(id == "UFID")
return dynamic_cast< const UniqueFileIdentifierFrame* >(this)->asProperties();
PropertyMap m;
m.unsupportedData().append(id);
return m;
@@ -584,7 +642,7 @@ void Frame::Header::setData(const ByteVector &data, uint version)
return;
}
d->frameSize = data.mid(3, 3).toUInt();
d->frameSize = data.toUInt(3, 3, true);
break;
}
@@ -612,7 +670,7 @@ void Frame::Header::setData(const ByteVector &data, uint version)
// Set the size -- the frame size is the four bytes starting at byte four in
// the frame header (structure 4)
d->frameSize = data.mid(4, 4).toUInt();
d->frameSize = data.toUInt(4U);
{ // read the first byte of flags
std::bitset<8> flags(data[8]);
@@ -659,7 +717,7 @@ void Frame::Header::setData(const ByteVector &data, uint version)
// iTunes writes v2.4 tags with v2.3-like frame sizes
if(d->frameSize > 127) {
if(!isValidFrameID(data.mid(d->frameSize + 10, 4))) {
unsigned int uintSize = data.mid(4, 4).toUInt();
unsigned int uintSize = data.toUInt(4U);
if(isValidFrameID(data.mid(uintSize + 10, 4))) {
d->frameSize = uintSize;
}

View File

@@ -274,6 +274,15 @@ namespace TagLib {
*/
static String frameIDToKey(const ByteVector &);
/*!
* Returns an appropriate TXXX frame description for the given free-form tag key.
*/
static String keyToTXXX(const String &);
/*!
* Returns a free-form tag name for the given ID3 frame description.
*/
static String txxxToKey(const String &);
/*!
* This helper function splits the PropertyMap \a original into three ProperytMaps

View File

@@ -44,6 +44,7 @@
#include "frames/unsynchronizedlyricsframe.h"
#include "frames/popularimeterframe.h"
#include "frames/privateframe.h"
#include "frames/ownershipframe.h"
using namespace TagLib;
using namespace ID3v2;
@@ -98,7 +99,7 @@ Frame *FrameFactory::createFrame(const ByteVector &origData, Header *tagHeader)
// A quick sanity check -- make sure that the frameID is 4 uppercase Latin1
// characters. Also make sure that there is data in the frame.
if(!frameID.size() == (version < 3 ? 3 : 4) ||
if(frameID.size() != (version < 3 ? 3 : 4) ||
header->frameSize() <= uint(header->dataLengthIndicator() ? 4 : 0) ||
header->frameSize() > data.size())
{
@@ -106,8 +107,19 @@ Frame *FrameFactory::createFrame(const ByteVector &origData, Header *tagHeader)
return 0;
}
#ifndef NO_ITUNES_HACKS
if(version == 3 && frameID.size() == 4 && frameID[3] == '\0') {
// iTunes v2.3 tags store v2.2 frames - convert now
frameID = frameID.mid(0, 3);
header->setFrameID(frameID);
header->setVersion(2);
updateFrame(header);
header->setVersion(3);
}
#endif
for(ByteVector::ConstIterator it = frameID.begin(); it != frameID.end(); it++) {
if( (*it < 'A' || *it > 'Z') && (*it < '1' || *it > '9') ) {
if( (*it < 'A' || *it > 'Z') && (*it < '0' || *it > '9') ) {
delete header;
return 0;
}
@@ -124,7 +136,7 @@ Frame *FrameFactory::createFrame(const ByteVector &origData, Header *tagHeader)
// TagLib doesn't mess with encrypted frames, so just treat them
// as unknown frames.
#if HAVE_ZLIB == 0
#if !defined(HAVE_ZLIB) || HAVE_ZLIB == 0
if(header->compression()) {
debug("Compressed frames are currently not supported.");
return new UnknownFrame(data, header);
@@ -238,6 +250,14 @@ Frame *FrameFactory::createFrame(const ByteVector &origData, Header *tagHeader)
if(frameID == "PRIV")
return new PrivateFrame(data, header);
// Ownership (frames 4.22)
if(frameID == "OWNE") {
OwnershipFrame *f = new OwnershipFrame(data, header);
d->setTextEncoding(f);
return f;
}
return new UnknownFrame(data, header);
}

View File

@@ -123,8 +123,7 @@ namespace TagLib {
FrameFactory();
/*!
* Destroys the frame factory. In most cases this will never be called (as
* is typical of singletons).
* Destroys the frame factory.
*/
virtual ~FrameFactory();

View File

@@ -49,7 +49,14 @@ TagLib::uint SynchData::toUInt(const ByteVector &data)
// Invalid data; assume this was created by some buggy software that just
// put normal integers here rather than syncsafe ones, and try it that
// way.
sum = (data.size() > 4) ? data.mid(0, 4).toUInt() : data.toUInt();
if(data.size() >= 4) {
sum = data.toUInt(0, true);
}
else {
ByteVector tmp(data);
tmp.resize(4);
sum = tmp.toUInt(0, true);
}
}
return sum;

View File

@@ -23,6 +23,10 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <tfile.h>
#include "id3v2tag.h"
@@ -70,8 +74,30 @@ public:
FrameListMap frameListMap;
FrameList frameList;
static const Latin1StringHandler *stringHandler;
};
static const Latin1StringHandler defaultStringHandler;
const ID3v2::Latin1StringHandler *ID3v2::Tag::TagPrivate::stringHandler = &defaultStringHandler;
////////////////////////////////////////////////////////////////////////////////
// StringHandler implementation
////////////////////////////////////////////////////////////////////////////////
Latin1StringHandler::Latin1StringHandler()
{
}
Latin1StringHandler::~Latin1StringHandler()
{
}
String Latin1StringHandler::parse(const ByteVector &data) const
{
return String(data, String::Latin1);
}
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
@@ -357,10 +383,12 @@ void ID3v2::Tag::removeUnsupportedProperties(const StringList &properties)
for(FrameList::ConstIterator fit = l.begin(); fit != l.end(); fit++)
if (dynamic_cast<const UnknownFrame *>(*fit) != 0)
removeFrame(*fit);
} else if(it->size() == 4){
}
else if(it->size() == 4){
ByteVector id = it->data(String::Latin1);
removeFrames(id);
} else {
}
else {
ByteVector id = it->substr(0,4).data(String::Latin1);
if(it->size() <= 5)
continue; // invalid specification
@@ -374,6 +402,8 @@ void ID3v2::Tag::removeUnsupportedProperties(const StringList &properties)
frame = CommentsFrame::findByDescription(this, description);
else if(id == "USLT")
frame = UnsynchronizedLyricsFrame::findByDescription(this, description);
else if(id == "UFID")
frame = UniqueFileIdentifierFrame::findByOwner(this, description);
if(frame)
removeFrame(frame);
}
@@ -584,6 +614,19 @@ ByteVector ID3v2::Tag::render(int version) const
return d->header.render() + tagData;
}
Latin1StringHandler const *ID3v2::Tag::latin1StringHandler()
{
return TagPrivate::stringHandler;
}
void ID3v2::Tag::setLatin1StringHandler(const Latin1StringHandler *handler)
{
if(handler)
TagPrivate::stringHandler = handler;
else
TagPrivate::stringHandler = &defaultStringHandler;
}
////////////////////////////////////////////////////////////////////////////////
// protected members
////////////////////////////////////////////////////////////////////////////////
@@ -645,8 +688,9 @@ void ID3v2::Tag::parse(const ByteVector &origData)
// portion of the frame data.
if(data.at(frameDataPosition) == 0) {
if(d->header.footerPresent())
if(d->header.footerPresent()) {
debug("Padding *and* a footer found. This is not allowed by the spec.");
}
d->paddingSize = frameDataLength - frameDataPosition;
return;

View File

@@ -57,6 +57,36 @@ namespace TagLib {
typedef List<Frame *> FrameList;
typedef Map<ByteVector, FrameList> FrameListMap;
//! An abstraction for the ISO-8859-1 string to data encoding in ID3v2 tags.
/*!
* ID3v2 tag can store strings in ISO-8859-1 (Latin1), and TagLib only
* supports genuine ISO-8859-1 by default. However, in practice, non
* ISO-8859-1 encodings are often used instead of ISO-8859-1, such as
* Windows-1252 for western languages, Shift_JIS for Japanese and so on.
*
* Here is an option to read such tags by subclassing this class,
* reimplementing parse() and setting your reimplementation as the default
* with ID3v2::Tag::setStringHandler().
*
* \note Writing non-ISO-8859-1 tags is not implemented intentionally.
* Use UTF-16 or UTF-8 instead.
*
* \see ID3v2::Tag::setStringHandler()
*/
class TAGLIB_EXPORT Latin1StringHandler
{
public:
Latin1StringHandler();
virtual ~Latin1StringHandler();
/*!
* Decode a string from \a data. The default implementation assumes that
* \a data is an ISO-8859-1 (Latin1) character array.
*/
virtual String parse(const ByteVector &data) const;
};
//! The main class in the ID3v2 implementation
/*!
@@ -323,6 +353,27 @@ namespace TagLib {
*/
// BIC: combine with the above method
ByteVector render(int version) const;
/*!
* Gets the current string handler that decides how the "Latin-1" data
* will be converted to and from binary data.
*
* \see Latin1StringHandler
*/
static Latin1StringHandler const *latin1StringHandler();
/*!
* Sets the string handler that decides how the "Latin-1" 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 Latin1StringHandler
*/
static void setLatin1StringHandler(const Latin1StringHandler *handler);
protected:
/*!

View File

@@ -156,16 +156,13 @@ void MPEG::File::removeUnsupportedProperties(const StringList &properties)
else if(d->hasID3v1)
d->tag.access<ID3v1::Tag>(ID3v1Index, false)->removeUnsupportedProperties(properties);
}
PropertyMap MPEG::File::setProperties(const PropertyMap &properties)
{
if(d->hasID3v2)
return d->tag.access<ID3v2::Tag>(ID3v2Index, false)->setProperties(properties);
else if(d->hasAPE)
return d->tag.access<APE::Tag>(APEIndex, false)->setProperties(properties);
else if(d->hasID3v1)
return d->tag.access<ID3v1::Tag>(ID3v1Index, false)->setProperties(properties);
else
return d->tag.access<ID3v2::Tag>(ID3v2Index, true)->setProperties(properties);
if(d->hasID3v1)
// update ID3v1 tag if it exists, but ignore the return value
d->tag.access<ID3v1::Tag>(ID3v1Index, false)->setProperties(properties);
return d->tag.access<ID3v2::Tag>(ID3v2Index, true)->setProperties(properties);
}
MPEG::Properties *MPEG::File::audioProperties() const
@@ -189,6 +186,11 @@ bool MPEG::File::save(int tags, bool stripOthers)
}
bool MPEG::File::save(int tags, bool stripOthers, int id3v2Version)
{
return save(tags, stripOthers, id3v2Version, true);
}
bool MPEG::File::save(int tags, bool stripOthers, int id3v2Version, bool duplicateTags)
{
if(tags == NoTags && stripOthers)
return strip(AllTags);
@@ -206,14 +208,19 @@ bool MPEG::File::save(int tags, bool stripOthers, int id3v2Version)
return false;
}
// Create the tags if we've been asked to. Copy the values from the tag that
// does exist into the new tag, except if the existing tag is to be stripped.
// Create the tags if we've been asked to.
if((tags & ID3v2) && ID3v1Tag() && !(stripOthers && !(tags & ID3v1)))
Tag::duplicate(ID3v1Tag(), ID3v2Tag(true), false);
if (duplicateTags) {
if((tags & ID3v1) && d->tag[ID3v2Index] && !(stripOthers && !(tags & ID3v2)))
Tag::duplicate(ID3v2Tag(), ID3v1Tag(true), false);
// Copy the values from the tag that does exist into the new tag,
// except if the existing tag is to be stripped.
if((tags & ID3v2) && ID3v1Tag() && !(stripOthers && !(tags & ID3v1)))
Tag::duplicate(ID3v1Tag(), ID3v2Tag(true), false);
if((tags & ID3v1) && d->tag[ID3v2Index] && !(stripOthers && !(tags & ID3v2)))
Tag::duplicate(ID3v2Tag(), ID3v1Tag(true), false);
}
bool success = true;
@@ -437,6 +444,21 @@ long MPEG::File::lastFrameOffset()
return previousFrameOffset(ID3v1Tag() ? d->ID3v1Location - 1 : length());
}
bool MPEG::File::hasID3v1Tag() const
{
return d->hasID3v1;
}
bool MPEG::File::hasID3v2Tag() const
{
return d->hasID3v2;
}
bool MPEG::File::hasAPETag() const
{
return d->hasAPE;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
@@ -634,9 +656,6 @@ void MPEG::File::findAPE()
bool MPEG::File::secondSynchByte(char byte)
{
if(uchar(byte) == 0xff)
return false;
std::bitset<8> b(byte);
// check to see if the byte matches 111xxxxx

View File

@@ -71,9 +71,10 @@ namespace TagLib {
};
/*!
* Contructs an MPEG 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 MPEG 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.
@@ -82,25 +83,31 @@ namespace TagLib {
Properties::ReadStyle propertiesStyle = Properties::Average);
/*!
* Contructs an MPEG 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. The frames will be created using
* Constructs an MPEG 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.
*
* \deprecated This constructor will be dropped in favor of the one below
* in a future version.
* \note In the current implementation, \a propertiesStyle is ignored.
*/
// BIC: merge with the above constructor
File(FileName file, ID3v2::FrameFactory *frameFactory,
bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
/*!
* Contructs an MPEG 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. The frames will be created using
* Constructs an MPEG 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,
bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
@@ -130,7 +137,7 @@ namespace TagLib {
virtual Tag *tag() const;
/*!
* Implements the unified property interface -- export function.
* Implements the reading part of the unified property interface.
* If the file contains more than one tag, only the
* first one (in the order ID3v2, APE, ID3v1) will be converted to the
* PropertyMap.
@@ -140,9 +147,12 @@ namespace TagLib {
void removeUnsupportedProperties(const StringList &properties);
/*!
* Implements the unified tag dictionary interface -- import function.
* As with the export, only one tag is taken into account. If the file
* has no tag at all, ID3v2 will be created.
* Implements the writing part of the unified tag dictionary interface.
* In order to avoid problems with deprecated tag formats, this method
* always creates an ID3v2 tag if necessary.
* If an ID3v1 tag exists, it will be updated as well, within the
* limitations of that format.
* The returned PropertyMap refers to the ID3v2 tag only.
*/
PropertyMap setProperties(const PropertyMap &);
@@ -207,42 +217,78 @@ namespace TagLib {
// BIC: combine with the above method
bool save(int tags, bool stripOthers, int id3v2Version);
/*!
* Save the file. This will attempt to save all of the tag types that are
* specified by OR-ing together TagTypes values. The save() method above
* uses AllTags. This returns true if saving was successful.
*
* If \a stripOthers is true this strips all tags not included in the mask,
* but does not modify them in memory, so later calls to save() which make
* use of these tags will remain valid. This also strips empty tags.
*
* The \a id3v2Version parameter specifies the version of the saved
* ID3v2 tag. It can be either 4 or 3.
*
* If \a duplicateTags is true and at least one tag -- ID3v1 or ID3v2 --
* exists this will duplicate its content into the other tag.
*/
// BIC: combine with the above method
bool save(int tags, bool stripOthers, int id3v2Version, bool duplicateTags);
/*!
* Returns a pointer to the ID3v2 tag of the file.
*
* A tag will always be returned, regardless of whether there is a
* tag in the file or not. Use ID3v2::Tag::isEmpty() to check if
* the tag contains no data.
* If \a create is false (the default) this may return 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 and returns a valid pointer.
*
* \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.
*
* A tag will always be returned, regardless of whether there is a
* tag in the file or not. Use Tag::isEmpty() to check if
* the tag contains no data.
* 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 and returns a valid pointer.
*
* \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
* an APE tag if one does not exist.
* an APE tag 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 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);
@@ -298,6 +344,27 @@ namespace TagLib {
*/
long lastFrameOffset();
/*!
* 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;
/*!
* 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 &);

View File

@@ -28,6 +28,7 @@
#include <tbytevector.h>
#include <tstring.h>
#include <tdebug.h>
#include "trefcounter.h"
#include "mpegheader.h"

View File

@@ -221,7 +221,7 @@ void MPEG::Properties::read()
double length = timePerFrame * d->xingHeader->totalFrames();
d->length = int(length);
d->bitrate = d->length > 0 ? d->xingHeader->totalSize() * 8 / length / 1000 : 0;
d->bitrate = d->length > 0 ? (int)(d->xingHeader->totalSize() * 8 / length / 1000) : 0;
}
else {
// Since there was no valid Xing header found, we hope that we're in a constant

View File

@@ -108,8 +108,8 @@ void MPEG::XingHeader::parse(const ByteVector &data)
return;
}
d->frames = data.mid(8, 4).toUInt();
d->size = data.mid(12, 4).toUInt();
d->frames = data.toUInt(8U);
d->size = data.toUInt(12U);
d->valid = true;
}

View File

@@ -26,6 +26,7 @@
#include <tbytevector.h>
#include <tstring.h>
#include <tdebug.h>
#include <tpropertymap.h>
#include <xiphcomment.h>
#include "oggflacfile.h"
@@ -72,14 +73,16 @@ Ogg::FLAC::File::File(FileName file, bool readProperties,
Properties::ReadStyle propertiesStyle) : Ogg::File(file)
{
d = new FilePrivate;
read(readProperties, propertiesStyle);
if(isOpen())
read(readProperties, propertiesStyle);
}
Ogg::FLAC::File::File(IOStream *stream, bool readProperties,
Properties::ReadStyle propertiesStyle) : Ogg::File(stream)
{
d = new FilePrivate;
read(readProperties, propertiesStyle);
if(isOpen())
read(readProperties, propertiesStyle);
}
Ogg::FLAC::File::~File()
@@ -92,6 +95,16 @@ Ogg::XiphComment *Ogg::FLAC::File::tag() const
return d->comment;
}
PropertyMap Ogg::FLAC::File::properties() const
{
return d->comment->properties();
}
PropertyMap Ogg::FLAC::File::setProperties(const PropertyMap &properties)
{
return d->comment->setProperties(properties);
}
Properties *Ogg::FLAC::File::audioProperties() const
{
return d->properties;
@@ -124,6 +137,11 @@ bool Ogg::FLAC::File::save()
return Ogg::File::save();
}
bool Ogg::FLAC::File::hasXiphComment() const
{
return d->hasXiphComment;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
@@ -228,7 +246,7 @@ void Ogg::FLAC::File::scan()
char blockType = header[0] & 0x7f;
bool lastBlock = (header[0] & 0x80) != 0;
uint length = header.mid(1, 3).toUInt();
uint length = header.toUInt(1, 3, true);
overhead += length;
// Sanity: First block should be the stream_info metadata
@@ -238,7 +256,7 @@ void Ogg::FLAC::File::scan()
return;
}
d->streamInfoData = metadataHeader.mid(4,length);
d->streamInfoData = metadataHeader.mid(4, length);
// Search through the remaining metadata
@@ -251,7 +269,7 @@ void Ogg::FLAC::File::scan()
header = metadataHeader.mid(0, 4);
blockType = header[0] & 0x7f;
lastBlock = (header[0] & 0x80) != 0;
length = header.mid(1, 3).toUInt();
length = header.toUInt(1, 3, true);
overhead += length;
if(blockType == 1) {
@@ -263,9 +281,9 @@ void Ogg::FLAC::File::scan()
d->hasXiphComment = true;
d->commentPacket = ipacket;
}
else if(blockType > 5)
else if(blockType > 5) {
debug("Ogg::FLAC::File::scan() -- Unknown metadata block");
}
}
// End of metadata, now comes the datastream

View File

@@ -64,17 +64,22 @@ namespace TagLib {
{
public:
/*!
* Contructs an Ogg/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 Ogg/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.
*/
File(FileName file, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
/*!
* Contructs an Ogg/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 Ogg/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.
*
* \note In the current implementation, \a propertiesStyle is ignored.
*/
File(IOStream *stream, bool readProperties = true,
Properties::ReadStyle propertiesStyle = Properties::Average);
@@ -86,6 +91,16 @@ namespace TagLib {
/*!
* Returns the Tag for this file. This will always be a XiphComment.
*
* \note This always returns 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()
*/
virtual XiphComment *tag() const;
@@ -95,6 +110,20 @@ namespace TagLib {
*/
virtual Properties *audioProperties() const;
/*!
* Implements the unified property interface -- export function.
* This forwards directly to XiphComment::properties().
*/
PropertyMap properties() const;
/*!
* Implements the unified tag dictionary interface -- import function.
* Like properties(), this is a forwarder to the file's XiphComment.
*/
PropertyMap setProperties(const PropertyMap &);
/*!
* Save the file. This will primarily save and update the XiphComment.
* Returns true if the save is successful.
@@ -107,6 +136,13 @@ namespace TagLib {
*/
long streamLength();
/*!
* Returns whether or not the file on disk actually has a XiphComment.
*
* \see tag()
*/
bool hasXiphComment() const;
private:
File(const File &);
File &operator=(const File &);

View File

@@ -82,9 +82,7 @@ namespace TagLib {
protected:
/*!
* Contructs an Ogg 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 Ogg file from \a file.
*
* \note This constructor is protected since Ogg::File shouldn't be
* instantiated directly but rather should be used through the codec
@@ -93,13 +91,14 @@ namespace TagLib {
File(FileName file);
/*!
* Contructs an Ogg 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 Ogg file from \a stream.
*
* \note This constructor is protected since Ogg::File shouldn't be
* instantiated directly but rather should be used through the codec
* specific subclasses.
*
* \note TagLib will *not* take ownership of the stream, the caller is
* responsible for deleting it after the File object.
*/
File(IOStream *stream);

View File

@@ -255,9 +255,9 @@ void Ogg::PageHeader::read()
d->firstPageOfStream = flags.test(1);
d->lastPageOfStream = flags.test(2);
d->absoluteGranularPosition = data.mid(6, 8).toLongLong(false);
d->streamSerialNumber = data.mid(14, 4).toUInt(false);
d->pageSequenceNumber = data.mid(18, 4).toUInt(false);
d->absoluteGranularPosition = data.toLongLong(6, false);
d->streamSerialNumber = data.toUInt(14, false);
d->pageSequenceNumber = data.toUInt(18, false);
// Byte number 27 is the number of page segments, which is the only variable
// length portion of the page header. After reading the number of page

View File

@@ -0,0 +1,139 @@
/***************************************************************************
copyright : (C) 2012 by Lukáš Lalinský
email : lalinsky@gmail.com
copyright : (C) 2002 - 2008 by Scott Wheeler
email : wheeler@kde.org
(original Vorbis implementation)
***************************************************************************/
/***************************************************************************
* 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 <bitset>
#include <tstring.h>
#include <tdebug.h>
#include <tpropertymap.h>
#include "opusfile.h"
using namespace TagLib;
using namespace TagLib::Ogg;
class Opus::File::FilePrivate
{
public:
FilePrivate() :
comment(0),
properties(0) {}
~FilePrivate()
{
delete comment;
delete properties;
}
Ogg::XiphComment *comment;
Properties *properties;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
Opus::File::File(FileName file, bool readProperties, Properties::ReadStyle propertiesStyle) :
Ogg::File(file),
d(new FilePrivate())
{
if(isOpen())
read(readProperties, propertiesStyle);
}
Opus::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle propertiesStyle) :
Ogg::File(stream),
d(new FilePrivate())
{
if(isOpen())
read(readProperties, propertiesStyle);
}
Opus::File::~File()
{
delete d;
}
Ogg::XiphComment *Opus::File::tag() const
{
return d->comment;
}
PropertyMap Opus::File::properties() const
{
return d->comment->properties();
}
PropertyMap Opus::File::setProperties(const PropertyMap &properties)
{
return d->comment->setProperties(properties);
}
Opus::Properties *Opus::File::audioProperties() const
{
return d->properties;
}
bool Opus::File::save()
{
if(!d->comment)
d->comment = new Ogg::XiphComment;
setPacket(1, ByteVector("OpusTags", 8) + d->comment->render(false));
return Ogg::File::save();
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void Opus::File::read(bool readProperties, Properties::ReadStyle propertiesStyle)
{
ByteVector opusHeaderData = packet(0);
if(!opusHeaderData.startsWith("OpusHead")) {
setValid(false);
debug("Opus::File::read() -- invalid Opus identification header");
return;
}
ByteVector commentHeaderData = packet(1);
if(!commentHeaderData.startsWith("OpusTags")) {
setValid(false);
debug("Opus::File::read() -- invalid Opus tags header");
return;
}
d->comment = new Ogg::XiphComment(commentHeaderData.mid(8));
if(readProperties)
d->properties = new Properties(this, propertiesStyle);
}

124
taglib/ogg/opus/opusfile.h Normal file
View File

@@ -0,0 +1,124 @@
/***************************************************************************
copyright : (C) 2012 by Lukáš Lalinský
email : lalinsky@gmail.com
copyright : (C) 2002 - 2008 by Scott Wheeler
email : wheeler@kde.org
(original Vorbis implementation)
***************************************************************************/
/***************************************************************************
* 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_OPUSFILE_H
#define TAGLIB_OPUSFILE_H
#include "oggfile.h"
#include "xiphcomment.h"
#include "opusproperties.h"
namespace TagLib {
namespace Ogg {
//! A namespace containing classes for Opus metadata
namespace Opus {
//! An implementation of Ogg::File with Opus specific methods
/*!
* This is the central class in the Ogg Opus metadata processing collection
* of classes. It's built upon Ogg::File which handles processing of the Ogg
* logical bitstream and breaking it down into pages which are handled by
* the codec implementations, in this case Opus specifically.
*/
class TAGLIB_EXPORT File : public Ogg::File
{
public:
/*!
* Constructs an Opus 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);
/*!
* Constructs an Opus 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);
/*!
* Destroys this instance of the File.
*/
virtual ~File();
/*!
* Returns the XiphComment for this file. XiphComment implements the tag
* interface, so this serves as the reimplementation of
* TagLib::File::tag().
*/
virtual Ogg::XiphComment *tag() const;
/*!
* Implements the unified property interface -- export function.
* This forwards directly to XiphComment::properties().
*/
PropertyMap properties() const;
/*!
* Implements the unified tag dictionary interface -- import function.
* Like properties(), this is a forwarder to the file's XiphComment.
*/
PropertyMap setProperties(const PropertyMap &);
/*!
* Returns the Opus::Properties for this file. If no audio properties
* were read then this will return a null pointer.
*/
virtual Properties *audioProperties() const;
virtual bool save();
private:
File(const File &);
File &operator=(const File &);
void read(bool readProperties, Properties::ReadStyle propertiesStyle);
class FilePrivate;
FilePrivate *d;
};
}
}
}
#endif

View File

@@ -0,0 +1,161 @@
/***************************************************************************
copyright : (C) 2012 by Lukáš Lalinský
email : lalinsky@gmail.com
copyright : (C) 2002 - 2008 by Scott Wheeler
email : wheeler@kde.org
(original Vorbis implementation)
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <tstring.h>
#include <tdebug.h>
#include <oggpageheader.h>
#include "opusproperties.h"
#include "opusfile.h"
using namespace TagLib;
using namespace TagLib::Ogg;
class Opus::Properties::PropertiesPrivate
{
public:
PropertiesPrivate(File *f, ReadStyle s) :
file(f),
style(s),
length(0),
inputSampleRate(0),
channels(0),
opusVersion(0) {}
File *file;
ReadStyle style;
int length;
int inputSampleRate;
int channels;
int opusVersion;
};
////////////////////////////////////////////////////////////////////////////////
// public members
////////////////////////////////////////////////////////////////////////////////
Opus::Properties::Properties(File *file, ReadStyle style) : AudioProperties(style)
{
d = new PropertiesPrivate(file, style);
read();
}
Opus::Properties::~Properties()
{
delete d;
}
int Opus::Properties::length() const
{
return d->length;
}
int Opus::Properties::bitrate() const
{
return 0;
}
int Opus::Properties::sampleRate() const
{
// Opus can decode any stream at a sample rate of 8, 12, 16, 24, or 48 kHz,
// so there is no single sample rate. Let's assume it's the highest
// possible.
return 48000;
}
int Opus::Properties::channels() const
{
return d->channels;
}
int Opus::Properties::inputSampleRate() const
{
return d->inputSampleRate;
}
int Opus::Properties::opusVersion() const
{
return d->opusVersion;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////
void Opus::Properties::read()
{
// Get the identification header from the Ogg implementation.
// http://tools.ietf.org/html/draft-terriberry-oggopus-01#section-5.1
ByteVector data = d->file->packet(0);
// *Magic Signature*
uint pos = 8;
// *Version* (8 bits, unsigned)
d->opusVersion = uchar(data.at(pos));
pos += 1;
// *Output Channel Count* 'C' (8 bits, unsigned)
d->channels = uchar(data.at(pos));
pos += 1;
// *Pre-skip* (16 bits, unsigned, little endian)
const ushort preSkip = data.toUShort(pos, false);
pos += 2;
// *Input Sample Rate* (32 bits, unsigned, little endian)
d->inputSampleRate = data.toUInt(pos, false);
pos += 4;
// *Output Gain* (16 bits, signed, little endian)
pos += 2;
// *Channel Mapping Family* (8 bits, unsigned)
pos += 1;
const Ogg::PageHeader *first = d->file->firstPageHeader();
const Ogg::PageHeader *last = d->file->lastPageHeader();
if(first && last) {
long long start = first->absoluteGranularPosition();
long long end = last->absoluteGranularPosition();
if(start >= 0 && end >= 0)
d->length = (int) ((end - start - preSkip) / 48000);
else {
debug("Opus::Properties::read() -- The PCM values for the start or "
"end of this file was incorrect.");
}
}
else
debug("Opus::Properties::read() -- Could not find valid first and last Ogg pages.");
}

View File

@@ -0,0 +1,96 @@
/***************************************************************************
copyright : (C) 2012 by Lukáš Lalinský
email : lalinsky@gmail.com
copyright : (C) 2002 - 2008 by Scott Wheeler
email : wheeler@kde.org
(original Vorbis implementation)
***************************************************************************/
/***************************************************************************
* 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_OPUSPROPERTIES_H
#define TAGLIB_OPUSPROPERTIES_H
#include "audioproperties.h"
namespace TagLib {
namespace Ogg {
namespace Opus {
class File;
//! An implementation of audio property reading for Ogg Opus
/*!
* This reads the data from an Ogg Opus stream found in the AudioProperties
* API.
*/
class TAGLIB_EXPORT Properties : public AudioProperties
{
public:
/*!
* Create an instance of Opus::Properties with the data read from the
* Opus::File \a file.
*/
Properties(File *file, ReadStyle style = Average);
/*!
* Destroys this Opus::Properties instance.
*/
virtual ~Properties();
// Reimplementations.
virtual int length() const;
virtual int bitrate() const;
virtual int sampleRate() const;
virtual int channels() const;
/*!
* The Opus codec supports decoding at multiple sample rates, there is no
* single sample rate of the encoded stream. This returns the sample rate
* of the original audio stream.
*/
int inputSampleRate() const;
/*!
* Returns the Opus version, currently "0" (as specified by the spec).
*/
int opusVersion() const;
private:
Properties(const Properties &);
Properties &operator=(const Properties &);
void read();
class PropertiesPrivate;
PropertiesPrivate *d;
};
}
}
}
#endif

View File

@@ -31,6 +31,7 @@
#include <tstring.h>
#include <tdebug.h>
#include <tpropertymap.h>
#include "speexfile.h"
@@ -62,14 +63,16 @@ Speex::File::File(FileName file, bool readProperties,
Properties::ReadStyle propertiesStyle) : Ogg::File(file)
{
d = new FilePrivate;
read(readProperties, propertiesStyle);
if(isOpen())
read(readProperties, propertiesStyle);
}
Speex::File::File(IOStream *stream, bool readProperties,
Properties::ReadStyle propertiesStyle) : Ogg::File(stream)
{
d = new FilePrivate;
read(readProperties, propertiesStyle);
if(isOpen())
read(readProperties, propertiesStyle);
}
Speex::File::~File()
@@ -82,6 +85,16 @@ Ogg::XiphComment *Speex::File::tag() const
return d->comment;
}
PropertyMap Speex::File::properties() const
{
return d->comment->properties();
}
PropertyMap Speex::File::setProperties(const PropertyMap &properties)
{
return d->comment->setProperties(properties);
}
Speex::Properties *Speex::File::audioProperties() const
{
return d->properties;

View File

@@ -56,17 +56,22 @@ namespace TagLib {
{
public:
/*!
* Contructs a Speex 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 Speex 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 a Speex 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 Speex 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);
@@ -83,12 +88,26 @@ namespace TagLib {
*/
virtual Ogg::XiphComment *tag() const;
/*!
* Implements the unified property interface -- export function.
* This forwards directly to XiphComment::properties().
*/
PropertyMap properties() const;
/*!
* Implements the unified tag dictionary interface -- import function.
* Like properties(), this is a forwarder to the file's XiphComment.
*/
PropertyMap setProperties(const PropertyMap &);
/*!
* Returns the Speex::Properties for this file. If no audio properties
* were read then this will return a null pointer.
*/
virtual Properties *audioProperties() const;
virtual bool save();
private:

View File

@@ -113,32 +113,32 @@ void Speex::Properties::read()
ByteVector data = d->file->packet(0);
int pos = 28;
uint pos = 28;
// speex_version_id; /**< Version for Speex (for checking compatibility) */
d->speexVersion = data.mid(pos, 4).toUInt(false);
d->speexVersion = data.toUInt(pos, false);
pos += 4;
// header_size; /**< Total size of the header ( sizeof(SpeexHeader) ) */
pos += 4;
// rate; /**< Sampling rate used */
d->sampleRate = data.mid(pos, 4).toUInt(false);
d->sampleRate = data.toUInt(pos, false);
pos += 4;
// mode; /**< Mode used (0 for narrowband, 1 for wideband) */
d->mode = data.mid(pos, 4).toUInt(false);
d->mode = data.toUInt(pos, false);
pos += 4;
// mode_bitstream_version; /**< Version ID of the bit-stream */
pos += 4;
// nb_channels; /**< Number of channels encoded */
d->channels = data.mid(pos, 4).toUInt(false);
d->channels = data.toUInt(pos, false);
pos += 4;
// bitrate; /**< Bit-rate used */
d->bitrate = data.mid(pos, 4).toUInt(false);
d->bitrate = data.toUInt(pos, false);
pos += 4;
// frame_size; /**< Size of frames */
@@ -146,7 +146,7 @@ void Speex::Properties::read()
pos += 4;
// vbr; /**< 1 for a VBR encoding, 0 otherwise */
d->vbr = data.mid(pos, 4).toUInt(false) == 1;
d->vbr = data.toUInt(pos, false) == 1;
pos += 4;
// frames_per_packet; /**< Number of frames stored per Ogg packet */

View File

@@ -67,14 +67,16 @@ Vorbis::File::File(FileName file, bool readProperties,
Properties::ReadStyle propertiesStyle) : Ogg::File(file)
{
d = new FilePrivate;
read(readProperties, propertiesStyle);
if(isOpen())
read(readProperties, propertiesStyle);
}
Vorbis::File::File(IOStream *stream, bool readProperties,
Properties::ReadStyle propertiesStyle) : Ogg::File(stream)
{
d = new FilePrivate;
read(readProperties, propertiesStyle);
if(isOpen())
read(readProperties, propertiesStyle);
}
Vorbis::File::~File()

View File

@@ -63,17 +63,22 @@ namespace TagLib {
{
public:
/*!
* Contructs a Vorbis 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 Vorbis 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 a Vorbis 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 Vorbis 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);

View File

@@ -133,7 +133,7 @@ void Vorbis::Properties::read()
ByteVector data = d->file->packet(0);
int pos = 0;
uint pos = 0;
if(data.mid(pos, 7) != vorbisSetupHeaderID) {
debug("Vorbis::Properties::read() -- invalid Vorbis identification header");
@@ -142,22 +142,22 @@ void Vorbis::Properties::read()
pos += 7;
d->vorbisVersion = data.mid(pos, 4).toUInt(false);
d->vorbisVersion = data.toUInt(pos, false);
pos += 4;
d->channels = uchar(data[pos]);
pos += 1;
d->sampleRate = data.mid(pos, 4).toUInt(false);
d->sampleRate = data.toUInt(pos, false);
pos += 4;
d->bitrateMaximum = data.mid(pos, 4).toUInt(false);
d->bitrateMaximum = data.toUInt(pos, false);
pos += 4;
d->bitrateNominal = data.mid(pos, 4).toUInt(false);
d->bitrateNominal = data.toUInt(pos, false);
pos += 4;
d->bitrateMinimum = data.mid(pos, 4).toUInt(false);
d->bitrateMinimum = data.toUInt(pos, false);
// TODO: Later this should be only the "fast" mode.
d->bitrate = d->bitrateNominal;
@@ -173,7 +173,7 @@ void Vorbis::Properties::read()
long long end = last->absoluteGranularPosition();
if(start >= 0 && end >= 0 && d->sampleRate > 0)
d->length = (end - start) / (long long) d->sampleRate;
d->length = (int)((end - start) / (long long) d->sampleRate);
else
debug("Vorbis::Properties::read() -- Either the PCM values for the start or "
"end of this file was incorrect or the sample rate is zero.");

View File

@@ -205,11 +205,14 @@ PropertyMap Ogg::XiphComment::setProperties(const PropertyMap &properties)
for(StringList::ConstIterator it = toRemove.begin(); it != toRemove.end(); ++it)
removeField(*it);
// now go through keys in \a properties and check that the values match those in the xiph comment */
// now go through keys in \a properties and check that the values match those in the xiph comment
PropertyMap invalid;
PropertyMap::ConstIterator it = properties.begin();
for(; it != properties.end(); ++it)
{
if(!d->fieldListMap.contains(it->first) || !(it->second == d->fieldListMap[it->first])) {
if(!checkKey(it->first))
invalid.insert(it->first, it->second);
else if(!d->fieldListMap.contains(it->first) || !(it->second == d->fieldListMap[it->first])) {
const StringList &sl = it->second;
if(sl.size() == 0)
// zero size string list -> remove the tag with all values
@@ -224,7 +227,18 @@ PropertyMap Ogg::XiphComment::setProperties(const PropertyMap &properties)
}
}
}
return PropertyMap();
return invalid;
}
bool Ogg::XiphComment::checkKey(const String &key)
{
if(key.size() < 1)
return false;
for(String::ConstIterator it = key.begin(); it != key.end(); it++)
// forbid non-printable, non-ascii, '=' (#61) and '~' (#126)
if (*it < 32 || *it >= 128 || *it == 61 || *it == 126)
return false;
return true;
}
String Ogg::XiphComment::vendorID() const
@@ -326,7 +340,7 @@ void Ogg::XiphComment::parse(const ByteVector &data)
uint pos = 0;
uint vendorLength = data.mid(0, 4).toUInt(false);
const uint vendorLength = data.toUInt(0, false);
pos += 4;
d->vendorID = String(data.mid(pos, vendorLength), String::UTF8);
@@ -334,7 +348,7 @@ void Ogg::XiphComment::parse(const ByteVector &data)
// Next the number of fields in the comment vector.
uint commentFields = data.mid(pos, 4).toUInt(false);
const uint commentFields = data.toUInt(pos, false);
pos += 4;
if(commentFields > (data.size() - 8) / 4) {
@@ -346,7 +360,7 @@ void Ogg::XiphComment::parse(const ByteVector &data)
// Each comment field is in the format "KEY=value" in a UTF8 string and has
// 4 bytes before the text starts that gives the length.
uint commentLength = data.mid(pos, 4).toUInt(false);
const uint commentLength = data.toUInt(pos, false);
pos += 4;
String comment = String(data.mid(pos, commentLength), String::UTF8);

View File

@@ -151,10 +151,18 @@ namespace TagLib {
/*!
* Implements the unified property interface -- import function.
* The tags from the given map will be stored one-to-one in the file.
* The tags from the given map will be stored one-to-one in the file,
* except for invalid keys (less than one character, non-ASCII, or
* containing '=' or '~') in which case the according values will
* be contained in the returned PropertyMap.
*/
PropertyMap setProperties(const PropertyMap&);
/*!
* Check if the given String is a valid Xiph comment key.
*/
static bool checkKey(const String&);
/*!
* Returns the vendor ID of the Ogg Vorbis encoder. libvorbis 1.0 as the
* most common case always returns "Xiph.Org libVorbis I 20020717".

View File

@@ -90,6 +90,11 @@ PropertyMap RIFF::AIFF::File::properties() const
return d->tag->properties();
}
void RIFF::AIFF::File::removeUnsupportedProperties(const StringList &unsupported)
{
d->tag->removeUnsupportedProperties(unsupported);
}
PropertyMap RIFF::AIFF::File::setProperties(const PropertyMap &properties)
{
return d->tag->setProperties(properties);
@@ -118,6 +123,7 @@ bool RIFF::AIFF::File::save()
return true;
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////

View File

@@ -58,17 +58,22 @@ namespace TagLib {
{
public:
/*!
* Contructs an AIFF 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 AIFF 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 AIFF 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 AIFF 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);
@@ -80,6 +85,12 @@ namespace TagLib {
/*!
* Returns the Tag for this file.
*
* \note This always returns a valid pointer regardless of whether or not
* the file on disk has an ID3v2 tag. Use hasID3v2Tag() to check if the file
* on disk actually has an ID3v2 tag.
*
* \see hasID3v2Tag()
*/
virtual ID3v2::Tag *tag() const;
@@ -89,6 +100,8 @@ namespace TagLib {
*/
PropertyMap properties() const;
void removeUnsupportedProperties(const StringList &properties);
/*!
* Implements the unified property interface -- import function.
* This method forwards to ID3v2::Tag::setProperties().
@@ -106,6 +119,13 @@ namespace TagLib {
*/
virtual bool save();
/*!
* 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 &);

View File

@@ -39,7 +39,7 @@
#define UnsignedToFloat(u) (((double)((long)(u - 2147483647L - 1))) + 2147483648.0)
static double ConvertFromIeeeExtended(unsigned char *bytes)
static double ConvertFromIeeeExtended(const TagLib::uchar *bytes)
{
double f;
int expon;
@@ -139,7 +139,7 @@ int RIFF::AIFF::Properties::sampleWidth() const
return d->sampleWidth;
}
uint RIFF::AIFF::Properties::sampleFrames() const
TagLib::uint RIFF::AIFF::Properties::sampleFrames() const
{
return d->sampleFrames;
}
@@ -150,11 +150,11 @@ uint RIFF::AIFF::Properties::sampleFrames() const
void RIFF::AIFF::Properties::read(const ByteVector &data)
{
d->channels = data.mid(0, 2).toShort();
d->sampleFrames = data.mid(2, 4).toUInt();
d->sampleWidth = data.mid(6, 2).toShort();
double sampleRate = ConvertFromIeeeExtended(reinterpret_cast<unsigned char *>(data.mid(8, 10).data()));
d->sampleRate = sampleRate;
d->bitrate = (sampleRate * d->sampleWidth * d->channels) / 1000.0;
d->channels = data.toShort(0U);
d->sampleFrames = data.toUInt(2U);
d->sampleWidth = data.toShort(6U);
double sampleRate = ConvertFromIeeeExtended(reinterpret_cast<const uchar *>(data.data() + 8));
d->sampleRate = (int)sampleRate;
d->bitrate = (int)((sampleRate * d->sampleWidth * d->channels) / 1000.0);
d->length = d->sampleRate > 0 ? d->sampleFrames / d->sampleRate : 0;
}

View File

@@ -28,6 +28,7 @@
#include <tstring.h>
#include "rifffile.h"
#include <algorithm>
#include <vector>
using namespace TagLib;
@@ -138,34 +139,49 @@ ByteVector RIFF::File::chunkData(uint i)
return readBlock(d->chunks[i].size);
}
void RIFF::File::setChunkData(uint i, const ByteVector &data)
{
// First we update the global size
d->size += ((data.size() + 1) & ~1) - (d->chunks[i].size + d->chunks[i].padding);
insert(ByteVector::fromUInt(d->size, d->endianness == BigEndian), 4, 4);
// Now update the specific chunk
writeChunk(chunkName(i), data, d->chunks[i].offset - 8, d->chunks[i].size + d->chunks[i].padding + 8);
d->chunks[i].size = data.size();
d->chunks[i].padding = (data.size() & 0x01) ? 1 : 0;
// Now update the internal offsets
for(i++; i < d->chunks.size(); i++)
d->chunks[i].offset = d->chunks[i-1].offset + 8 + d->chunks[i-1].size + d->chunks[i-1].padding;
}
void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data)
{
setChunkData(name, data, false);
}
void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data, bool alwaysCreate)
{
if(d->chunks.size() == 0) {
debug("RIFF::File::setChunkData - No valid chunks found.");
return;
}
for(uint i = 0; i < d->chunks.size(); i++) {
if(d->chunks[i].name == name) {
if(alwaysCreate && name != "LIST") {
debug("RIFF::File::setChunkData - alwaysCreate should be used for only \"LIST\" chunks.");
return;
}
// First we update the global size
d->size += ((data.size() + 1) & ~1) - (d->chunks[i].size + d->chunks[i].padding);
insert(ByteVector::fromUInt(d->size, d->endianness == BigEndian), 4, 4);
// Now update the specific chunk
writeChunk(name, data, d->chunks[i].offset - 8, d->chunks[i].size + d->chunks[i].padding + 8);
d->chunks[i].size = data.size();
d->chunks[i].padding = (data.size() & 0x01) ? 1 : 0;
// Now update the internal offsets
for(i++; i < d->chunks.size(); i++)
d->chunks[i].offset = d->chunks[i-1].offset + 8 + d->chunks[i-1].size + d->chunks[i-1].padding;
return;
if(!alwaysCreate) {
for(uint i = 0; i < d->chunks.size(); i++) {
if(d->chunks[i].name == name) {
setChunkData(i, data);
return;
}
}
}
@@ -181,7 +197,7 @@ void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data)
// Now add the chunk to the file
writeChunk(name, data, offset, std::max(ulong(0), length() - offset), (offset & 1) ? 1 : 0);
writeChunk(name, data, offset, std::max<long>(0, length() - offset), (offset & 1) ? 1 : 0);
// And update our internal structure
@@ -199,6 +215,28 @@ void RIFF::File::setChunkData(const ByteVector &name, const ByteVector &data)
d->chunks.push_back(chunk);
}
void RIFF::File::removeChunk(uint i)
{
if(i >= d->chunks.size())
return;
removeBlock(d->chunks[i].offset - 8, d->chunks[i].size + 8);
d->chunks.erase(d->chunks.begin() + i);
}
void RIFF::File::removeChunk(const ByteVector &name)
{
std::vector<Chunk> newChunks;
for(size_t i = 0; i < d->chunks.size(); ++i) {
if(d->chunks[i].name == name)
removeBlock(d->chunks[i].offset - 8, d->chunks[i].size + 8);
else
newChunks.push_back(d->chunks[i]);
}
d->chunks.swap(newChunks);
}
////////////////////////////////////////////////////////////////////////////////
// private members
////////////////////////////////////////////////////////////////////////////////

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