From ea24699b37768c9df2455e0bc638251497c5f5f3 Mon Sep 17 00:00:00 2001 From: Herwig Birke Date: Tue, 20 Feb 2018 11:00:17 +0100 Subject: [PATCH] . --- cmainwindow.cpp | 4 +- cmediainfo.cpp | 190 +- cmediainfo.h | 30 +- qtJukeBox.pro | 6 +- taglib/AUTHORS | 17 - taglib/CMakeLists.txt | 120 - taglib/COPYING.LGPL | 502 ---- taglib/COPYING.MPL | 470 ---- taglib/ConfigureChecks.cmake | 226 -- taglib/Doxyfile.cmake | 210 -- taglib/INSTALL | 157 -- taglib/NEWS | 189 -- taglib/bindings/CMakeLists.txt | 1 - taglib/bindings/README | 6 - taglib/bindings/c/CMakeLists.txt | 68 - taglib/bindings/c/tag_c.cpp | 290 --- taglib/bindings/c/tag_c.h | 299 --- taglib/bindings/c/taglib_c.pc.cmake | 12 - taglib/cmake/modules/FindCppUnit.cmake | 69 - taglib/cmake/modules/MacroEnsureVersion.cmake | 71 - taglib/cmake_uninstall.cmake.in | 21 - taglib/config.h.cmake | 37 - taglib/doc/README | 1 - taglib/doc/api-footer.html | 4 - taglib/doc/api-header.html | 41 - taglib/doc/taglib-api.css | 395 ---- taglib/doc/taglib.png | Bin 2748 -> 0 bytes taglib/examples/CMakeLists.txt | 50 - taglib/examples/framelist.cpp | 109 - taglib/examples/strip-id3v1.cpp | 40 - taglib/examples/tagreader.cpp | 96 - taglib/examples/tagreader_c.c | 81 - taglib/examples/tagwriter.cpp | 139 -- taglib/taglib-config.cmake | 55 - taglib/taglib-config.cmd.cmake | 36 - taglib/taglib.pc.cmake | 11 - taglib/taglib/CMakeLists.txt | 335 --- taglib/taglib/ape/ape-tag-format.txt | 170 -- taglib/taglib/ape/apefile.cpp | 314 --- taglib/taglib/ape/apefile.h | 229 -- taglib/taglib/ape/apefooter.cpp | 236 -- taglib/taglib/ape/apefooter.h | 173 -- taglib/taglib/ape/apeitem.cpp | 286 --- taglib/taglib/ape/apeitem.h | 219 -- taglib/taglib/ape/apeproperties.cpp | 232 -- taglib/taglib/ape/apeproperties.h | 99 - taglib/taglib/ape/apetag.cpp | 383 ---- taglib/taglib/ape/apetag.h | 208 -- taglib/taglib/asf/asfattribute.cpp | 350 --- taglib/taglib/asf/asfattribute.h | 203 -- taglib/taglib/asf/asffile.cpp | 630 ----- taglib/taglib/asf/asffile.h | 148 -- taglib/taglib/asf/asfpicture.cpp | 179 -- taglib/taglib/asf/asfpicture.h | 217 -- taglib/taglib/asf/asfproperties.cpp | 111 - taglib/taglib/asf/asfproperties.h | 76 - taglib/taglib/asf/asftag.cpp | 354 --- taglib/taglib/asf/asftag.h | 190 -- taglib/taglib/audioproperties.cpp | 51 - taglib/taglib/audioproperties.h | 110 - taglib/taglib/fileref.cpp | 286 --- taglib/taglib/fileref.h | 263 --- taglib/taglib/flac/flacfile.cpp | 568 ----- taglib/taglib/flac/flacfile.h | 305 --- taglib/taglib/flac/flacmetadatablock.cpp | 47 - taglib/taglib/flac/flacmetadatablock.h | 75 - taglib/taglib/flac/flacpicture.cpp | 217 -- taglib/taglib/flac/flacpicture.h | 208 -- taglib/taglib/flac/flacproperties.cpp | 169 -- taglib/taglib/flac/flacproperties.h | 103 - .../taglib/flac/flacunknownmetadatablock.cpp | 79 - taglib/taglib/flac/flacunknownmetadatablock.h | 81 - taglib/taglib/it/itfile.cpp | 330 --- taglib/taglib/it/itfile.h | 109 - taglib/taglib/it/itproperties.cpp | 245 -- taglib/taglib/it/itproperties.h | 101 - taglib/taglib/mod/modfile.cpp | 187 -- taglib/taglib/mod/modfile.h | 110 - taglib/taglib/mod/modfilebase.cpp | 120 - taglib/taglib/mod/modfilebase.h | 62 - taglib/taglib/mod/modfileprivate.h | 67 - taglib/taglib/mod/modproperties.cpp | 96 - taglib/taglib/mod/modproperties.h | 65 - taglib/taglib/mod/modtag.cpp | 168 -- taglib/taglib/mod/modtag.h | 190 -- taglib/taglib/mp4/mp4atom.cpp | 194 -- taglib/taglib/mp4/mp4atom.h | 111 - taglib/taglib/mp4/mp4coverart.cpp | 83 - taglib/taglib/mp4/mp4coverart.h | 75 - taglib/taglib/mp4/mp4file.cpp | 163 -- taglib/taglib/mp4/mp4file.h | 130 -- taglib/taglib/mp4/mp4item.cpp | 206 -- taglib/taglib/mp4/mp4item.h | 83 - taglib/taglib/mp4/mp4properties.cpp | 199 -- taglib/taglib/mp4/mp4properties.h | 71 - taglib/taglib/mp4/mp4tag.cpp | 917 -------- taglib/taglib/mp4/mp4tag.h | 118 - taglib/taglib/mpc/mpcfile.cpp | 367 --- taglib/taglib/mpc/mpcfile.h | 231 -- taglib/taglib/mpc/mpcproperties.cpp | 316 --- taglib/taglib/mpc/mpcproperties.h | 122 - taglib/taglib/mpeg/id3v1/id3v1genres.cpp | 219 -- taglib/taglib/mpeg/id3v1/id3v1genres.h | 66 - taglib/taglib/mpeg/id3v1/id3v1tag.cpp | 265 --- taglib/taglib/mpeg/id3v1/id3v1tag.h | 202 -- .../id3v2/frames/attachedpictureframe.cpp | 222 -- .../mpeg/id3v2/frames/attachedpictureframe.h | 230 -- .../mpeg/id3v2/frames/commentsframe.cpp | 197 -- .../taglib/mpeg/id3v2/frames/commentsframe.h | 179 -- .../frames/generalencapsulatedobjectframe.cpp | 176 -- .../frames/generalencapsulatedobjectframe.h | 178 -- .../mpeg/id3v2/frames/ownershipframe.cpp | 162 -- .../taglib/mpeg/id3v2/frames/ownershipframe.h | 151 -- .../mpeg/id3v2/frames/popularimeterframe.cpp | 137 -- .../mpeg/id3v2/frames/popularimeterframe.h | 132 -- .../taglib/mpeg/id3v2/frames/privateframe.cpp | 128 -- .../taglib/mpeg/id3v2/frames/privateframe.h | 111 - .../mpeg/id3v2/frames/relativevolumeframe.cpp | 236 -- .../mpeg/id3v2/frames/relativevolumeframe.h | 274 --- .../id3v2/frames/textidentificationframe.cpp | 423 ---- .../id3v2/frames/textidentificationframe.h | 313 --- .../frames/uniquefileidentifierframe.cpp | 148 -- .../id3v2/frames/uniquefileidentifierframe.h | 123 - .../taglib/mpeg/id3v2/frames/unknownframe.cpp | 84 - .../taglib/mpeg/id3v2/frames/unknownframe.h | 79 - .../frames/unsynchronizedlyricsframe.cpp | 193 -- .../id3v2/frames/unsynchronizedlyricsframe.h | 179 -- .../taglib/mpeg/id3v2/frames/urllinkframe.cpp | 230 -- .../taglib/mpeg/id3v2/frames/urllinkframe.h | 189 -- taglib/taglib/mpeg/id3v2/id3v2.2.0.txt | 1660 -------------- taglib/taglib/mpeg/id3v2/id3v2.3.0.txt | 2022 ----------------- taglib/taglib/mpeg/id3v2/id3v2.4.0-frames.txt | 1734 -------------- .../taglib/mpeg/id3v2/id3v2.4.0-structure.txt | 733 ------ .../taglib/mpeg/id3v2/id3v2extendedheader.cpp | 71 - .../taglib/mpeg/id3v2/id3v2extendedheader.h | 93 - taglib/taglib/mpeg/id3v2/id3v2footer.cpp | 60 - taglib/taglib/mpeg/id3v2/id3v2footer.h | 82 - taglib/taglib/mpeg/id3v2/id3v2frame.cpp | 844 ------- taglib/taglib/mpeg/id3v2/id3v2frame.h | 518 ----- .../taglib/mpeg/id3v2/id3v2framefactory.cpp | 458 ---- taglib/taglib/mpeg/id3v2/id3v2framefactory.h | 166 -- taglib/taglib/mpeg/id3v2/id3v2header.cpp | 243 -- taglib/taglib/mpeg/id3v2/id3v2header.h | 175 -- taglib/taglib/mpeg/id3v2/id3v2synchdata.cpp | 84 - taglib/taglib/mpeg/id3v2/id3v2synchdata.h | 70 - taglib/taglib/mpeg/id3v2/id3v2tag.cpp | 732 ------ taglib/taglib/mpeg/id3v2/id3v2tag.h | 412 ---- taglib/taglib/mpeg/mpegfile.cpp | 663 ------ taglib/taglib/mpeg/mpegfile.h | 390 ---- taglib/taglib/mpeg/mpegheader.cpp | 277 --- taglib/taglib/mpeg/mpegheader.h | 166 -- taglib/taglib/mpeg/mpegproperties.cpp | 254 --- taglib/taglib/mpeg/mpegproperties.h | 118 - taglib/taglib/mpeg/xingheader.cpp | 115 - taglib/taglib/mpeg/xingheader.h | 100 - taglib/taglib/ogg/flac/oggflacfile.cpp | 294 --- taglib/taglib/ogg/flac/oggflacfile.h | 162 -- taglib/taglib/ogg/oggfile.cpp | 432 ---- taglib/taglib/ogg/oggfile.h | 122 - taglib/taglib/ogg/oggpage.cpp | 340 --- taglib/taglib/ogg/oggpage.h | 211 -- taglib/taglib/ogg/oggpageheader.cpp | 323 --- taglib/taglib/ogg/oggpageheader.h | 232 -- taglib/taglib/ogg/opus/opusfile.cpp | 139 -- taglib/taglib/ogg/opus/opusfile.h | 124 - taglib/taglib/ogg/opus/opusproperties.cpp | 161 -- taglib/taglib/ogg/opus/opusproperties.h | 96 - taglib/taglib/ogg/speex/speexfile.cpp | 132 -- taglib/taglib/ogg/speex/speexfile.h | 126 - taglib/taglib/ogg/speex/speexproperties.cpp | 170 -- taglib/taglib/ogg/speex/speexproperties.h | 89 - taglib/taglib/ogg/vorbis/vorbisfile.cpp | 138 -- taglib/taglib/ogg/vorbis/vorbisfile.h | 144 -- taglib/taglib/ogg/vorbis/vorbisproperties.cpp | 183 -- taglib/taglib/ogg/vorbis/vorbisproperties.h | 125 - taglib/taglib/ogg/xiphcomment.cpp | 382 ---- taglib/taglib/ogg/xiphcomment.h | 225 -- taglib/taglib/riff/aiff/aifffile.cpp | 144 -- taglib/taglib/riff/aiff/aifffile.h | 142 -- taglib/taglib/riff/aiff/aiffproperties.cpp | 160 -- taglib/taglib/riff/aiff/aiffproperties.h | 83 - taglib/taglib/riff/rifffile.cpp | 321 --- taglib/taglib/riff/rifffile.h | 157 -- taglib/taglib/riff/wav/infotag.cpp | 266 --- taglib/taglib/riff/wav/infotag.h | 192 -- taglib/taglib/riff/wav/wavfile.cpp | 244 -- taglib/taglib/riff/wav/wavfile.h | 189 -- taglib/taglib/riff/wav/wavproperties.cpp | 129 -- taglib/taglib/riff/wav/wavproperties.h | 92 - taglib/taglib/s3m/s3mfile.cpp | 243 -- taglib/taglib/s3m/s3mfile.h | 108 - taglib/taglib/s3m/s3mproperties.cpp | 204 -- taglib/taglib/s3m/s3mproperties.h | 88 - taglib/taglib/tag.cpp | 180 -- taglib/taglib/tag.h | 201 -- taglib/taglib/taglib_config.h.cmake | 4 - taglib/taglib/taglib_export.h | 43 - taglib/taglib/tagunion.cpp | 186 -- taglib/taglib/tagunion.h | 95 - taglib/taglib/toolkit/taglib.h | 170 -- taglib/taglib/toolkit/tbytevector.cpp | 857 ------- taglib/taglib/toolkit/tbytevector.h | 518 ----- taglib/taglib/toolkit/tbytevectorlist.cpp | 102 - taglib/taglib/toolkit/tbytevectorlist.h | 91 - taglib/taglib/toolkit/tbytevectorstream.cpp | 167 -- taglib/taglib/toolkit/tbytevectorstream.h | 145 -- taglib/taglib/toolkit/tdebug.cpp | 99 - taglib/taglib/toolkit/tdebug.h | 62 - taglib/taglib/toolkit/tdebuglistener.cpp | 85 - taglib/taglib/toolkit/tdebuglistener.h | 74 - taglib/taglib/toolkit/tfile.cpp | 503 ---- taglib/taglib/toolkit/tfile.h | 306 --- taglib/taglib/toolkit/tfilestream.cpp | 492 ---- taglib/taglib/toolkit/tfilestream.h | 154 -- taglib/taglib/toolkit/tiostream.cpp | 150 -- taglib/taglib/toolkit/tiostream.h | 169 -- taglib/taglib/toolkit/tlist.h | 257 --- taglib/taglib/toolkit/tlist.tcc | 324 --- taglib/taglib/toolkit/tmap.h | 199 -- taglib/taglib/toolkit/tmap.tcc | 199 -- taglib/taglib/toolkit/tpropertymap.cpp | 173 -- taglib/taglib/toolkit/tpropertymap.h | 233 -- taglib/taglib/toolkit/trefcounter.cpp | 108 - taglib/taglib/toolkit/trefcounter.h | 111 - taglib/taglib/toolkit/tstring.cpp | 880 ------- taglib/taglib/toolkit/tstring.h | 543 ----- taglib/taglib/toolkit/tstringlist.cpp | 123 - taglib/taglib/toolkit/tstringlist.h | 115 - taglib/taglib/toolkit/tutils.h | 190 -- taglib/taglib/toolkit/unicode.cpp | 303 --- taglib/taglib/toolkit/unicode.h | 154 -- taglib/taglib/trueaudio/trueaudiofile.cpp | 325 --- taglib/taglib/trueaudio/trueaudiofile.h | 252 -- .../taglib/trueaudio/trueaudioproperties.cpp | 150 -- taglib/taglib/trueaudio/trueaudioproperties.h | 98 - taglib/taglib/wavpack/wavpackfile.cpp | 311 --- taglib/taglib/wavpack/wavpackfile.h | 216 -- taglib/taglib/wavpack/wavpackproperties.cpp | 203 -- taglib/taglib/wavpack/wavpackproperties.h | 110 - taglib/taglib/xm/xmfile.cpp | 650 ------ taglib/taglib/xm/xmfile.h | 108 - taglib/taglib/xm/xmproperties.cpp | 180 -- taglib/taglib/xm/xmproperties.h | 79 - taglib/tests/CMakeLists.txt | 76 - taglib/tests/data/005411.id3 | Bin 38402 -> 0 bytes taglib/tests/data/64bit.mp4 | Bin 85 -> 0 bytes taglib/tests/data/broken-tenc.id3 | Bin 400 -> 0 bytes taglib/tests/data/changed.mod | Bin 3132 -> 0 bytes taglib/tests/data/changed.s3m | Bin 544 -> 0 bytes taglib/tests/data/changed.xm | Bin 5471 -> 0 bytes taglib/tests/data/click.mpc | Bin 1588 -> 0 bytes taglib/tests/data/click.wv | Bin 3176 -> 0 bytes taglib/tests/data/compressed_id3_frame.mp3 | Bin 5000 -> 0 bytes .../data/correctness_gain_silent_output.opus | Bin 35506 -> 0 bytes taglib/tests/data/covr-junk.m4a | Bin 5108 -> 0 bytes taglib/tests/data/empty.aiff | Bin 5936 -> 0 bytes taglib/tests/data/empty.ogg | Bin 4328 -> 0 bytes taglib/tests/data/empty.spx | Bin 24301 -> 0 bytes taglib/tests/data/empty.tta | Bin 79538 -> 0 bytes taglib/tests/data/empty.wav | Bin 14744 -> 0 bytes taglib/tests/data/empty_alac.m4a | Bin 5380 -> 0 bytes taglib/tests/data/empty_flac.oga | Bin 9113 -> 0 bytes taglib/tests/data/empty_vorbis.oga | Bin 4328 -> 0 bytes taglib/tests/data/gnre.m4a | Bin 5026 -> 0 bytes taglib/tests/data/has-tags.m4a | Bin 5108 -> 0 bytes taglib/tests/data/id3v22-tda.mp3 | Bin 8192 -> 0 bytes taglib/tests/data/ilst-is-last.m4a | Bin 32768 -> 0 bytes taglib/tests/data/mac-390-hdr.ape | Bin 128 -> 0 bytes taglib/tests/data/mac-396.ape | Bin 104 -> 0 bytes taglib/tests/data/mac-399.ape | Bin 172 -> 0 bytes taglib/tests/data/mpeg2.mp3 | Bin 16384 -> 0 bytes taglib/tests/data/multiple-vc.flac | Bin 4754 -> 0 bytes taglib/tests/data/no-extension | Bin 256 -> 0 bytes taglib/tests/data/no-tags.3g2 | Bin 68335 -> 0 bytes taglib/tests/data/no-tags.flac | Bin 4692 -> 0 bytes taglib/tests/data/no-tags.m4a | Bin 2898 -> 0 bytes taglib/tests/data/no_length.wv | Bin 532 -> 0 bytes taglib/tests/data/noise.aif | Bin 4400 -> 0 bytes taglib/tests/data/noise_odd.aif | Bin 4399 -> 0 bytes taglib/tests/data/rare_frames.mp3 | Bin 8320 -> 0 bytes taglib/tests/data/silence-1.wma | Bin 35416 -> 0 bytes taglib/tests/data/silence-44-s.flac | Bin 50904 -> 0 bytes taglib/tests/data/stripped.xm | Bin 602 -> 0 bytes taglib/tests/data/sv4_header.mpc | Bin 128 -> 0 bytes taglib/tests/data/sv5_header.mpc | Bin 128 -> 0 bytes taglib/tests/data/sv8_header.mpc | Bin 114 -> 0 bytes taglib/tests/data/test.it | Bin 644 -> 0 bytes taglib/tests/data/test.mod | Bin 3132 -> 0 bytes taglib/tests/data/test.ogg | Bin 4408 -> 0 bytes taglib/tests/data/test.s3m | Bin 544 -> 0 bytes taglib/tests/data/test.xm | Bin 5471 -> 0 bytes taglib/tests/data/unsupported-extension.xxx | Bin 256 -> 0 bytes taglib/tests/data/unsynch.id3 | Bin 320 -> 0 bytes taglib/tests/data/w000.mp3 | Bin 512 -> 0 bytes taglib/tests/data/xing.mp3 | Bin 8208 -> 0 bytes taglib/tests/data/zero-size-chunk.wav | Bin 1024 -> 0 bytes taglib/tests/main.cpp | 57 - taglib/tests/test_aiff.cpp | 31 - taglib/tests/test_ape.cpp | 52 - taglib/tests/test_apetag.cpp | 122 - taglib/tests/test_asf.cpp | 255 --- taglib/tests/test_bytevector.cpp | 246 -- taglib/tests/test_bytevectorlist.cpp | 38 - taglib/tests/test_bytevectorstream.cpp | 92 - taglib/tests/test_fileref.cpp | 163 -- taglib/tests/test_flac.cpp | 248 -- taglib/tests/test_flacpicture.cpp | 52 - .../tests/test_flacunknownmetadatablock.cpp | 38 - taglib/tests/test_id3v1.cpp | 40 - taglib/tests/test_id3v2.cpp | 758 ------ taglib/tests/test_info.cpp | 49 - taglib/tests/test_it.cpp | 136 -- taglib/tests/test_list.cpp | 58 - taglib/tests/test_map.cpp | 27 - taglib/tests/test_mod.cpp | 126 - taglib/tests/test_mp4.cpp | 282 --- taglib/tests/test_mp4coverart.cpp | 49 - taglib/tests/test_mp4item.cpp | 37 - taglib/tests/test_mpc.cpp | 66 - taglib/tests/test_mpeg.cpp | 88 - taglib/tests/test_ogg.cpp | 104 - taglib/tests/test_oggflac.cpp | 44 - taglib/tests/test_opus.cpp | 61 - taglib/tests/test_propertymap.cpp | 32 - taglib/tests/test_riff.cpp | 198 -- taglib/tests/test_s3m.cpp | 123 - taglib/tests/test_string.cpp | 233 -- taglib/tests/test_synchdata.cpp | 107 - taglib/tests/test_trueaudio.cpp | 27 - taglib/tests/test_wav.cpp | 36 - taglib/tests/test_wavpack.cpp | 40 - taglib/tests/test_xiphcomment.cpp | 79 - taglib/tests/test_xm.cpp | 216 -- taglib/tests/utils.h | 104 - 334 files changed, 117 insertions(+), 57691 deletions(-) delete mode 100644 taglib/AUTHORS delete mode 100644 taglib/CMakeLists.txt delete mode 100644 taglib/COPYING.LGPL delete mode 100644 taglib/COPYING.MPL delete mode 100644 taglib/ConfigureChecks.cmake delete mode 100644 taglib/Doxyfile.cmake delete mode 100644 taglib/INSTALL delete mode 100644 taglib/NEWS delete mode 100644 taglib/bindings/CMakeLists.txt delete mode 100644 taglib/bindings/README delete mode 100644 taglib/bindings/c/CMakeLists.txt delete mode 100644 taglib/bindings/c/tag_c.cpp delete mode 100644 taglib/bindings/c/tag_c.h delete mode 100644 taglib/bindings/c/taglib_c.pc.cmake delete mode 100644 taglib/cmake/modules/FindCppUnit.cmake delete mode 100644 taglib/cmake/modules/MacroEnsureVersion.cmake delete mode 100644 taglib/cmake_uninstall.cmake.in delete mode 100644 taglib/config.h.cmake delete mode 100644 taglib/doc/README delete mode 100644 taglib/doc/api-footer.html delete mode 100644 taglib/doc/api-header.html delete mode 100644 taglib/doc/taglib-api.css delete mode 100644 taglib/doc/taglib.png delete mode 100644 taglib/examples/CMakeLists.txt delete mode 100644 taglib/examples/framelist.cpp delete mode 100644 taglib/examples/strip-id3v1.cpp delete mode 100644 taglib/examples/tagreader.cpp delete mode 100644 taglib/examples/tagreader_c.c delete mode 100644 taglib/examples/tagwriter.cpp delete mode 100644 taglib/taglib-config.cmake delete mode 100644 taglib/taglib-config.cmd.cmake delete mode 100644 taglib/taglib.pc.cmake delete mode 100644 taglib/taglib/CMakeLists.txt delete mode 100644 taglib/taglib/ape/ape-tag-format.txt delete mode 100644 taglib/taglib/ape/apefile.cpp delete mode 100644 taglib/taglib/ape/apefile.h delete mode 100644 taglib/taglib/ape/apefooter.cpp delete mode 100644 taglib/taglib/ape/apefooter.h delete mode 100644 taglib/taglib/ape/apeitem.cpp delete mode 100644 taglib/taglib/ape/apeitem.h delete mode 100644 taglib/taglib/ape/apeproperties.cpp delete mode 100644 taglib/taglib/ape/apeproperties.h delete mode 100644 taglib/taglib/ape/apetag.cpp delete mode 100644 taglib/taglib/ape/apetag.h delete mode 100644 taglib/taglib/asf/asfattribute.cpp delete mode 100644 taglib/taglib/asf/asfattribute.h delete mode 100644 taglib/taglib/asf/asffile.cpp delete mode 100644 taglib/taglib/asf/asffile.h delete mode 100644 taglib/taglib/asf/asfpicture.cpp delete mode 100644 taglib/taglib/asf/asfpicture.h delete mode 100644 taglib/taglib/asf/asfproperties.cpp delete mode 100644 taglib/taglib/asf/asfproperties.h delete mode 100644 taglib/taglib/asf/asftag.cpp delete mode 100644 taglib/taglib/asf/asftag.h delete mode 100644 taglib/taglib/audioproperties.cpp delete mode 100644 taglib/taglib/audioproperties.h delete mode 100644 taglib/taglib/fileref.cpp delete mode 100644 taglib/taglib/fileref.h delete mode 100644 taglib/taglib/flac/flacfile.cpp delete mode 100644 taglib/taglib/flac/flacfile.h delete mode 100644 taglib/taglib/flac/flacmetadatablock.cpp delete mode 100644 taglib/taglib/flac/flacmetadatablock.h delete mode 100644 taglib/taglib/flac/flacpicture.cpp delete mode 100644 taglib/taglib/flac/flacpicture.h delete mode 100644 taglib/taglib/flac/flacproperties.cpp delete mode 100644 taglib/taglib/flac/flacproperties.h delete mode 100644 taglib/taglib/flac/flacunknownmetadatablock.cpp delete mode 100644 taglib/taglib/flac/flacunknownmetadatablock.h delete mode 100644 taglib/taglib/it/itfile.cpp delete mode 100644 taglib/taglib/it/itfile.h delete mode 100644 taglib/taglib/it/itproperties.cpp delete mode 100644 taglib/taglib/it/itproperties.h delete mode 100644 taglib/taglib/mod/modfile.cpp delete mode 100644 taglib/taglib/mod/modfile.h delete mode 100644 taglib/taglib/mod/modfilebase.cpp delete mode 100644 taglib/taglib/mod/modfilebase.h delete mode 100644 taglib/taglib/mod/modfileprivate.h delete mode 100644 taglib/taglib/mod/modproperties.cpp delete mode 100644 taglib/taglib/mod/modproperties.h delete mode 100644 taglib/taglib/mod/modtag.cpp delete mode 100644 taglib/taglib/mod/modtag.h delete mode 100644 taglib/taglib/mp4/mp4atom.cpp delete mode 100644 taglib/taglib/mp4/mp4atom.h delete mode 100644 taglib/taglib/mp4/mp4coverart.cpp delete mode 100644 taglib/taglib/mp4/mp4coverart.h delete mode 100644 taglib/taglib/mp4/mp4file.cpp delete mode 100644 taglib/taglib/mp4/mp4file.h delete mode 100644 taglib/taglib/mp4/mp4item.cpp delete mode 100644 taglib/taglib/mp4/mp4item.h delete mode 100644 taglib/taglib/mp4/mp4properties.cpp delete mode 100644 taglib/taglib/mp4/mp4properties.h delete mode 100644 taglib/taglib/mp4/mp4tag.cpp delete mode 100644 taglib/taglib/mp4/mp4tag.h delete mode 100644 taglib/taglib/mpc/mpcfile.cpp delete mode 100644 taglib/taglib/mpc/mpcfile.h delete mode 100644 taglib/taglib/mpc/mpcproperties.cpp delete mode 100644 taglib/taglib/mpc/mpcproperties.h delete mode 100644 taglib/taglib/mpeg/id3v1/id3v1genres.cpp delete mode 100644 taglib/taglib/mpeg/id3v1/id3v1genres.h delete mode 100644 taglib/taglib/mpeg/id3v1/id3v1tag.cpp delete mode 100644 taglib/taglib/mpeg/id3v1/id3v1tag.h delete mode 100644 taglib/taglib/mpeg/id3v2/frames/attachedpictureframe.cpp delete mode 100644 taglib/taglib/mpeg/id3v2/frames/attachedpictureframe.h delete mode 100644 taglib/taglib/mpeg/id3v2/frames/commentsframe.cpp delete mode 100644 taglib/taglib/mpeg/id3v2/frames/commentsframe.h delete mode 100644 taglib/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.cpp delete mode 100644 taglib/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.h delete mode 100644 taglib/taglib/mpeg/id3v2/frames/ownershipframe.cpp delete mode 100644 taglib/taglib/mpeg/id3v2/frames/ownershipframe.h delete mode 100644 taglib/taglib/mpeg/id3v2/frames/popularimeterframe.cpp delete mode 100644 taglib/taglib/mpeg/id3v2/frames/popularimeterframe.h delete mode 100644 taglib/taglib/mpeg/id3v2/frames/privateframe.cpp delete mode 100644 taglib/taglib/mpeg/id3v2/frames/privateframe.h delete mode 100644 taglib/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp delete mode 100644 taglib/taglib/mpeg/id3v2/frames/relativevolumeframe.h delete mode 100644 taglib/taglib/mpeg/id3v2/frames/textidentificationframe.cpp delete mode 100644 taglib/taglib/mpeg/id3v2/frames/textidentificationframe.h delete mode 100644 taglib/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.cpp delete mode 100644 taglib/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.h delete mode 100644 taglib/taglib/mpeg/id3v2/frames/unknownframe.cpp delete mode 100644 taglib/taglib/mpeg/id3v2/frames/unknownframe.h delete mode 100644 taglib/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp delete mode 100644 taglib/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.h delete mode 100644 taglib/taglib/mpeg/id3v2/frames/urllinkframe.cpp delete mode 100644 taglib/taglib/mpeg/id3v2/frames/urllinkframe.h delete mode 100644 taglib/taglib/mpeg/id3v2/id3v2.2.0.txt delete mode 100644 taglib/taglib/mpeg/id3v2/id3v2.3.0.txt delete mode 100644 taglib/taglib/mpeg/id3v2/id3v2.4.0-frames.txt delete mode 100644 taglib/taglib/mpeg/id3v2/id3v2.4.0-structure.txt delete mode 100644 taglib/taglib/mpeg/id3v2/id3v2extendedheader.cpp delete mode 100644 taglib/taglib/mpeg/id3v2/id3v2extendedheader.h delete mode 100644 taglib/taglib/mpeg/id3v2/id3v2footer.cpp delete mode 100644 taglib/taglib/mpeg/id3v2/id3v2footer.h delete mode 100644 taglib/taglib/mpeg/id3v2/id3v2frame.cpp delete mode 100644 taglib/taglib/mpeg/id3v2/id3v2frame.h delete mode 100644 taglib/taglib/mpeg/id3v2/id3v2framefactory.cpp delete mode 100644 taglib/taglib/mpeg/id3v2/id3v2framefactory.h delete mode 100644 taglib/taglib/mpeg/id3v2/id3v2header.cpp delete mode 100644 taglib/taglib/mpeg/id3v2/id3v2header.h delete mode 100644 taglib/taglib/mpeg/id3v2/id3v2synchdata.cpp delete mode 100644 taglib/taglib/mpeg/id3v2/id3v2synchdata.h delete mode 100644 taglib/taglib/mpeg/id3v2/id3v2tag.cpp delete mode 100644 taglib/taglib/mpeg/id3v2/id3v2tag.h delete mode 100644 taglib/taglib/mpeg/mpegfile.cpp delete mode 100644 taglib/taglib/mpeg/mpegfile.h delete mode 100644 taglib/taglib/mpeg/mpegheader.cpp delete mode 100644 taglib/taglib/mpeg/mpegheader.h delete mode 100644 taglib/taglib/mpeg/mpegproperties.cpp delete mode 100644 taglib/taglib/mpeg/mpegproperties.h delete mode 100644 taglib/taglib/mpeg/xingheader.cpp delete mode 100644 taglib/taglib/mpeg/xingheader.h delete mode 100644 taglib/taglib/ogg/flac/oggflacfile.cpp delete mode 100644 taglib/taglib/ogg/flac/oggflacfile.h delete mode 100644 taglib/taglib/ogg/oggfile.cpp delete mode 100644 taglib/taglib/ogg/oggfile.h delete mode 100644 taglib/taglib/ogg/oggpage.cpp delete mode 100644 taglib/taglib/ogg/oggpage.h delete mode 100644 taglib/taglib/ogg/oggpageheader.cpp delete mode 100644 taglib/taglib/ogg/oggpageheader.h delete mode 100644 taglib/taglib/ogg/opus/opusfile.cpp delete mode 100644 taglib/taglib/ogg/opus/opusfile.h delete mode 100644 taglib/taglib/ogg/opus/opusproperties.cpp delete mode 100644 taglib/taglib/ogg/opus/opusproperties.h delete mode 100644 taglib/taglib/ogg/speex/speexfile.cpp delete mode 100644 taglib/taglib/ogg/speex/speexfile.h delete mode 100644 taglib/taglib/ogg/speex/speexproperties.cpp delete mode 100644 taglib/taglib/ogg/speex/speexproperties.h delete mode 100644 taglib/taglib/ogg/vorbis/vorbisfile.cpp delete mode 100644 taglib/taglib/ogg/vorbis/vorbisfile.h delete mode 100644 taglib/taglib/ogg/vorbis/vorbisproperties.cpp delete mode 100644 taglib/taglib/ogg/vorbis/vorbisproperties.h delete mode 100644 taglib/taglib/ogg/xiphcomment.cpp delete mode 100644 taglib/taglib/ogg/xiphcomment.h delete mode 100644 taglib/taglib/riff/aiff/aifffile.cpp delete mode 100644 taglib/taglib/riff/aiff/aifffile.h delete mode 100644 taglib/taglib/riff/aiff/aiffproperties.cpp delete mode 100644 taglib/taglib/riff/aiff/aiffproperties.h delete mode 100644 taglib/taglib/riff/rifffile.cpp delete mode 100644 taglib/taglib/riff/rifffile.h delete mode 100644 taglib/taglib/riff/wav/infotag.cpp delete mode 100644 taglib/taglib/riff/wav/infotag.h delete mode 100644 taglib/taglib/riff/wav/wavfile.cpp delete mode 100644 taglib/taglib/riff/wav/wavfile.h delete mode 100644 taglib/taglib/riff/wav/wavproperties.cpp delete mode 100644 taglib/taglib/riff/wav/wavproperties.h delete mode 100644 taglib/taglib/s3m/s3mfile.cpp delete mode 100644 taglib/taglib/s3m/s3mfile.h delete mode 100644 taglib/taglib/s3m/s3mproperties.cpp delete mode 100644 taglib/taglib/s3m/s3mproperties.h delete mode 100644 taglib/taglib/tag.cpp delete mode 100644 taglib/taglib/tag.h delete mode 100644 taglib/taglib/taglib_config.h.cmake delete mode 100644 taglib/taglib/taglib_export.h delete mode 100644 taglib/taglib/tagunion.cpp delete mode 100644 taglib/taglib/tagunion.h delete mode 100644 taglib/taglib/toolkit/taglib.h delete mode 100644 taglib/taglib/toolkit/tbytevector.cpp delete mode 100644 taglib/taglib/toolkit/tbytevector.h delete mode 100644 taglib/taglib/toolkit/tbytevectorlist.cpp delete mode 100644 taglib/taglib/toolkit/tbytevectorlist.h delete mode 100644 taglib/taglib/toolkit/tbytevectorstream.cpp delete mode 100644 taglib/taglib/toolkit/tbytevectorstream.h delete mode 100644 taglib/taglib/toolkit/tdebug.cpp delete mode 100644 taglib/taglib/toolkit/tdebug.h delete mode 100644 taglib/taglib/toolkit/tdebuglistener.cpp delete mode 100644 taglib/taglib/toolkit/tdebuglistener.h delete mode 100644 taglib/taglib/toolkit/tfile.cpp delete mode 100644 taglib/taglib/toolkit/tfile.h delete mode 100644 taglib/taglib/toolkit/tfilestream.cpp delete mode 100644 taglib/taglib/toolkit/tfilestream.h delete mode 100644 taglib/taglib/toolkit/tiostream.cpp delete mode 100644 taglib/taglib/toolkit/tiostream.h delete mode 100644 taglib/taglib/toolkit/tlist.h delete mode 100644 taglib/taglib/toolkit/tlist.tcc delete mode 100644 taglib/taglib/toolkit/tmap.h delete mode 100644 taglib/taglib/toolkit/tmap.tcc delete mode 100644 taglib/taglib/toolkit/tpropertymap.cpp delete mode 100644 taglib/taglib/toolkit/tpropertymap.h delete mode 100644 taglib/taglib/toolkit/trefcounter.cpp delete mode 100644 taglib/taglib/toolkit/trefcounter.h delete mode 100644 taglib/taglib/toolkit/tstring.cpp delete mode 100644 taglib/taglib/toolkit/tstring.h delete mode 100644 taglib/taglib/toolkit/tstringlist.cpp delete mode 100644 taglib/taglib/toolkit/tstringlist.h delete mode 100644 taglib/taglib/toolkit/tutils.h delete mode 100644 taglib/taglib/toolkit/unicode.cpp delete mode 100644 taglib/taglib/toolkit/unicode.h delete mode 100644 taglib/taglib/trueaudio/trueaudiofile.cpp delete mode 100644 taglib/taglib/trueaudio/trueaudiofile.h delete mode 100644 taglib/taglib/trueaudio/trueaudioproperties.cpp delete mode 100644 taglib/taglib/trueaudio/trueaudioproperties.h delete mode 100644 taglib/taglib/wavpack/wavpackfile.cpp delete mode 100644 taglib/taglib/wavpack/wavpackfile.h delete mode 100644 taglib/taglib/wavpack/wavpackproperties.cpp delete mode 100644 taglib/taglib/wavpack/wavpackproperties.h delete mode 100644 taglib/taglib/xm/xmfile.cpp delete mode 100644 taglib/taglib/xm/xmfile.h delete mode 100644 taglib/taglib/xm/xmproperties.cpp delete mode 100644 taglib/taglib/xm/xmproperties.h delete mode 100644 taglib/tests/CMakeLists.txt delete mode 100644 taglib/tests/data/005411.id3 delete mode 100644 taglib/tests/data/64bit.mp4 delete mode 100644 taglib/tests/data/broken-tenc.id3 delete mode 100644 taglib/tests/data/changed.mod delete mode 100644 taglib/tests/data/changed.s3m delete mode 100644 taglib/tests/data/changed.xm delete mode 100644 taglib/tests/data/click.mpc delete mode 100644 taglib/tests/data/click.wv delete mode 100644 taglib/tests/data/compressed_id3_frame.mp3 delete mode 100644 taglib/tests/data/correctness_gain_silent_output.opus delete mode 100644 taglib/tests/data/covr-junk.m4a delete mode 100644 taglib/tests/data/empty.aiff delete mode 100644 taglib/tests/data/empty.ogg delete mode 100644 taglib/tests/data/empty.spx delete mode 100644 taglib/tests/data/empty.tta delete mode 100644 taglib/tests/data/empty.wav delete mode 100644 taglib/tests/data/empty_alac.m4a delete mode 100644 taglib/tests/data/empty_flac.oga delete mode 100644 taglib/tests/data/empty_vorbis.oga delete mode 100644 taglib/tests/data/gnre.m4a delete mode 100644 taglib/tests/data/has-tags.m4a delete mode 100644 taglib/tests/data/id3v22-tda.mp3 delete mode 100644 taglib/tests/data/ilst-is-last.m4a delete mode 100644 taglib/tests/data/mac-390-hdr.ape delete mode 100644 taglib/tests/data/mac-396.ape delete mode 100644 taglib/tests/data/mac-399.ape delete mode 100644 taglib/tests/data/mpeg2.mp3 delete mode 100644 taglib/tests/data/multiple-vc.flac delete mode 100644 taglib/tests/data/no-extension delete mode 100644 taglib/tests/data/no-tags.3g2 delete mode 100644 taglib/tests/data/no-tags.flac delete mode 100644 taglib/tests/data/no-tags.m4a delete mode 100644 taglib/tests/data/no_length.wv delete mode 100644 taglib/tests/data/noise.aif delete mode 100644 taglib/tests/data/noise_odd.aif delete mode 100644 taglib/tests/data/rare_frames.mp3 delete mode 100644 taglib/tests/data/silence-1.wma delete mode 100644 taglib/tests/data/silence-44-s.flac delete mode 100644 taglib/tests/data/stripped.xm delete mode 100644 taglib/tests/data/sv4_header.mpc delete mode 100644 taglib/tests/data/sv5_header.mpc delete mode 100644 taglib/tests/data/sv8_header.mpc delete mode 100644 taglib/tests/data/test.it delete mode 100644 taglib/tests/data/test.mod delete mode 100644 taglib/tests/data/test.ogg delete mode 100644 taglib/tests/data/test.s3m delete mode 100644 taglib/tests/data/test.xm delete mode 100644 taglib/tests/data/unsupported-extension.xxx delete mode 100644 taglib/tests/data/unsynch.id3 delete mode 100644 taglib/tests/data/w000.mp3 delete mode 100644 taglib/tests/data/xing.mp3 delete mode 100644 taglib/tests/data/zero-size-chunk.wav delete mode 100644 taglib/tests/main.cpp delete mode 100644 taglib/tests/test_aiff.cpp delete mode 100644 taglib/tests/test_ape.cpp delete mode 100644 taglib/tests/test_apetag.cpp delete mode 100644 taglib/tests/test_asf.cpp delete mode 100644 taglib/tests/test_bytevector.cpp delete mode 100644 taglib/tests/test_bytevectorlist.cpp delete mode 100644 taglib/tests/test_bytevectorstream.cpp delete mode 100644 taglib/tests/test_fileref.cpp delete mode 100644 taglib/tests/test_flac.cpp delete mode 100644 taglib/tests/test_flacpicture.cpp delete mode 100644 taglib/tests/test_flacunknownmetadatablock.cpp delete mode 100644 taglib/tests/test_id3v1.cpp delete mode 100644 taglib/tests/test_id3v2.cpp delete mode 100644 taglib/tests/test_info.cpp delete mode 100644 taglib/tests/test_it.cpp delete mode 100644 taglib/tests/test_list.cpp delete mode 100644 taglib/tests/test_map.cpp delete mode 100644 taglib/tests/test_mod.cpp delete mode 100644 taglib/tests/test_mp4.cpp delete mode 100644 taglib/tests/test_mp4coverart.cpp delete mode 100644 taglib/tests/test_mp4item.cpp delete mode 100644 taglib/tests/test_mpc.cpp delete mode 100644 taglib/tests/test_mpeg.cpp delete mode 100644 taglib/tests/test_ogg.cpp delete mode 100644 taglib/tests/test_oggflac.cpp delete mode 100644 taglib/tests/test_opus.cpp delete mode 100644 taglib/tests/test_propertymap.cpp delete mode 100644 taglib/tests/test_riff.cpp delete mode 100644 taglib/tests/test_s3m.cpp delete mode 100644 taglib/tests/test_string.cpp delete mode 100644 taglib/tests/test_synchdata.cpp delete mode 100644 taglib/tests/test_trueaudio.cpp delete mode 100644 taglib/tests/test_wav.cpp delete mode 100644 taglib/tests/test_wavpack.cpp delete mode 100644 taglib/tests/test_xiphcomment.cpp delete mode 100644 taglib/tests/test_xm.cpp delete mode 100644 taglib/tests/utils.h diff --git a/cmainwindow.cpp b/cmainwindow.cpp index ede24ec..c574d3c 100644 --- a/cmainwindow.cpp +++ b/cmainwindow.cpp @@ -65,8 +65,8 @@ cMainWindow::cMainWindow(QWidget *parent) : // lpMediaInfo->readFromFile("C:\\Users\\birkeh\\Music\\Amy MacDonald\\Life In A Beautiful Light\\CD1\\Amy Macdonald - Life In A Beautiful Light - 05 - The Game.mp3"); // lpMediaInfo->readFromFile("C:\\Users\\birkeh\\Music\\Amy MacDonald\\A Curious Thing\\CD1\\Amy MacDonald - A Curious Thing - 01 - Don't tell me it's over.mp3"); // lpMediaInfo->readFromFile("C:\\Users\\birkeh\\Music\\id3v1\\id3v1_140_genre_W.mp3"); - lpMediaInfo->readFromFile("C:\\Users\\birkeh\\Documents\\__P__\\MP3Test\\From-The-Machine-World.mp3"); - +// lpMediaInfo->readFromFile("C:\\Users\\vet0572\\Music\\Heartbeat\\Strong\\CD1\\Heartbeat - Strong - 01 - Strong.mp3"); + lpMediaInfo->readFromFile("C:\\Users\\vet0572\\Music\\Amy MacDonald\\Under Stars (Deluxe)\\02 - Under Stars.mp3"); QString sz; QStringList szL; qint16 i; diff --git a/cmediainfo.cpp b/cmediainfo.cpp index ea1604a..64936ca 100644 --- a/cmediainfo.cpp +++ b/cmediainfo.cpp @@ -22,28 +22,28 @@ cMediaInfo::~cMediaInfo() void cMediaInfo::clear() { - m_szFileName = ""; - m_FileType = MEDIA_TYPE_UNKNOWN; - m_bIsValid = false; + m_szFileName = ""; + m_FileType = MEDIA_TYPE_UNKNOWN; + m_bIsValid = false; - m_iLength = -1; - m_iBitrate = -1; - m_iSampleRate = -1; - m_iChannels = -1; - m_iBitsPerSample = -1; - m_iLayer = -1; - m_iVersion = -1; - m_iSampleWidth = -1; - m_ullSampleFrames = 0; - m_bIsEncrypted = false; - m_iTrackGain = -1; - m_iAlbumGain = -1; - m_iTrackPeak = -1; - m_iAlbumPeak = -1; - m_bProtectionEnabled = false; - m_channelMode = CHANNEL_MODE_UNKNOWN; - m_bIsCopyrighted = false; - m_bIsOriginal = false; + m_iLength = -1; + m_iBitrate = -1; + m_iSampleRate = -1; + m_iChannels = -1; + m_iBitsPerSample = -1; + m_iLayer = -1; + m_iVersion = -1; + m_iSampleWidth = -1; + m_ullSampleFrames = 0; + m_bIsEncrypted = false; + m_iTrackGain = -1; + m_iAlbumGain = -1; + m_iTrackPeak = -1; + m_iAlbumPeak = -1; + m_bProtectionEnabled = false; + m_channelMode = CHANNEL_MODE_UNKNOWN; + m_bIsCopyrighted = false; + m_bIsOriginal = false; m_szContentGroupDescription = ""; m_szTitle = ""; @@ -106,21 +106,21 @@ void cMediaInfo::clear() m_imageList.clear(); - m_szAlbum = ""; + m_szAlbum = ""; m_szArtistList.clear(); m_szAlbumArtistList.clear(); m_szComposerList.clear(); - m_szComment = ""; + m_szComment = ""; m_szGenreList.clear(); - m_szTitle = ""; - m_szRating = ""; - m_szCopyright = ""; - m_szTrackNumber = ""; - m_iYear = -1; + m_szTitle = ""; + m_szRating = ""; + m_szCopyright = ""; + m_szTrackNumber = ""; + m_iYear = -1; - m_iID3v2Version = -1; - m_iID3v2Revision = -1; - m_iID3v2Size = -1; + m_iID3v2Version = -1; + m_iID3v2Revision = -1; + m_iID3v2Size = -1; m_TAGAPEList.clear(); m_TAGPropertiesList.clear(); @@ -194,12 +194,12 @@ bool cMediaInfo::readFromFile(const QString& szFileName) tags = lpApe->properties(); APE::Properties* lpAudioProperties = lpApe->audioProperties(); - m_iLength = lpAudioProperties->length(); - m_iBitrate = lpAudioProperties->bitrate(); - m_iSampleRate = lpAudioProperties->sampleRate(); - m_iChannels = lpAudioProperties->channels(); - m_iBitsPerSample = lpAudioProperties->bitsPerSample(); - m_iVersion = lpAudioProperties->version(); + m_iLength = lpAudioProperties->length(); + m_iBitrate = lpAudioProperties->bitrate(); + m_iSampleRate = lpAudioProperties->sampleRate(); + m_iChannels = lpAudioProperties->channels(); + m_iBitsPerSample = lpAudioProperties->bitsPerSample(); + m_iVersion = lpAudioProperties->version(); break; } case MEDIA_TYPE_ASF: @@ -223,11 +223,11 @@ bool cMediaInfo::readFromFile(const QString& szFileName) tags = lpASF->properties(); ASF::Properties* lpAudioProperties = lpASF->audioProperties(); - m_iLength = lpAudioProperties->length(); - m_iBitrate = lpAudioProperties->bitrate(); - m_iSampleRate = lpAudioProperties->sampleRate(); - m_iChannels = lpAudioProperties->channels(); - m_bIsEncrypted = lpAudioProperties->isEncrypted(); + m_iLength = lpAudioProperties->length(); + m_iBitrate = lpAudioProperties->bitrate(); + m_iSampleRate = lpAudioProperties->sampleRate(); + m_iChannels = lpAudioProperties->channels(); + m_bIsEncrypted = lpAudioProperties->isEncrypted(); break; } case MEDIA_TYPE_FLAC: @@ -238,12 +238,12 @@ bool cMediaInfo::readFromFile(const QString& szFileName) tags = lpFlac->properties(); FLAC::Properties* lpAudioProperties = lpFlac->audioProperties(); - m_iLength = lpAudioProperties->length(); - m_iBitrate = lpAudioProperties->bitrate(); - m_iSampleRate = lpAudioProperties->sampleRate(); - m_iChannels = lpAudioProperties->channels(); - m_iSampleWidth = lpAudioProperties->sampleWidth(); - m_ullSampleFrames = lpAudioProperties->sampleFrames(); + m_iLength = lpAudioProperties->length(); + m_iBitrate = lpAudioProperties->bitrate(); + m_iSampleRate = lpAudioProperties->sampleRate(); + m_iChannels = lpAudioProperties->channels(); + m_iSampleWidth = lpAudioProperties->sampleWidth(); + m_ullSampleFrames = lpAudioProperties->sampleFrames(); break; } case MEDIA_TYPE_MP4: @@ -265,12 +265,12 @@ bool cMediaInfo::readFromFile(const QString& szFileName) tags = lpMP4->properties(); MP4::Properties* lpAudioProperties = lpMP4->audioProperties(); - m_iLength = lpAudioProperties->length(); - m_iBitrate = lpAudioProperties->bitrate(); - m_iSampleRate = lpAudioProperties->sampleRate(); - m_iChannels = lpAudioProperties->channels(); - m_iBitsPerSample = lpAudioProperties->bitsPerSample(); - m_bIsEncrypted = lpAudioProperties->isEncrypted(); + m_iLength = lpAudioProperties->length(); + m_iBitrate = lpAudioProperties->bitrate(); + m_iSampleRate = lpAudioProperties->sampleRate(); + m_iChannels = lpAudioProperties->channels(); + m_iBitsPerSample = lpAudioProperties->bitsPerSample(); + m_bIsEncrypted = lpAudioProperties->isEncrypted(); break; } case MEDIA_TYPE_MPC: @@ -281,16 +281,16 @@ bool cMediaInfo::readFromFile(const QString& szFileName) tags = lpMPC->properties(); MPC::Properties* lpAudioProperties = lpMPC->audioProperties(); - m_iLength = lpAudioProperties->length(); - m_iBitrate = lpAudioProperties->bitrate(); - m_iSampleRate = lpAudioProperties->sampleRate(); - m_iChannels = lpAudioProperties->channels(); - m_iVersion = lpAudioProperties->mpcVersion(); - m_ullSampleFrames = lpAudioProperties->sampleFrames(); - m_iTrackGain = lpAudioProperties->trackGain(); - m_iAlbumGain = lpAudioProperties->albumGain(); - m_iTrackPeak = lpAudioProperties->trackPeak(); - m_iAlbumPeak = lpAudioProperties->albumPeak(); + m_iLength = lpAudioProperties->length(); + m_iBitrate = lpAudioProperties->bitrate(); + m_iSampleRate = lpAudioProperties->sampleRate(); + m_iChannels = lpAudioProperties->channels(); + m_iVersion = lpAudioProperties->mpcVersion(); + m_ullSampleFrames = lpAudioProperties->sampleFrames(); + m_iTrackGain = lpAudioProperties->trackGain(); + m_iAlbumGain = lpAudioProperties->albumGain(); + m_iTrackPeak = lpAudioProperties->trackPeak(); + m_iAlbumPeak = lpAudioProperties->albumPeak(); break; } case MEDIA_TYPE_MPEG: @@ -302,11 +302,11 @@ bool cMediaInfo::readFromFile(const QString& szFileName) tags = lpMPEG->properties(); MPEG::Properties* lpAudioProperties = lpMPEG->audioProperties(); - m_iLength = lpAudioProperties->length(); - m_iBitrate = lpAudioProperties->bitrate(); - m_iSampleRate = lpAudioProperties->sampleRate(); - m_iChannels = lpAudioProperties->channels(); - m_iLayer = lpAudioProperties->layer(); + m_iLength = lpAudioProperties->length(); + m_iBitrate = lpAudioProperties->bitrate(); + m_iSampleRate = lpAudioProperties->sampleRate(); + m_iChannels = lpAudioProperties->channels(); + m_iLayer = lpAudioProperties->layer(); switch(lpAudioProperties->version()) { case MPEG::Header::Version1: @@ -319,24 +319,24 @@ bool cMediaInfo::readFromFile(const QString& szFileName) m_iVersion = 25; break; } - m_bProtectionEnabled = lpAudioProperties->protectionEnabled(); + m_bProtectionEnabled = lpAudioProperties->protectionEnabled(); switch(lpAudioProperties->channelMode()) { case MPEG::Header::Stereo: - m_channelMode = CHANNEL_MODE_STEREO; + m_channelMode = CHANNEL_MODE_STEREO; break; case MPEG::Header::JointStereo: - m_channelMode = CHANNEL_MODE_JOINTSTEREO; + m_channelMode = CHANNEL_MODE_JOINTSTEREO; break; case MPEG::Header::DualChannel: - m_channelMode = CHANNEL_MODE_DUALMONO; + m_channelMode = CHANNEL_MODE_DUALMONO; break; case MPEG::Header::SingleChannel: - m_channelMode = CHANNEL_MODE_MONO; + m_channelMode = CHANNEL_MODE_MONO; break; } - m_bIsCopyrighted = lpAudioProperties->isCopyrighted(); - m_bIsOriginal = lpAudioProperties->isOriginal(); + m_bIsCopyrighted = lpAudioProperties->isCopyrighted(); + m_bIsOriginal = lpAudioProperties->isOriginal(); break; } case MEDIA_TYPE_TRUEAUDIO: @@ -347,12 +347,12 @@ bool cMediaInfo::readFromFile(const QString& szFileName) tags = lpTrueAudio->properties(); TrueAudio::Properties* lpAudioProperties = lpTrueAudio->audioProperties(); - m_iLength = lpAudioProperties->length(); - m_iBitrate = lpAudioProperties->bitrate(); - m_iSampleRate = lpAudioProperties->sampleRate(); - m_iChannels = lpAudioProperties->channels(); - m_iBitsPerSample = lpAudioProperties->bitsPerSample(); - m_iVersion = lpAudioProperties->ttaVersion(); + m_iLength = lpAudioProperties->length(); + m_iBitrate = lpAudioProperties->bitrate(); + m_iSampleRate = lpAudioProperties->sampleRate(); + m_iChannels = lpAudioProperties->channels(); + m_iBitsPerSample = lpAudioProperties->bitsPerSample(); + m_iVersion = lpAudioProperties->ttaVersion(); break; } case MEDIA_TYPE_WAVPACK: @@ -363,13 +363,13 @@ bool cMediaInfo::readFromFile(const QString& szFileName) tags = lpWavPack->properties(); WavPack::Properties* lpAudioProperties = lpWavPack->audioProperties(); - m_iLength = lpAudioProperties->length(); - m_iBitrate = lpAudioProperties->bitrate(); - m_iSampleRate = lpAudioProperties->sampleRate(); - m_iChannels = lpAudioProperties->channels(); - m_iBitsPerSample = lpAudioProperties->bitsPerSample(); - m_ullSampleFrames = lpAudioProperties->sampleFrames(); - m_iVersion = lpAudioProperties->version(); + m_iLength = lpAudioProperties->length(); + m_iBitrate = lpAudioProperties->bitrate(); + m_iSampleRate = lpAudioProperties->sampleRate(); + m_iChannels = lpAudioProperties->channels(); + m_iBitsPerSample = lpAudioProperties->bitsPerSample(); + m_ullSampleFrames = lpAudioProperties->sampleFrames(); + m_iVersion = lpAudioProperties->version(); break; } case MEDIA_TYPE_WAV: @@ -379,12 +379,12 @@ bool cMediaInfo::readFromFile(const QString& szFileName) tags = lpWav->properties(); RIFF::WAV::Properties* lpAudioProperties = lpWav->audioProperties(); - m_iLength = lpAudioProperties->length(); - m_iBitrate = lpAudioProperties->bitrate(); - m_iSampleRate = lpAudioProperties->sampleRate(); - m_iChannels = lpAudioProperties->channels(); - m_iSampleWidth = lpAudioProperties->sampleWidth(); - m_ullSampleFrames = lpAudioProperties->sampleFrames(); + m_iLength = lpAudioProperties->length(); + m_iBitrate = lpAudioProperties->bitrate(); + m_iSampleRate = lpAudioProperties->sampleRate(); + m_iChannels = lpAudioProperties->channels(); + m_iSampleWidth = lpAudioProperties->sampleWidth(); + m_ullSampleFrames = lpAudioProperties->sampleFrames(); break; } default: diff --git a/cmediainfo.h b/cmediainfo.h index 9a88dd3..f840f87 100644 --- a/cmediainfo.h +++ b/cmediainfo.h @@ -45,24 +45,24 @@ class cMediaInfo : public QObject public: enum MEDIA_TYPE { - MEDIA_TYPE_UNKNOWN = 0, - MEDIA_TYPE_APE, // APE - MEDIA_TYPE_ASF, // WMA - MEDIA_TYPE_FLAC, // FLAC - MEDIA_TYPE_MP4, // AAC, MP4, M4A - MEDIA_TYPE_MPC, // MPC - MEDIA_TYPE_MPEG, // MP1, MP2, MP3 - MEDIA_TYPE_TRUEAUDIO, // TTA - MEDIA_TYPE_WAVPACK, // WV - MEDIA_TYPE_WAV // WAV + MEDIA_TYPE_UNKNOWN = 0, + MEDIA_TYPE_APE = 1, // APE + MEDIA_TYPE_ASF = 2, // WMA + MEDIA_TYPE_FLAC = 3, // FLAC + MEDIA_TYPE_MP4 = 4, // AAC, MP4, M4A + MEDIA_TYPE_MPC = 5, // MPC + MEDIA_TYPE_MPEG = 6, // MP1, MP2, MP3 + MEDIA_TYPE_TRUEAUDIO = 7, // TTA + MEDIA_TYPE_WAVPACK = 8, // WV + MEDIA_TYPE_WAV = 9, // WAV }; enum CHANNEL_MODE { - CHANNEL_MODE_UNKNOWN = 0, - CHANNEL_MODE_STEREO, - CHANNEL_MODE_JOINTSTEREO, - CHANNEL_MODE_MONO, - CHANNEL_MODE_DUALMONO + CHANNEL_MODE_UNKNOWN = 0, + CHANNEL_MODE_STEREO = 1, + CHANNEL_MODE_JOINTSTEREO = 2, + CHANNEL_MODE_MONO = 3, + CHANNEL_MODE_DUALMONO = 4 }; explicit cMediaInfo(bool bAPE = true, bool bID3V1 = true, bool bID3V2 = true, bool bProperties = true, QObject *parent = 0); diff --git a/qtJukeBox.pro b/qtJukeBox.pro index 3cba2aa..3324bc5 100644 --- a/qtJukeBox.pro +++ b/qtJukeBox.pro @@ -12,6 +12,10 @@ TARGET = qtJukeBox TEMPLATE = app +INCLUDEPATH += "C:/dev/3rdParty/taglib/include" +DEPENDPATH += "C:/dev/3rdParty/taglib/include" +LIBS += "C:/dev/3rdParty/taglib/lib/libtag.dll.a" + SOURCES += main.cpp\ cmainwindow.cpp \ cmediainfo.cpp \ @@ -29,4 +33,4 @@ HEADERS += cmainwindow.h \ FORMS += cmainwindow.ui -LIBS += -ltaglib +#LIBS += -ltaglib diff --git a/taglib/AUTHORS b/taglib/AUTHORS deleted file mode 100644 index e996d94..0000000 --- a/taglib/AUTHORS +++ /dev/null @@ -1,17 +0,0 @@ -Scott Wheeler - Author, maintainer -Lukas Lalinsky - Implementation of multiple new file formats, many bug fixes, maintainer -Ismael Orenstein - Xing header implementation -Allan Sandfeld Jensen - FLAC metadata implementation -Teemu Tervo - Numerous bug reports and fixes -Mathias Panzenböck - Mod, S3M, IT and XM metadata implementations -Tsuda Kageyu - 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! diff --git a/taglib/CMakeLists.txt b/taglib/CMakeLists.txt deleted file mode 100644 index 317ffa1..0000000 --- a/taglib/CMakeLists.txt +++ /dev/null @@ -1,120 +0,0 @@ -project(taglib) - -cmake_minimum_required(VERSION 2.6.0 FATAL_ERROR) - -option(ENABLE_STATIC "Make static version of libtag" OFF) -if(ENABLE_STATIC) - add_definitions(-DTAGLIB_STATIC) - set(BUILD_SHARED_LIBS OFF) -else() - set(BUILD_SHARED_LIBS ON) -endif() -OPTION(ENABLE_STATIC_RUNTIME "Visual Studio, link with runtime statically" OFF) - -option(VISIBILITY_HIDDEN "Build with -fvisibility=hidden" OFF) -if(VISIBILITY_HIDDEN) - add_definitions (-fvisibility=hidden) -endif() - -option(BUILD_TESTS "Build the test suite" OFF) -option(BUILD_EXAMPLES "Build the examples" OFF) - -option(NO_ITUNES_HACKS "Disable workarounds for iTunes bugs" OFF) - -add_definitions(-DHAVE_CONFIG_H) -set(TESTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/tests/") - -## the following are directories where stuff will be installed to -set(LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)") -set(EXEC_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}" CACHE PATH "Base directory for executables and libraries" FORCE) -set(BIN_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/bin" CACHE PATH "The subdirectory to the binaries prefix (default prefix/bin)" FORCE) -set(LIB_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is /lib${LIB_SUFFIX})" FORCE) -set(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "The subdirectory to the header prefix" FORCE) - -if(APPLE) - option(BUILD_FRAMEWORK "Build an OS X framework" OFF) - set(FRAMEWORK_INSTALL_DIR "/Library/Frameworks" CACHE STRING "Directory to install frameworks to.") -endif() - -if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") -endif() -if (MSVC AND ENABLE_STATIC_RUNTIME) - foreach(flag_var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) - string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") - endforeach(flag_var) -endif() - -set(TAGLIB_LIB_MAJOR_VERSION "1") -set(TAGLIB_LIB_MINOR_VERSION "9") -set(TAGLIB_LIB_PATCH_VERSION "1") - -set(TAGLIB_LIB_VERSION_STRING "${TAGLIB_LIB_MAJOR_VERSION}.${TAGLIB_LIB_MINOR_VERSION}.${TAGLIB_LIB_PATCH_VERSION}") - -# 1. If the library source code has changed at all since the last update, then increment revision. -# 2. If any interfaces have been added, removed, or changed since the last update, increment current, and set revision to 0. -# 3. If any interfaces have been added since the last public release, then increment age. -# 4. If any interfaces have been removed since the last public release, then set age to 0. -set(TAGLIB_SOVERSION_CURRENT 15) -set(TAGLIB_SOVERSION_REVISION 0) -set(TAGLIB_SOVERSION_AGE 14) - -math(EXPR TAGLIB_SOVERSION_MAJOR "${TAGLIB_SOVERSION_CURRENT} - ${TAGLIB_SOVERSION_AGE}") -math(EXPR TAGLIB_SOVERSION_MINOR "${TAGLIB_SOVERSION_AGE}") -math(EXPR TAGLIB_SOVERSION_PATCH "${TAGLIB_SOVERSION_REVISION}") - -include(ConfigureChecks.cmake) - -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 ) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/taglib.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) -endif() - -include_directories(${CMAKE_CURRENT_BINARY_DIR}) -configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) - -if(WITH_ASF) - set(TAGLIB_WITH_ASF TRUE) -endif() -if(WITH_MP4) - set(TAGLIB_WITH_MP4 TRUE) -endif() - -option(TRACE_IN_RELEASE "Output debug messages even in release mode" OFF) -if(TRACE_IN_RELEASE) - set(TRACE_IN_RELEASE TRUE) -endif() - -configure_file(taglib/taglib_config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/taglib_config.h) - -add_subdirectory(taglib) -add_subdirectory(bindings) -if(BUILD_TESTS) - enable_testing() - add_subdirectory(tests) -endif(BUILD_TESTS) -add_subdirectory(examples) - -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.cmake ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) -file(COPY doc/taglib.png DESTINATION doc) -add_custom_target(docs doxygen) - -# uninstall target -configure_file( - "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" - "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" - IMMEDIATE @ONLY) - -add_custom_target(uninstall - COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") diff --git a/taglib/COPYING.LGPL b/taglib/COPYING.LGPL deleted file mode 100644 index 4362b49..0000000 --- a/taglib/COPYING.LGPL +++ /dev/null @@ -1,502 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - 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 - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! diff --git a/taglib/COPYING.MPL b/taglib/COPYING.MPL deleted file mode 100644 index 7714141..0000000 --- a/taglib/COPYING.MPL +++ /dev/null @@ -1,470 +0,0 @@ - MOZILLA PUBLIC LICENSE - Version 1.1 - - --------------- - -1. Definitions. - - 1.0.1. "Commercial Use" means distribution or otherwise making the - Covered Code available to a third party. - - 1.1. "Contributor" means each entity that creates or contributes to - the creation of Modifications. - - 1.2. "Contributor Version" means the combination of the Original - Code, prior Modifications used by a Contributor, and the Modifications - made by that particular Contributor. - - 1.3. "Covered Code" means the Original Code or Modifications or the - combination of the Original Code and Modifications, in each case - including portions thereof. - - 1.4. "Electronic Distribution Mechanism" means a mechanism generally - accepted in the software development community for the electronic - transfer of data. - - 1.5. "Executable" means Covered Code in any form other than Source - Code. - - 1.6. "Initial Developer" means the individual or entity identified - as the Initial Developer in the Source Code notice required by Exhibit - A. - - 1.7. "Larger Work" means a work which combines Covered Code or - portions thereof with code not governed by the terms of this License. - - 1.8. "License" means this document. - - 1.8.1. "Licensable" means having the right to grant, to the maximum - extent possible, whether at the time of the initial grant or - subsequently acquired, any and all of the rights conveyed herein. - - 1.9. "Modifications" means any addition to or deletion from the - substance or structure of either the Original Code or any previous - Modifications. When Covered Code is released as a series of files, a - Modification is: - A. Any addition to or deletion from the contents of a file - containing Original Code or previous Modifications. - - B. Any new file that contains any part of the Original Code or - previous Modifications. - - 1.10. "Original Code" means Source Code of computer software code - which is described in the Source Code notice required by Exhibit A as - Original Code, and which, at the time of its release under this - License is not already Covered Code governed by this License. - - 1.10.1. "Patent Claims" means any patent claim(s), now owned or - hereafter acquired, including without limitation, method, process, - and apparatus claims, in any patent Licensable by grantor. - - 1.11. "Source Code" means the preferred form of the Covered Code for - making modifications to it, including all modules it contains, plus - any associated interface definition files, scripts used to control - compilation and installation of an Executable, or source code - differential comparisons against either the Original Code or another - well known, available Covered Code of the Contributor's choice. The - Source Code can be in a compressed or archival form, provided the - appropriate decompression or de-archiving software is widely available - for no charge. - - 1.12. "You" (or "Your") means an individual or a legal entity - exercising rights under, and complying with all of the terms of, this - License or a future version of this License issued under Section 6.1. - For legal entities, "You" includes any entity which controls, is - controlled by, or is under common control with You. For purposes of - this definition, "control" means (a) the power, direct or indirect, - to cause the direction or management of such entity, whether by - contract or otherwise, or (b) ownership of more than fifty percent - (50%) of the outstanding shares or beneficial ownership of such - entity. - -2. Source Code License. - - 2.1. The Initial Developer Grant. - The Initial Developer hereby grants You a world-wide, royalty-free, - non-exclusive license, subject to third party intellectual property - claims: - (a) under intellectual property rights (other than patent or - trademark) Licensable by Initial Developer to use, reproduce, - modify, display, perform, sublicense and distribute the Original - Code (or portions thereof) with or without Modifications, and/or - as part of a Larger Work; and - - (b) under Patents Claims infringed by the making, using or - selling of Original Code, to make, have made, use, practice, - sell, and offer for sale, and/or otherwise dispose of the - Original Code (or portions thereof). - - (c) the licenses granted in this Section 2.1(a) and (b) are - effective on the date Initial Developer first distributes - Original Code under the terms of this License. - - (d) Notwithstanding Section 2.1(b) above, no patent license is - granted: 1) for code that You delete from the Original Code; 2) - separate from the Original Code; or 3) for infringements caused - by: i) the modification of the Original Code or ii) the - combination of the Original Code with other software or devices. - - 2.2. Contributor Grant. - Subject to third party intellectual property claims, each Contributor - hereby grants You a world-wide, royalty-free, non-exclusive license - - (a) under intellectual property rights (other than patent or - trademark) Licensable by Contributor, to use, reproduce, modify, - display, perform, sublicense and distribute the Modifications - created by such Contributor (or portions thereof) either on an - unmodified basis, with other Modifications, as Covered Code - and/or as part of a Larger Work; and - - (b) under Patent Claims infringed by the making, using, or - selling of Modifications made by that Contributor either alone - and/or in combination with its Contributor Version (or portions - of such combination), to make, use, sell, offer for sale, have - made, and/or otherwise dispose of: 1) Modifications made by that - Contributor (or portions thereof); and 2) the combination of - Modifications made by that Contributor with its Contributor - Version (or portions of such combination). - - (c) the licenses granted in Sections 2.2(a) and 2.2(b) are - effective on the date Contributor first makes Commercial Use of - the Covered Code. - - (d) Notwithstanding Section 2.2(b) above, no patent license is - granted: 1) for any code that Contributor has deleted from the - Contributor Version; 2) separate from the Contributor Version; - 3) for infringements caused by: i) third party modifications of - Contributor Version or ii) the combination of Modifications made - by that Contributor with other software (except as part of the - Contributor Version) or other devices; or 4) under Patent Claims - infringed by Covered Code in the absence of Modifications made by - that Contributor. - -3. Distribution Obligations. - - 3.1. Application of License. - The Modifications which You create or to which You contribute are - governed by the terms of this License, including without limitation - Section 2.2. The Source Code version of Covered Code may be - distributed only under the terms of this License or a future version - of this License released under Section 6.1, and You must include a - copy of this License with every copy of the Source Code You - distribute. You may not offer or impose any terms on any Source Code - version that alters or restricts the applicable version of this - License or the recipients' rights hereunder. However, You may include - an additional document offering the additional rights described in - Section 3.5. - - 3.2. Availability of Source Code. - Any Modification which You create or to which You contribute must be - made available in Source Code form under the terms of this License - either on the same media as an Executable version or via an accepted - Electronic Distribution Mechanism to anyone to whom you made an - Executable version available; and if made available via Electronic - Distribution Mechanism, must remain available for at least twelve (12) - months after the date it initially became available, or at least six - (6) months after a subsequent version of that particular Modification - has been made available to such recipients. You are responsible for - ensuring that the Source Code version remains available even if the - Electronic Distribution Mechanism is maintained by a third party. - - 3.3. Description of Modifications. - You must cause all Covered Code to which You contribute to contain a - file documenting the changes You made to create that Covered Code and - the date of any change. You must include a prominent statement that - the Modification is derived, directly or indirectly, from Original - Code provided by the Initial Developer and including the name of the - Initial Developer in (a) the Source Code, and (b) in any notice in an - Executable version or related documentation in which You describe the - origin or ownership of the Covered Code. - - 3.4. Intellectual Property Matters - (a) Third Party Claims. - If Contributor has knowledge that a license under a third party's - intellectual property rights is required to exercise the rights - granted by such Contributor under Sections 2.1 or 2.2, - Contributor must include a text file with the Source Code - distribution titled "LEGAL" which describes the claim and the - party making the claim in sufficient detail that a recipient will - know whom to contact. If Contributor obtains such knowledge after - the Modification is made available as described in Section 3.2, - Contributor shall promptly modify the LEGAL file in all copies - Contributor makes available thereafter and shall take other steps - (such as notifying appropriate mailing lists or newsgroups) - reasonably calculated to inform those who received the Covered - Code that new knowledge has been obtained. - - (b) Contributor APIs. - If Contributor's Modifications include an application programming - interface and Contributor has knowledge of patent licenses which - are reasonably necessary to implement that API, Contributor must - also include this information in the LEGAL file. - - (c) Representations. - Contributor represents that, except as disclosed pursuant to - Section 3.4(a) above, Contributor believes that Contributor's - Modifications are Contributor's original creation(s) and/or - Contributor has sufficient rights to grant the rights conveyed by - this License. - - 3.5. Required Notices. - You must duplicate the notice in Exhibit A in each file of the Source - Code. If it is not possible to put such notice in a particular Source - Code file due to its structure, then You must include such notice in a - location (such as a relevant directory) where a user would be likely - to look for such a notice. If You created one or more Modification(s) - You may add your name as a Contributor to the notice described in - Exhibit A. You must also duplicate this License in any documentation - for the Source Code where You describe recipients' rights or ownership - rights relating to Covered Code. You may choose to offer, and to - charge a fee for, warranty, support, indemnity or liability - obligations to one or more recipients of Covered Code. However, You - may do so only on Your own behalf, and not on behalf of the Initial - Developer or any Contributor. You must make it absolutely clear than - any such warranty, support, indemnity or liability obligation is - offered by You alone, and You hereby agree to indemnify the Initial - Developer and every Contributor for any liability incurred by the - Initial Developer or such Contributor as a result of warranty, - support, indemnity or liability terms You offer. - - 3.6. Distribution of Executable Versions. - You may distribute Covered Code in Executable form only if the - requirements of Section 3.1-3.5 have been met for that Covered Code, - and if You include a notice stating that the Source Code version of - the Covered Code is available under the terms of this License, - including a description of how and where You have fulfilled the - obligations of Section 3.2. The notice must be conspicuously included - in any notice in an Executable version, related documentation or - collateral in which You describe recipients' rights relating to the - Covered Code. You may distribute the Executable version of Covered - Code or ownership rights under a license of Your choice, which may - contain terms different from this License, provided that You are in - compliance with the terms of this License and that the license for the - Executable version does not attempt to limit or alter the recipient's - rights in the Source Code version from the rights set forth in this - License. If You distribute the Executable version under a different - license You must make it absolutely clear that any terms which differ - from this License are offered by You alone, not by the Initial - Developer or any Contributor. You hereby agree to indemnify the - Initial Developer and every Contributor for any liability incurred by - the Initial Developer or such Contributor as a result of any such - terms You offer. - - 3.7. Larger Works. - You may create a Larger Work by combining Covered Code with other code - not governed by the terms of this License and distribute the Larger - Work as a single product. In such a case, You must make sure the - requirements of this License are fulfilled for the Covered Code. - -4. Inability to Comply Due to Statute or Regulation. - - If it is impossible for You to comply with any of the terms of this - License with respect to some or all of the Covered Code due to - statute, judicial order, or regulation then You must: (a) comply with - the terms of this License to the maximum extent possible; and (b) - describe the limitations and the code they affect. Such description - must be included in the LEGAL file described in Section 3.4 and must - be included with all distributions of the Source Code. Except to the - extent prohibited by statute or regulation, such description must be - sufficiently detailed for a recipient of ordinary skill to be able to - understand it. - -5. Application of this License. - - This License applies to code to which the Initial Developer has - attached the notice in Exhibit A and to related Covered Code. - -6. Versions of the License. - - 6.1. New Versions. - Netscape Communications Corporation ("Netscape") may publish revised - and/or new versions of the License from time to time. Each version - will be given a distinguishing version number. - - 6.2. Effect of New Versions. - Once Covered Code has been published under a particular version of the - License, You may always continue to use it under the terms of that - version. You may also choose to use such Covered Code under the terms - of any subsequent version of the License published by Netscape. No one - other than Netscape has the right to modify the terms applicable to - Covered Code created under this License. - - 6.3. Derivative Works. - If You create or use a modified version of this License (which you may - only do in order to apply it to code which is not already Covered Code - governed by this License), You must (a) rename Your license so that - the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", - "MPL", "NPL" or any confusingly similar phrase do not appear in your - license (except to note that your license differs from this License) - and (b) otherwise make it clear that Your version of the license - contains terms which differ from the Mozilla Public License and - Netscape Public License. (Filling in the name of the Initial - Developer, Original Code or Contributor in the notice described in - Exhibit A shall not of themselves be deemed to be modifications of - this License.) - -7. DISCLAIMER OF WARRANTY. - - COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, - WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF - DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. - THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE - IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, - YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE - COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER - OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF - ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. - -8. TERMINATION. - - 8.1. This License and the rights granted hereunder will terminate - automatically if You fail to comply with terms herein and fail to cure - such breach within 30 days of becoming aware of the breach. All - sublicenses to the Covered Code which are properly granted shall - survive any termination of this License. Provisions which, by their - nature, must remain in effect beyond the termination of this License - shall survive. - - 8.2. If You initiate litigation by asserting a patent infringement - claim (excluding declatory judgment actions) against Initial Developer - or a Contributor (the Initial Developer or Contributor against whom - You file such action is referred to as "Participant") alleging that: - - (a) such Participant's Contributor Version directly or indirectly - infringes any patent, then any and all rights granted by such - Participant to You under Sections 2.1 and/or 2.2 of this License - shall, upon 60 days notice from Participant terminate prospectively, - unless if within 60 days after receipt of notice You either: (i) - agree in writing to pay Participant a mutually agreeable reasonable - royalty for Your past and future use of Modifications made by such - Participant, or (ii) withdraw Your litigation claim with respect to - the Contributor Version against such Participant. If within 60 days - of notice, a reasonable royalty and payment arrangement are not - mutually agreed upon in writing by the parties or the litigation claim - is not withdrawn, the rights granted by Participant to You under - Sections 2.1 and/or 2.2 automatically terminate at the expiration of - the 60 day notice period specified above. - - (b) any software, hardware, or device, other than such Participant's - Contributor Version, directly or indirectly infringes any patent, then - any rights granted to You by such Participant under Sections 2.1(b) - and 2.2(b) are revoked effective as of the date You first made, used, - sold, distributed, or had made, Modifications made by that - Participant. - - 8.3. If You assert a patent infringement claim against Participant - alleging that such Participant's Contributor Version directly or - indirectly infringes any patent where such claim is resolved (such as - by license or settlement) prior to the initiation of patent - infringement litigation, then the reasonable value of the licenses - granted by such Participant under Sections 2.1 or 2.2 shall be taken - into account in determining the amount or value of any payment or - license. - - 8.4. In the event of termination under Sections 8.1 or 8.2 above, - all end user license agreements (excluding distributors and resellers) - which have been validly granted by You or any distributor hereunder - prior to termination shall survive termination. - -9. LIMITATION OF LIABILITY. - - UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT - (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL - DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, - OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR - ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY - CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, - WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER - COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN - INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF - LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY - RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW - PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE - EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO - THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. - -10. U.S. GOVERNMENT END USERS. - - The Covered Code is a "commercial item," as that term is defined in - 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer - software" and "commercial computer software documentation," as such - terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 - C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), - all U.S. Government End Users acquire Covered Code with only those - rights set forth herein. - -11. MISCELLANEOUS. - - This License represents the complete agreement concerning subject - matter hereof. If any provision of this License is held to be - unenforceable, such provision shall be reformed only to the extent - necessary to make it enforceable. This License shall be governed by - California law provisions (except to the extent applicable law, if - any, provides otherwise), excluding its conflict-of-law provisions. - With respect to disputes in which at least one party is a citizen of, - or an entity chartered or registered to do business in the United - States of America, any litigation relating to this License shall be - subject to the jurisdiction of the Federal Courts of the Northern - District of California, with venue lying in Santa Clara County, - California, with the losing party responsible for costs, including - without limitation, court costs and reasonable attorneys' fees and - expenses. The application of the United Nations Convention on - Contracts for the International Sale of Goods is expressly excluded. - Any law or regulation which provides that the language of a contract - shall be construed against the drafter shall not apply to this - License. - -12. RESPONSIBILITY FOR CLAIMS. - - As between Initial Developer and the Contributors, each party is - responsible for claims and damages arising, directly or indirectly, - out of its utilization of rights under this License and You agree to - work with Initial Developer and Contributors to distribute such - responsibility on an equitable basis. Nothing herein is intended or - shall be deemed to constitute any admission of liability. - -13. MULTIPLE-LICENSED CODE. - - Initial Developer may designate portions of the Covered Code as - "Multiple-Licensed". "Multiple-Licensed" means that the Initial - Developer permits you to utilize portions of the Covered Code under - Your choice of the NPL or the alternative licenses, if any, specified - by the Initial Developer in the file described in Exhibit A. - -EXHIBIT A -Mozilla Public License. - - ``The contents of this file are subject to the Mozilla Public License - Version 1.1 (the "License"); you may not use this file except in - compliance with the License. You may obtain a copy of the License at - http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the - License for the specific language governing rights and limitations - under the License. - - The Original Code is ______________________________________. - - The Initial Developer of the Original Code is ________________________. - Portions created by ______________________ are Copyright (C) ______ - _______________________. All Rights Reserved. - - Contributor(s): ______________________________________. - - Alternatively, the contents of this file may be used under the terms - of the _____ license (the "[___] License"), in which case the - provisions of [______] License are applicable instead of those - above. If you wish to allow use of your version of this file only - under the terms of the [____] License and not to allow others to use - your version of this file under the MPL, indicate your decision by - deleting the provisions above and replace them with the notice and - other provisions required by the [___] License. If you do not delete - the provisions above, a recipient may use your version of this file - under either the MPL or the [___] License." - - [NOTE: The text of this Exhibit A may differ slightly from the text of - the notices in the Source Code files of the Original Code. You should - use the text of this Exhibit A rather than the text found in the - Original Code Source Code for Your Modifications.] - diff --git a/taglib/ConfigureChecks.cmake b/taglib/ConfigureChecks.cmake deleted file mode 100644 index b0f164a..0000000 --- a/taglib/ConfigureChecks.cmake +++ /dev/null @@ -1,226 +0,0 @@ -include(CheckIncludeFile) -include(CheckIncludeFiles) -include(CheckSymbolExists) -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 - int main() { - std::atomic x; - x.fetch_add(1); - x.fetch_sub(1); - return 0; - } -" HAVE_STD_ATOMIC) - -if(NOT HAVE_STD_ATOMIC) - check_cxx_source_compiles(" - #include - int main() { - boost::atomic 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 - 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 - 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 - 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 - 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 - 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 - int main() { - OSSwapInt16(0); - OSSwapInt32(0); - OSSwapInt64(0); - return 0; - } - " HAVE_MAC_BYTESWAP) - - if(NOT HAVE_MAC_BYTESWAP) - check_cxx_source_compiles(" - #include - 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 - int main() { char buf[20]; snprintf(buf, 20, \"%d\", 1); return 0; } -" HAVE_SNPRINTF) - -if(NOT HAVE_SNPRINTF) - check_cxx_source_compiles(" - #include - 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 - int main() { - std::codecvt_utf8_utf16 x; - return 0; - } -" HAVE_STD_CODECVT) - -# Check for libz using the cmake supplied FindZLIB.cmake - -find_package(ZLIB) -if(ZLIB_FOUND) - set(HAVE_ZLIB 1) -else() - 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) -endif() diff --git a/taglib/Doxyfile.cmake b/taglib/Doxyfile.cmake deleted file mode 100644 index 6da30bb..0000000 --- a/taglib/Doxyfile.cmake +++ /dev/null @@ -1,210 +0,0 @@ -# Doxyfile 1.3.4 - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- -PROJECT_NAME = TagLib -PROJECT_NUMBER = ${TAGLIB_LIB_VERSION_STRING} -OUTPUT_DIRECTORY = doc -OUTPUT_LANGUAGE = English -USE_WINDOWS_ENCODING = NO -BRIEF_MEMBER_DESC = YES -REPEAT_BRIEF = YES -ALWAYS_DETAILED_SEC = NO -INLINE_INHERITED_MEMB = NO -FULL_PATH_NAMES = NO -STRIP_FROM_PATH = -SHORT_NAMES = NO -JAVADOC_AUTOBRIEF = NO -MULTILINE_CPP_IS_BRIEF = NO -DETAILS_AT_TOP = NO -INHERIT_DOCS = YES -DISTRIBUTE_GROUP_DOC = NO -TAB_SIZE = 4 -ALIASES = -OPTIMIZE_OUTPUT_FOR_C = NO -OPTIMIZE_OUTPUT_JAVA = NO -SUBGROUPING = YES -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- -EXTRACT_ALL = YES -EXTRACT_PRIVATE = NO -EXTRACT_STATIC = NO -EXTRACT_LOCAL_CLASSES = NO -HIDE_UNDOC_MEMBERS = NO -HIDE_UNDOC_CLASSES = NO -HIDE_FRIEND_COMPOUNDS = NO -HIDE_IN_BODY_DOCS = NO -INTERNAL_DOCS = YES -CASE_SENSE_NAMES = YES -HIDE_SCOPE_NAMES = NO -SHOW_INCLUDE_FILES = YES -INLINE_INFO = YES -SORT_MEMBER_DOCS = YES -GENERATE_TODOLIST = NO -GENERATE_TESTLIST = NO -GENERATE_BUGLIST = NO -GENERATE_DEPRECATEDLIST= NO -ENABLED_SECTIONS = -MAX_INITIALIZER_LINES = 30 -SHOW_USED_FILES = YES -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- -QUIET = NO -WARNINGS = YES -WARN_IF_UNDOCUMENTED = NO -WARN_IF_DOC_ERROR = YES -WARN_FORMAT = "$file:$line: $text" -WARN_LOGFILE = -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- -INPUT = @CMAKE_SOURCE_DIR@/taglib -FILE_PATTERNS = *.h \ - *.hh \ - *.H -RECURSIVE = YES -EXCLUDE = -EXCLUDE_SYMLINKS = NO -EXCLUDE_PATTERNS = -EXAMPLE_PATH = -EXAMPLE_PATTERNS = -EXAMPLE_RECURSIVE = NO -IMAGE_PATH = -INPUT_FILTER = -FILTER_SOURCE_FILES = NO -#--------------------------------------------------------------------------- -# configuration options related to source browsing -#--------------------------------------------------------------------------- -SOURCE_BROWSER = NO -INLINE_SOURCES = NO -STRIP_CODE_COMMENTS = YES -REFERENCED_BY_RELATION = YES -REFERENCES_RELATION = YES -VERBATIM_HEADERS = YES -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- -ALPHABETICAL_INDEX = YES -COLS_IN_ALPHA_INDEX = 5 -IGNORE_PREFIX = -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- -GENERATE_HTML = YES -HTML_OUTPUT = html -HTML_FILE_EXTENSION = .html -HTML_HEADER = @CMAKE_SOURCE_DIR@/doc/api-header.html -HTML_FOOTER = @CMAKE_SOURCE_DIR@/doc/api-footer.html -HTML_STYLESHEET = @CMAKE_SOURCE_DIR@/doc/taglib-api.css -HTML_ALIGN_MEMBERS = YES -GENERATE_HTMLHELP = NO -CHM_FILE = -HHC_LOCATION = -GENERATE_CHI = NO -BINARY_TOC = NO -TOC_EXPAND = NO -DISABLE_INDEX = YES -ENUM_VALUES_PER_LINE = 4 -GENERATE_TREEVIEW = NO -TREEVIEW_WIDTH = 250 -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- -GENERATE_LATEX = NO -LATEX_OUTPUT = latex -LATEX_CMD_NAME = latex -MAKEINDEX_CMD_NAME = makeindex -COMPACT_LATEX = NO -PAPER_TYPE = letter -EXTRA_PACKAGES = -LATEX_HEADER = -PDF_HYPERLINKS = YES -USE_PDFLATEX = YES -LATEX_BATCHMODE = NO -LATEX_HIDE_INDICES = NO -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- -GENERATE_RTF = NO -RTF_OUTPUT = rtf -COMPACT_RTF = NO -RTF_HYPERLINKS = NO -RTF_STYLESHEET_FILE = -RTF_EXTENSIONS_FILE = -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- -GENERATE_MAN = NO -MAN_OUTPUT = man -MAN_EXTENSION = .3 -MAN_LINKS = NO -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- -GENERATE_XML = NO -XML_OUTPUT = xml -XML_SCHEMA = -XML_DTD = -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- -GENERATE_AUTOGEN_DEF = NO -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- -GENERATE_PERLMOD = NO -PERLMOD_LATEX = NO -PERLMOD_PRETTY = YES -PERLMOD_MAKEVAR_PREFIX = -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- -ENABLE_PREPROCESSING = YES -MACRO_EXPANSION = NO -EXPAND_ONLY_PREDEF = NO -SEARCH_INCLUDES = YES -INCLUDE_PATH = -INCLUDE_FILE_PATTERNS = -PREDEFINED = DO_NOT_DOCUMENT \ - DOXYGEN \ - WITH_MP4 \ - WITH_ASF -EXPAND_AS_DEFINED = -SKIP_FUNCTION_MACROS = YES -#--------------------------------------------------------------------------- -# Configuration::addtions related to external references -#--------------------------------------------------------------------------- -TAGFILES = -GENERATE_TAGFILE = -ALLEXTERNALS = NO -EXTERNAL_GROUPS = YES -PERL_PATH = /usr/bin/perl -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- -CLASS_DIAGRAMS = YES -HIDE_UNDOC_RELATIONS = YES -HAVE_DOT = YES -CLASS_GRAPH = YES -COLLABORATION_GRAPH = YES -UML_LOOK = NO -TEMPLATE_RELATIONS = YES -INCLUDE_GRAPH = YES -INCLUDED_BY_GRAPH = YES -CALL_GRAPH = NO -GRAPHICAL_HIERARCHY = YES -DOT_IMAGE_FORMAT = png -DOT_PATH = -DOTFILE_DIRS = -MAX_DOT_GRAPH_WIDTH = 1024 -MAX_DOT_GRAPH_HEIGHT = 1024 -MAX_DOT_GRAPH_DEPTH = 0 -GENERATE_LEGEND = YES -DOT_CLEANUP = YES -#--------------------------------------------------------------------------- -# Configuration::addtions related to the search engine -#--------------------------------------------------------------------------- -SEARCHENGINE = NO diff --git a/taglib/INSTALL b/taglib/INSTALL deleted file mode 100644 index 9e6e807..0000000 --- a/taglib/INSTALL +++ /dev/null @@ -1,157 +0,0 @@ -TagLib Installation -=================== - -TagLib uses the CMake build system. As a user, you will most likely want to -build TagLib in release mode and install it into a system-wide location. -This can be done using the following commands: - - cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_RELEASE_TYPE=Release . - make - sudo make install - -In order to build the included examples, use the BUILD_EXAMPLES option: - - cmake -DBUILD_EXAMPLES=ON [...] - -See http://www.cmake.org/cmake/help/runningcmake.html for generic help on -running CMake. - -Mac OS X --------- - -On Mac OS X, you might want to build a framework that can be easily integrated -into your application. If you set the BUILD_FRAMEWORK option on, it will compile -TagLib as a framework. For example, the following command can be used to build -an Universal Binary framework with Mac OS X 10.4 as the deployment target: - - cmake -DCMAKE_BUILD_TYPE=Release \ - -DBUILD_FRAMEWORK=ON \ - -DCMAKE_C_COMPILER=/usr/bin/gcc-4.0 \ - -DCMAKE_CXX_COMPILER=/usr/bin/c++-4.0 \ - -DCMAKE_OSX_SYSROOT=/Developer/SDKs/MacOSX10.4u.sdk/ \ - -DCMAKE_OSX_DEPLOYMENT_TARGET=10.4 \ - -DCMAKE_OSX_ARCHITECTURES="ppc;i386;x86_64" - -For a 10.6 Snow Leopard static library with both 32-bit and 64-bit code, use: - - cmake -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_OSX_DEPLOYMENT_TARGET=10.6 \ - -DCMAKE_OSX_ARCHITECTURES="i386;x86_64" \ - -DENABLE_STATIC=ON \ - -DCMAKE_INSTALL_PREFIX="" - -After 'make', and 'make install', add libtag.a to your XCode project, and add -the include folder to the project's User Header Search Paths. - -Windows -------- - -It's Windows ... Systems vary! -This means you need to adjust things to suit your system, especially paths. - -Tested with: - Microsoft Visual Studio 2010 - Gcc by mingw-w64.sf.net v4.6.3 (Strawberry Perl 32b) - MinGW32-4.8.0 - -Requirements: - 1. Tool chain, Build Environment, Whatever ya want to call it ... - Installed and working. - 2. CMake program. (Available at: www.cmake.org) - Installed and working. - -Optional: - 1. Zlib library. - Available in some Tool Chains, Not all. - Search the web, Take your choice. - -Useful configuration options used with CMake (GUI and/or Command line): - Any of the ZLIB_ variables may be used at the command line, ZLIB_ROOT is only - available on the Command line. - ZLIB_ROOT= Where to find ZLib's root directory. - Assumes parent of: \include and \lib. - ZLIB_INCLUDE_DIR= Where to find ZLib's Include directory. - ZLIB_LIBRARY= Where to find ZLib's Library. - CMAKE_INSTALL_PREFIX= Where to install Taglib. - CMAKE_BUILD_TYPE= Release, Debug, etc ... (Not available in MSVC) - -The easiest way is at the Command Prompt. - MSVS Command Prompt for MSVS Users. - (Batch file and/or Shortcuts are your friends) - - 1. Build the Makefiles: - Replace "GENERATOR" with your needs. - For MSVS : "Visual Studio X" where X is the single or two digit version. - For MinGW: "MinGW Makefiles" - - C:\GitRoot\taglib> cmake -G "GENERATOR" -DCMAKE_INSTALL_PREFIX=C:\Libraries\taglib - - Or use the CMake GUI: - 1. Open CMake GUI. - 2. Set Paths. - "Where is the source code" and "Where to build the binaries" - Example, Both would be: C:\GitRoot\taglib - 3. Tick: Advanced - 4. Select: Configure - 5. Select: Generator - 6. Tick: Use default native compilers - 7. Select: Finish - Wait until done. - 5. If using ZLib, Scroll down. - (to the bottom of the list of options ... should go over them all) - 1. Edit: ZLIB_INCLUDE_DIR - 2. Edit: ZLIB_LIBRARY - 6. Select: Generate - - 2. Build the project: - MSVS: - C:\GitRoot\taglib> msbuild all_build.vcxproj /p:Configuration=Release - OR (Depending on MSVS version or personal choice) - C:\GitRoot\taglib> devenv all_build.vcxproj /build Release - MinGW: - C:\GitRoot\taglib> gmake - OR (Depending on MinGW install) - C:\GitRoot\taglib> mingw32-make - - Or in the MSVS GUI: - 1. Open MSVS. - 2. Open taglib solution. - 3. Set build type to: Release (look in the tool bars) - 2. Hit F7 to build the solution. (project) - - 3. Install the project: - (Change 'install' to 'uninstall' to uninstall the project) - MSVS: - C:\GitRoot\taglib> msbuild install.vcxproj - OR (Depending on MSVC version or personal choice) - C:\GitRoot\taglib> devenv install.vcxproj - MinGW: - C:\GitRoot\taglib> gmake install - OR (Depending on MinGW install) - C:\GitRoot\taglib> mingw32-make install - - Or in the MSVS GUI: - 1. Open project. - 2. Open Solution Explorer. - 3. Right Click: INSTALL - 4. Select: Project Only - 5. Select: Build Only INSTALL - -To build a static library enable the following two options with CMake. - -DENABLE_STATIC=ON -DENABLE_STATIC_RUNTIME=ON - -Including ENABLE_STATIC_RUNTIME=ON indicates you want TagLib built using the -static runtime library, rather than the DLL form of the runtime. - -Unit Tests ----------- - -If you want to run the test suite to make sure TagLib works properly on your -system, you need to have cppunit installed. To build the tests, include -the option -DBUILD_TESTS=on when running cmake. - -The test suite has a custom target in the build system, so you can run -the tests using make: - - make check - diff --git a/taglib/NEWS b/taglib/NEWS deleted file mode 100644 index 72d41fb..0000000 --- a/taglib/NEWS +++ /dev/null @@ -1,189 +0,0 @@ -TagLib 1.9.1 (Oct 8, 2013) -========================== - - * Fixed binary incompatible change in TagLib::Map and TagLib::List. - * Fixed constructing String from ByteVector. - * Fixed compilation on MSVC with the /Zc:wchar_t- option. - * Fixed detecting of RIFF files with invalid chunk sizes. - * Added TagLib::MP4::PropertyMap::codec(). - -TagLib 1.9 (Oct 6, 2013) -======================== - - * Added support for the Ogg Opus file format. - * Added support for INFO tags in WAV files. - * Changed FileStream to use Windows file API. - * Included taglib-config.cmd script for Windows. - * New ID3v1::Tag methods for working directly with genre numbers. - * New MPEG::File methods for checking which tags are saved in the file. - * Added support for the PropertyMap API to ASF and MP4 files. - * Added MusicBrainz identifiers to the PropertyMap API. - * Allowed reading of MP4 cover art without an explicitly specified format. - * Better parsing of corrupted FLAC files. - * Fixed saving of PropertyMap comments without description into ID3v2 tags. - * Fixed crash when parsing certain XM files. - * Fixed compilation of unit test with clang. - * Better handling of files that can't be open or have read-only permissions. - * Improved atomic reference counting. - * New hookable API for debug messages. - * More complete Windows install instructions. - * Many smaller bug fixes and performance improvements. - -TagLib 1.8 (Sep 6, 2012) -======================== - -1.8: - - * Added support for OWNE ID3 frames. - * Changed key validation in the new PropertyMap API. - * ID3v1::Tag::setStringHandler will no londer delete the previous handler, - the caller is responsible for this. - * File objects will also no longer delete the passed IOStream objects. It - should be done in the caller code after the File object is no longer - used. - * Added ID3v2::Tag::setLatin1StringHandler for custom handling of - latin1-encoded text in ID3v2 frames. - * Fixed validation of ID3v2 frame IDs (IDs with '0' were ignored). - -1.8 BETA: - - * New API for accessing tags by name. - * New abstract I/O stream layer to allow custom I/O handlers. - * Support for writing ID3v2.3 tags. - * Support for various module file formats (MOD, S3M, IT, XM). - * Support for MP4 and ASF is now enabled by default. - * Started using atomic int operations for reference counting. - * Added methods for checking if WMA and MP4 files are DRM-protected. - * Added taglib_free to the C bindings. - * New method to allow removing pictures from FLAC files. - * Support for reading audio properties from ALAC and Musepack SV8 files. - * Added replay-gain information to Musepack audio properties. - * Support for APEv2 binary tags. - * Many AudioProperties subclasses now provide information about the total number of samples. - * Various small bug fixes. - -TagLib 1.7.2 (Apr 20, 2012) -=========================== - - * Fixed division by zero while parsing corrupted MP4 files (CVE-2012-2396). - * Fixed compilation on Haiku. - -TagLib 1.7.1 (Mar 17, 2012) -=========================== - - * Improved parsing of corrupted WMA, RIFF and OGG files. - * Fixed a memory leak in the WMA parser. - * Fixed a memory leak in the FLAC parser. - * Fixed a possible division by zero in the APE parser. - * Added detection of TTA2 files. - * Fixed saving of multiple identically named tags to Vorbis Comments. - -TagLib 1.7 (Mar 11, 2011) -========================= - -1.7: - - * Fixed memory leaks in the FLAC file format parser. - * Fixed bitrate calculation for WAV files. - -1.7 RC1: - - * Support for reading/writing tags from Monkey's Audio files. (BUG:210404) - * Support for reading/writing embedded pictures from WMA files. - * Support for reading/writing embedded pictures from FLAC files (BUG:218696). - * Implemented APE::Tag::isEmpty() to check for all APE tags, not just the - basic ones. - * Added reading of WAV audio length. (BUG:116033) - * Exposed FLAC MD5 signature of the uncompressed audio stream via - FLAC::Properties::signature(). (BUG:160172) - * Added function ByteVector::toHex() for hex-encoding of byte vectors. - * WavPack reader now tries to get the audio length by finding the final - block, if the header doesn't have the information. (BUG:258016) - * Fixed a memory leak in the ID3v2.2 PIC frame parser. (BUG:257007) - * Fixed writing of RIFF files with even chunk sizes. (BUG:243954) - * Fixed compilation on MSVC 2010. - * Removed support for building using autoconf/automake. - * API docs can be now built using "make docs". - -TagLib 1.6.3 (Apr 17, 2010) -=========================== - - * Fixed definitions of the TAGLIB_WITH_MP4 and TAGLIB_WITH_ASF macros. - * Fixed upgrading of ID3v2.3 genre frame with ID3v1 code 0 (Blues). - * New method `int String::toInt(bool *ok)` which can return whether the - conversion to a number was successfull. - * Fixed parsing of incorrectly written lengths in ID3v2 (affects mainly - compressed frames). (BUG:231075) - -TagLib 1.6.2 (Apr 9, 2010) -========================== - - * Read Vorbis Comments from the first FLAC metadata block, if there are - multipe ones. (BUG:211089) - * Fixed a memory leak in FileRef's OGA format detection. - * Fixed compilation with the Sun Studio compiler. (BUG:215225) - * Handle WM/TrackNumber attributes with DWORD content in WMA files. - (BUG:218526) - * More strict check if something is a valid MP4 file. (BUG:216819) - * Correctly save MP4 int-pair atoms with flags set to 0. - * Fixed compilation of the test runner on Windows. - * Store ASF attributes larger than 64k in the metadata library object. - * Ignore trailing non-data atoms when parsing MP4 covr atoms. - * Don't upgrade ID3v2.2 frame TDA to TDRC. (BUG:228968) - -TagLib 1.6.1 (Oct 31, 2009) -=========================== - - * Better detection of the audio codec of .oga files in FileRef. - * Fixed saving of Vorbis comments to Ogg FLAC files. TagLib tried to - include the Vorbis framing bit, which is only correct for Ogg Vorbis. - * Public symbols now have explicitly set visibility to "default" on GCC. - * Added missing exports for static ID3v1 functions. - * Fixed a typo in taglib_c.pc - * Fixed a failing test on ppc64. - * Support for binary 'covr' atom in MP4 files. TagLib 1.6 treated them - as text atoms, which corrupted them in some cases. - * Fixed ID3v1-style genre to string conversion in MP4 files. - -TagLib 1.6 (Sep 13, 2009) -========================= - -1.6: - - * New CMake option to build a static version - ENABLE_STATIC. - * Added support for disabling dllimport/dllexport on Windows using the - TAGLIB_STATIC macro. - * Support for parsing the obsolete 'gnre' MP4 atom. - * New cpp macros TAGLIB_WITH_MP4 and TAGLIB_WITH_ASF to determin if - TagLib was built with MP4/ASF support. - -1.6 RC1: - - * Split Ogg packets larger than 64k into multiple pages. (BUG:171957) - * TagLib can now use FLAC padding block. (BUG:107659) - * ID3v2.2 frames are now not incorrectly saved. (BUG:176373) - * Support for ID3v2.2 PIC frames. (BUG:167786) - * Fixed a bug in ByteVectorList::split(). - * XiphComment::year() now falls back to YEAR if DATE doesn't exist - and XiphComment::year() falls back to TRACKNUM if TRACKNUMBER doesn't - exist. (BUG:144396) - * Improved ID3v2.3 genre parsing. (BUG:188578) - * Better checking of corrupted ID3v2 APIC data. (BUG:168382) - * Bitrate calculating using the Xing header now uses floating point - numbers. (BUG:172556) - * New TagLib::String method rfind(). - * Added support for MP4 file format with iTunes-style metadata [optional]. - * Added support for ASF (WMA) file format [optional]. - * Fixed crash when saving a Locator APEv2 tag. (BUG:169810) - * Fixed a possible crash in the non-const version of String::operator[] - and in String::operator+=. (BUG:169389) - * Added support for PRIV ID3v2 frames. - * Empty ID3v2 genres are no longer treated as numeric ID3v1 genres. - * Added support for the POPM (rating/playcount) ID3v2 frame. - * Generic RIFF file format support: - * Support for AIFF files with ID3v2 tags. - * Support for WAV files with ID3v2 tags. - * Fixed crash on handling unsupported ID3v2 frames, e.g. on encrypted - frames. (BUG:161721) - * Fixed overflow while calculating bitrate of FLAC files with a very - high bitrate. diff --git a/taglib/bindings/CMakeLists.txt b/taglib/bindings/CMakeLists.txt deleted file mode 100644 index d019843..0000000 --- a/taglib/bindings/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -add_subdirectory(c) diff --git a/taglib/bindings/README b/taglib/bindings/README deleted file mode 100644 index bfbd44a..0000000 --- a/taglib/bindings/README +++ /dev/null @@ -1,6 +0,0 @@ -There are a few other people that have done bindings externally that I have -been made aware of. I have not personally reviewed these bindings, but I'm -listing them here so that those who find them useful are able to find them: - -http://developer.kde.org/~wheeler/taglib.html#bindings - diff --git a/taglib/bindings/c/CMakeLists.txt b/taglib/bindings/c/CMakeLists.txt deleted file mode 100644 index 2d9dafc..0000000 --- a/taglib/bindings/c/CMakeLists.txt +++ /dev/null @@ -1,68 +0,0 @@ -include_directories( - ${CMAKE_CURRENT_SOURCE_DIR}/../../taglib - ${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/toolkit - ${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/asf - ${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/mpeg - ${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/ogg - ${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/ogg/vorbis - ${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/ogg/flac - ${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/flac - ${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/mpc - ${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/mp4 - ${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/mpeg/id3v2 - ${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/mpeg/id3v2/frames - ${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/wavpack - ${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/ogg/speex - ${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/trueaudio -) - -set(tag_c_HDRS tag_c.h) - -add_library(tag_c tag_c.cpp ${tag_c_HDRS}) - -target_link_libraries(tag_c tag) -set_target_properties(tag_c PROPERTIES PUBLIC_HEADER "${tag_c_HDRS}") -if(BUILD_FRAMEWORK) - set_target_properties(tag_c PROPERTIES FRAMEWORK TRUE) -endif() - -# On Solaris we need to explicitly add the C++ standard and runtime -# libraries to the libs used by the C bindings, because those C bindings -# themselves won't pull in the C++ libs -- and if a C application is -# using the C bindings then we get link errors. -check_library_exists(Crun __RTTI___ "" HAVE_CRUN_LIB) -if(HAVE_CRUN_LIB) - # Which libraries to link depends critically on which - # STL version is going to be used by your application - # and which runtime is in use. While Crun is pretty much - # the only game in town, the three available STLs -- Cstd, - # stlport4 and stdcxx -- make this a mess. The KDE-Solaris - # team supports stdcxx (Apache RogueWave stdcxx 4.1.3). - - # According to http://bugs.kde.org/show_bug.cgi?id=215225 the library can have the following two names: - find_library(ROGUEWAVE_STDCXX_LIBRARY NAMES stdcxx4 stdcxx) - if(NOT ROGUEWAVE_STDCXX_LIBRARY) - message(FATAL_ERROR "Did not find supported STL library (tried stdcxx4 and stdcxx)") - endif() - target_link_libraries(tag_c ${ROGUEWAVE_STDCXX_LIBRARY} Crun) -endif() - -set_target_properties(tag_c PROPERTIES - VERSION 0.0.0 - SOVERSION 0 - DEFINE_SYMBOL MAKE_TAGLIB_C_LIB - INSTALL_NAME_DIR ${LIB_INSTALL_DIR} -) -install(TARGETS tag_c - FRAMEWORK DESTINATION ${FRAMEWORK_INSTALL_DIR} - LIBRARY DESTINATION ${LIB_INSTALL_DIR} - RUNTIME DESTINATION ${BIN_INSTALL_DIR} - ARCHIVE DESTINATION ${LIB_INSTALL_DIR} - PUBLIC_HEADER DESTINATION ${INCLUDE_INSTALL_DIR}/taglib -) - -if(NOT WIN32 AND NOT BUILD_FRAMEWORK) - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/taglib_c.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/taglib_c.pc) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/taglib_c.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) -endif() - diff --git a/taglib/bindings/c/tag_c.cpp b/taglib/bindings/c/tag_c.cpp deleted file mode 100644 index 2ae8c7d..0000000 --- a/taglib/bindings/c/tag_c.cpp +++ /dev/null @@ -1,290 +0,0 @@ -/*************************************************************************** - copyright : (C) 2003 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * - * USA * - ***************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tag_c.h" - -using namespace TagLib; - -static List strings; -static bool unicodeStrings = true; -static bool stringManagementEnabled = true; - -void taglib_set_strings_unicode(BOOL unicode) -{ - unicodeStrings = bool(unicode); -} - -void taglib_set_string_management_enabled(BOOL management) -{ - stringManagementEnabled = bool(management); -} - -void taglib_free(void* pointer) -{ - free(pointer); -} - -//////////////////////////////////////////////////////////////////////////////// -// TagLib::File wrapper -//////////////////////////////////////////////////////////////////////////////// - -TagLib_File *taglib_file_new(const char *filename) -{ - return reinterpret_cast(FileRef::create(filename)); -} - -TagLib_File *taglib_file_new_type(const char *filename, TagLib_File_Type type) -{ - switch(type) { - case TagLib_File_MPEG: - return reinterpret_cast(new MPEG::File(filename)); - case TagLib_File_OggVorbis: - return reinterpret_cast(new Ogg::Vorbis::File(filename)); - case TagLib_File_FLAC: - return reinterpret_cast(new FLAC::File(filename)); - case TagLib_File_MPC: - return reinterpret_cast(new MPC::File(filename)); - case TagLib_File_OggFlac: - return reinterpret_cast(new Ogg::FLAC::File(filename)); - case TagLib_File_WavPack: - return reinterpret_cast(new WavPack::File(filename)); - case TagLib_File_Speex: - return reinterpret_cast(new Ogg::Speex::File(filename)); - case TagLib_File_TrueAudio: - return reinterpret_cast(new TrueAudio::File(filename)); - case TagLib_File_MP4: - return reinterpret_cast(new MP4::File(filename)); - case TagLib_File_ASF: - return reinterpret_cast(new ASF::File(filename)); - default: - return 0; - } - - return 0; -} - -void taglib_file_free(TagLib_File *file) -{ - delete reinterpret_cast(file); -} - -BOOL taglib_file_is_valid(const TagLib_File *file) -{ - return reinterpret_cast(file)->isValid(); -} - -TagLib_Tag *taglib_file_tag(const TagLib_File *file) -{ - const File *f = reinterpret_cast(file); - return reinterpret_cast(f->tag()); -} - -const TagLib_AudioProperties *taglib_file_audioproperties(const TagLib_File *file) -{ - const File *f = reinterpret_cast(file); - return reinterpret_cast(f->audioProperties()); -} - -BOOL taglib_file_save(TagLib_File *file) -{ - return reinterpret_cast(file)->save(); -} - -//////////////////////////////////////////////////////////////////////////////// -// TagLib::Tag wrapper -//////////////////////////////////////////////////////////////////////////////// - -char *taglib_tag_title(const TagLib_Tag *tag) -{ - const Tag *t = reinterpret_cast(tag); - char *s = ::strdup(t->title().toCString(unicodeStrings)); - if(stringManagementEnabled) - strings.append(s); - return s; -} - -char *taglib_tag_artist(const TagLib_Tag *tag) -{ - const Tag *t = reinterpret_cast(tag); - char *s = ::strdup(t->artist().toCString(unicodeStrings)); - if(stringManagementEnabled) - strings.append(s); - return s; -} - -char *taglib_tag_album(const TagLib_Tag *tag) -{ - const Tag *t = reinterpret_cast(tag); - char *s = ::strdup(t->album().toCString(unicodeStrings)); - if(stringManagementEnabled) - strings.append(s); - return s; -} - -char *taglib_tag_comment(const TagLib_Tag *tag) -{ - const Tag *t = reinterpret_cast(tag); - char *s = ::strdup(t->comment().toCString(unicodeStrings)); - if(stringManagementEnabled) - strings.append(s); - return s; -} - -char *taglib_tag_genre(const TagLib_Tag *tag) -{ - const Tag *t = reinterpret_cast(tag); - char *s = ::strdup(t->genre().toCString(unicodeStrings)); - if(stringManagementEnabled) - strings.append(s); - return s; -} - -unsigned int taglib_tag_year(const TagLib_Tag *tag) -{ - const Tag *t = reinterpret_cast(tag); - return t->year(); -} - -unsigned int taglib_tag_track(const TagLib_Tag *tag) -{ - const Tag *t = reinterpret_cast(tag); - return t->track(); -} - -void taglib_tag_set_title(TagLib_Tag *tag, const char *title) -{ - Tag *t = reinterpret_cast(tag); - t->setTitle(String(title, unicodeStrings ? String::UTF8 : String::Latin1)); -} - -void taglib_tag_set_artist(TagLib_Tag *tag, const char *artist) -{ - Tag *t = reinterpret_cast(tag); - t->setArtist(String(artist, unicodeStrings ? String::UTF8 : String::Latin1)); -} - -void taglib_tag_set_album(TagLib_Tag *tag, const char *album) -{ - Tag *t = reinterpret_cast(tag); - t->setAlbum(String(album, unicodeStrings ? String::UTF8 : String::Latin1)); -} - -void taglib_tag_set_comment(TagLib_Tag *tag, const char *comment) -{ - Tag *t = reinterpret_cast(tag); - t->setComment(String(comment, unicodeStrings ? String::UTF8 : String::Latin1)); -} - -void taglib_tag_set_genre(TagLib_Tag *tag, const char *genre) -{ - Tag *t = reinterpret_cast(tag); - t->setGenre(String(genre, unicodeStrings ? String::UTF8 : String::Latin1)); -} - -void taglib_tag_set_year(TagLib_Tag *tag, unsigned int year) -{ - Tag *t = reinterpret_cast(tag); - t->setYear(year); -} - -void taglib_tag_set_track(TagLib_Tag *tag, unsigned int track) -{ - Tag *t = reinterpret_cast(tag); - t->setTrack(track); -} - -void taglib_tag_free_strings() -{ - if(!stringManagementEnabled) - return; - - for(List::Iterator it = strings.begin(); it != strings.end(); ++it) - free(*it); - strings.clear(); -} - -//////////////////////////////////////////////////////////////////////////////// -// TagLib::AudioProperties wrapper -//////////////////////////////////////////////////////////////////////////////// - -int taglib_audioproperties_length(const TagLib_AudioProperties *audioProperties) -{ - const AudioProperties *p = reinterpret_cast(audioProperties); - return p->length(); -} - -int taglib_audioproperties_bitrate(const TagLib_AudioProperties *audioProperties) -{ - const AudioProperties *p = reinterpret_cast(audioProperties); - return p->bitrate(); -} - -int taglib_audioproperties_samplerate(const TagLib_AudioProperties *audioProperties) -{ - const AudioProperties *p = reinterpret_cast(audioProperties); - return p->sampleRate(); -} - -int taglib_audioproperties_channels(const TagLib_AudioProperties *audioProperties) -{ - const AudioProperties *p = reinterpret_cast(audioProperties); - return p->channels(); -} - -void taglib_id3v2_set_default_text_encoding(TagLib_ID3v2_Encoding encoding) -{ - String::Type type = String::Latin1; - - switch(encoding) - { - case TagLib_ID3v2_Latin1: - type = String::Latin1; - break; - case TagLib_ID3v2_UTF16: - type = String::UTF16; - break; - case TagLib_ID3v2_UTF16BE: - type = String::UTF16BE; - break; - case TagLib_ID3v2_UTF8: - type = String::UTF8; - break; - } - - ID3v2::FrameFactory::instance()->setDefaultTextEncoding(type); -} diff --git a/taglib/bindings/c/tag_c.h b/taglib/bindings/c/tag_c.h deleted file mode 100644 index 2e8b752..0000000 --- a/taglib/bindings/c/tag_c.h +++ /dev/null @@ -1,299 +0,0 @@ -/*************************************************************************** - copyright : (C) 2003 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * - * USA * - ***************************************************************************/ - -#ifndef TAGLIB_TAG_C -#define TAGLIB_TAG_C - -/* Do not include this in the main TagLib documentation. */ -#ifndef DO_NOT_DOCUMENT - -#ifdef __cplusplus -extern "C" { -#endif - -#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 -#define TAGLIB_C_EXPORT __declspec(dllimport) -#endif -#elif defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 1) -#define TAGLIB_C_EXPORT __attribute__ ((visibility("default"))) -#else -#define TAGLIB_C_EXPORT -#endif - -#ifndef BOOL -#define BOOL int -#endif - -/******************************************************************************* - * [ TagLib C Binding ] - * - * This is an interface to TagLib's "simple" API, meaning that you can read and - * modify media files in a generic, but not specialized way. This is a rough - * representation of TagLib::File and TagLib::Tag, for which the documentation - * is somewhat more complete and worth consulting. - *******************************************************************************/ - -/* - * These are used for type provide some type safety to the C API (as opposed to - * using void *, but pointers to them are simply cast to the corresponding C++ - * types in the implementation. - */ - -typedef struct { int dummy; } TagLib_File; -typedef struct { int dummy; } TagLib_Tag; -typedef struct { int dummy; } TagLib_AudioProperties; - -/*! - * By default all strings coming into or out of TagLib's C API are in UTF8. - * However, it may be desirable for TagLib to operate on Latin1 (ISO-8859-1) - * strings in which case this should be set to FALSE. - */ -TAGLIB_C_EXPORT void taglib_set_strings_unicode(BOOL unicode); - -/*! - * TagLib can keep track of strings that are created when outputting tag values - * and clear them using taglib_tag_clear_strings(). This is enabled by default. - * However if you wish to do more fine grained management of strings, you can do - * so by setting \a management to FALSE. - */ -TAGLIB_C_EXPORT void taglib_set_string_management_enabled(BOOL management); - -/*! - * Explicitly free a string returned from TagLib - */ -TAGLIB_C_EXPORT void taglib_free(void* pointer); - -/******************************************************************************* - * File API - ******************************************************************************/ - -typedef enum { - TagLib_File_MPEG, - TagLib_File_OggVorbis, - TagLib_File_FLAC, - TagLib_File_MPC, - TagLib_File_OggFlac, - TagLib_File_WavPack, - TagLib_File_Speex, - TagLib_File_TrueAudio, - TagLib_File_MP4, - TagLib_File_ASF -} TagLib_File_Type; - -/*! - * Creates a TagLib file based on \a filename. TagLib will try to guess the file - * type. - * - * \returns NULL if the file type cannot be determined or the file cannot - * be opened. - */ -TAGLIB_C_EXPORT TagLib_File *taglib_file_new(const char *filename); - -/*! - * Creates a TagLib file based on \a filename. Rather than attempting to guess - * the type, it will use the one specified by \a type. - */ -TAGLIB_C_EXPORT TagLib_File *taglib_file_new_type(const char *filename, TagLib_File_Type type); - -/*! - * Frees and closes the file. - */ -TAGLIB_C_EXPORT void taglib_file_free(TagLib_File *file); - -/*! - * Returns true if the file is open and readble and valid information for - * the Tag and / or AudioProperties was found. - */ - -TAGLIB_C_EXPORT BOOL taglib_file_is_valid(const TagLib_File *file); - -/*! - * Returns a pointer to the tag associated with this file. This will be freed - * automatically when the file is freed. - */ -TAGLIB_C_EXPORT TagLib_Tag *taglib_file_tag(const TagLib_File *file); - -/*! - * Returns a pointer to the the audio properties associated with this file. This - * will be freed automatically when the file is freed. - */ -TAGLIB_C_EXPORT const TagLib_AudioProperties *taglib_file_audioproperties(const TagLib_File *file); - -/*! - * Saves the \a file to disk. - */ -TAGLIB_C_EXPORT BOOL taglib_file_save(TagLib_File *file); - -/****************************************************************************** - * Tag API - ******************************************************************************/ - -/*! - * Returns a string with this tag's title. - * - * \note By default this string should be UTF8 encoded and its memory should be - * freed using taglib_tag_free_strings(). - */ -TAGLIB_C_EXPORT char *taglib_tag_title(const TagLib_Tag *tag); - -/*! - * Returns a string with this tag's artist. - * - * \note By default this string should be UTF8 encoded and its memory should be - * freed using taglib_tag_free_strings(). - */ -TAGLIB_C_EXPORT char *taglib_tag_artist(const TagLib_Tag *tag); - -/*! - * Returns a string with this tag's album name. - * - * \note By default this string should be UTF8 encoded and its memory should be - * freed using taglib_tag_free_strings(). - */ -TAGLIB_C_EXPORT char *taglib_tag_album(const TagLib_Tag *tag); - -/*! - * Returns a string with this tag's comment. - * - * \note By default this string should be UTF8 encoded and its memory should be - * freed using taglib_tag_free_strings(). - */ -TAGLIB_C_EXPORT char *taglib_tag_comment(const TagLib_Tag *tag); - -/*! - * Returns a string with this tag's genre. - * - * \note By default this string should be UTF8 encoded and its memory should be - * freed using taglib_tag_free_strings(). - */ -TAGLIB_C_EXPORT char *taglib_tag_genre(const TagLib_Tag *tag); - -/*! - * Returns the tag's year or 0 if year is not set. - */ -TAGLIB_C_EXPORT unsigned int taglib_tag_year(const TagLib_Tag *tag); - -/*! - * Returns the tag's track number or 0 if track number is not set. - */ -TAGLIB_C_EXPORT unsigned int taglib_tag_track(const TagLib_Tag *tag); - -/*! - * Sets the tag's title. - * - * \note By default this string should be UTF8 encoded. - */ -TAGLIB_C_EXPORT void taglib_tag_set_title(TagLib_Tag *tag, const char *title); - -/*! - * Sets the tag's artist. - * - * \note By default this string should be UTF8 encoded. - */ -TAGLIB_C_EXPORT void taglib_tag_set_artist(TagLib_Tag *tag, const char *artist); - -/*! - * Sets the tag's album. - * - * \note By default this string should be UTF8 encoded. - */ -TAGLIB_C_EXPORT void taglib_tag_set_album(TagLib_Tag *tag, const char *album); - -/*! - * Sets the tag's comment. - * - * \note By default this string should be UTF8 encoded. - */ -TAGLIB_C_EXPORT void taglib_tag_set_comment(TagLib_Tag *tag, const char *comment); - -/*! - * Sets the tag's genre. - * - * \note By default this string should be UTF8 encoded. - */ -TAGLIB_C_EXPORT void taglib_tag_set_genre(TagLib_Tag *tag, const char *genre); - -/*! - * Sets the tag's year. 0 indicates that this field should be cleared. - */ -TAGLIB_C_EXPORT void taglib_tag_set_year(TagLib_Tag *tag, unsigned int year); - -/*! - * Sets the tag's track number. 0 indicates that this field should be cleared. - */ -TAGLIB_C_EXPORT void taglib_tag_set_track(TagLib_Tag *tag, unsigned int track); - -/*! - * Frees all of the strings that have been created by the tag. - */ -TAGLIB_C_EXPORT void taglib_tag_free_strings(void); - -/****************************************************************************** - * Audio Properties API - ******************************************************************************/ - -/*! - * Returns the length of the file in seconds. - */ -TAGLIB_C_EXPORT int taglib_audioproperties_length(const TagLib_AudioProperties *audioProperties); - -/*! - * Returns the bitrate of the file in kb/s. - */ -TAGLIB_C_EXPORT int taglib_audioproperties_bitrate(const TagLib_AudioProperties *audioProperties); - -/*! - * Returns the sample rate of the file in Hz. - */ -TAGLIB_C_EXPORT int taglib_audioproperties_samplerate(const TagLib_AudioProperties *audioProperties); - -/*! - * Returns the number of channels in the audio stream. - */ -TAGLIB_C_EXPORT int taglib_audioproperties_channels(const TagLib_AudioProperties *audioProperties); - -/******************************************************************************* - * Special convenience ID3v2 functions - *******************************************************************************/ - -typedef enum { - TagLib_ID3v2_Latin1, - TagLib_ID3v2_UTF16, - TagLib_ID3v2_UTF16BE, - TagLib_ID3v2_UTF8 -} TagLib_ID3v2_Encoding; - -/*! - * This sets the default encoding for ID3v2 frames that are written to tags. - */ - -TAGLIB_C_EXPORT void taglib_id3v2_set_default_text_encoding(TagLib_ID3v2_Encoding encoding); - -#ifdef __cplusplus -} -#endif -#endif /* DO_NOT_DOCUMENT */ -#endif diff --git a/taglib/bindings/c/taglib_c.pc.cmake b/taglib/bindings/c/taglib_c.pc.cmake deleted file mode 100644 index 61764fc..0000000 --- a/taglib/bindings/c/taglib_c.pc.cmake +++ /dev/null @@ -1,12 +0,0 @@ -prefix=${CMAKE_INSTALL_PREFIX} -exec_prefix=${CMAKE_INSTALL_PREFIX} -libdir=${LIB_INSTALL_DIR} -includedir=${INCLUDE_INSTALL_DIR} - - -Name: TagLib C Bindings -Description: Audio meta-data library (C bindings) -Requires: taglib -Version: ${TAGLIB_LIB_MAJOR_VERSION}.${TAGLIB_LIB_MINOR_VERSION}.${TAGLIB_LIB_PATCH_VERSION} -Libs: -L${LIB_INSTALL_DIR} -ltag_c -Cflags: -I${INCLUDE_INSTALL_DIR}/taglib diff --git a/taglib/cmake/modules/FindCppUnit.cmake b/taglib/cmake/modules/FindCppUnit.cmake deleted file mode 100644 index adaaeb6..0000000 --- a/taglib/cmake/modules/FindCppUnit.cmake +++ /dev/null @@ -1,69 +0,0 @@ -# - Try to find the libcppunit libraries -# Once done this will define -# -# CppUnit_FOUND - system has libcppunit -# CPPUNIT_INCLUDE_DIR - the libcppunit include directory -# CPPUNIT_LIBRARIES - libcppunit library - -include (MacroEnsureVersion) - -if(NOT CPPUNIT_MIN_VERSION) - SET(CPPUNIT_MIN_VERSION 1.12.0) -endif(NOT CPPUNIT_MIN_VERSION) - -FIND_PROGRAM(CPPUNIT_CONFIG_EXECUTABLE cppunit-config ) - -IF(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES) - - # in cache already - SET(CppUnit_FOUND TRUE) - -ELSE(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES) - - SET(CPPUNIT_INCLUDE_DIR) - SET(CPPUNIT_LIBRARIES) - - IF(CPPUNIT_CONFIG_EXECUTABLE) - EXEC_PROGRAM(${CPPUNIT_CONFIG_EXECUTABLE} ARGS --cflags RETURN_VALUE _return_VALUE OUTPUT_VARIABLE CPPUNIT_CFLAGS) - EXEC_PROGRAM(${CPPUNIT_CONFIG_EXECUTABLE} ARGS --libs RETURN_VALUE _return_VALUE OUTPUT_VARIABLE CPPUNIT_LIBRARIES) - EXEC_PROGRAM(${CPPUNIT_CONFIG_EXECUTABLE} ARGS --version RETURN_VALUE _return_VALUE OUTPUT_VARIABLE CPPUNIT_INSTALLED_VERSION) - STRING(REGEX REPLACE "-I(.+)" "\\1" CPPUNIT_CFLAGS "${CPPUNIT_CFLAGS}") - ELSE(CPPUNIT_CONFIG_EXECUTABLE) - # in case win32 needs to find it the old way? - FIND_PATH(CPPUNIT_CFLAGS cppunit/TestRunner.h PATHS /usr/include /usr/local/include ) - FIND_LIBRARY(CPPUNIT_LIBRARIES NAMES cppunit PATHS /usr/lib /usr/local/lib ) - # how can we find cppunit version? - MESSAGE (STATUS "Ensure you cppunit installed version is at least ${CPPUNIT_MIN_VERSION}") - SET (CPPUNIT_INSTALLED_VERSION ${CPPUNIT_MIN_VERSION}) - ENDIF(CPPUNIT_CONFIG_EXECUTABLE) - - SET(CPPUNIT_INCLUDE_DIR ${CPPUNIT_CFLAGS} "${CPPUNIT_CFLAGS}/cppunit") - -ENDIF(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES) - -IF(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES) - - SET(CppUnit_FOUND TRUE) - - if(NOT CppUnit_FIND_QUIETLY) - MESSAGE (STATUS "Found cppunit: ${CPPUNIT_LIBRARIES}") - endif(NOT CppUnit_FIND_QUIETLY) - - IF(CPPUNIT_CONFIG_EXECUTABLE) - EXEC_PROGRAM(${CPPUNIT_CONFIG_EXECUTABLE} ARGS --version RETURN_VALUE _return_VALUE OUTPUT_VARIABLE CPPUNIT_INSTALLED_VERSION) - ENDIF(CPPUNIT_CONFIG_EXECUTABLE) - - macro_ensure_version( ${CPPUNIT_MIN_VERSION} ${CPPUNIT_INSTALLED_VERSION} CPPUNIT_INSTALLED_VERSION_OK ) - - IF(NOT CPPUNIT_INSTALLED_VERSION_OK) - MESSAGE ("** CppUnit version is too old: found ${CPPUNIT_INSTALLED_VERSION} installed, ${CPPUNIT_MIN_VERSION} or major is required") - SET(CppUnit_FOUND FALSE) - ENDIF(NOT CPPUNIT_INSTALLED_VERSION_OK) - -ELSE(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES) - - SET(CppUnit_FOUND FALSE CACHE BOOL "Not found cppunit library") - -ENDIF(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES) - -MARK_AS_ADVANCED(CPPUNIT_INCLUDE_DIR CPPUNIT_LIBRARIES) diff --git a/taglib/cmake/modules/MacroEnsureVersion.cmake b/taglib/cmake/modules/MacroEnsureVersion.cmake deleted file mode 100644 index c6df537..0000000 --- a/taglib/cmake/modules/MacroEnsureVersion.cmake +++ /dev/null @@ -1,71 +0,0 @@ -# This macro compares version numbers of the form "x.y.z" -# MACRO_ENSURE_VERSION( FOO_MIN_VERSION FOO_VERSION_FOUND FOO_VERSION_OK) -# will set FOO_VERSIN_OK to true if FOO_VERSION_FOUND >= FOO_MIN_VERSION -# where both have to be in a 3-part-version format, leading and trailing -# text is ok, e.g. -# MACRO_ENSURE_VERSION( "2.5.31" "flex 2.5.4a" VERSION_OK) -# which means 2.5.31 is required and "flex 2.5.4a" is what was found on the system - -# Copyright (c) 2006, David Faure, -# -# Redistribution and use is allowed according to the terms of the BSD license. -# For details see the accompanying COPYING-CMAKE-SCRIPTS file. - -MACRO(MACRO_ENSURE_VERSION requested_version found_version var_too_old) - - # parse the parts of the version string - STRING(REGEX REPLACE "([0-9]+)\\.[0-9]+\\.[0-9]+" "\\1" req_major_vers "${requested_version}") - STRING(REGEX REPLACE "[0-9]+\\.([0-9]+)\\.[0-9]+" "\\1" req_minor_vers "${requested_version}") - STRING(REGEX REPLACE "[0-9]+\\.[0-9]+\\.([0-9]+)" "\\1" req_patch_vers "${requested_version}") - - STRING(REGEX REPLACE "[^0-9]*([0-9]+)\\.[0-9]+\\.[0-9]+.*" "\\1" found_major_vers "${found_version}") - STRING(REGEX REPLACE "[^0-9]*[0-9]+\\.([0-9]+)\\.[0-9]+.*" "\\1" found_minor_vers "${found_version}") - STRING(REGEX REPLACE "[^0-9]*[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" found_patch_vers "${found_version}") - - # compute an overall version number which can be compared at once - MATH(EXPR req_vers_num "${req_major_vers}*10000 + ${req_minor_vers}*100 + ${req_patch_vers}") - MATH(EXPR found_vers_num "${found_major_vers}*10000 + ${found_minor_vers}*100 + ${found_patch_vers}") - - if (found_vers_num LESS req_vers_num) - set( ${var_too_old} FALSE ) - else (found_vers_num LESS req_vers_num) - set( ${var_too_old} TRUE ) - endif (found_vers_num LESS req_vers_num) - -ENDMACRO(MACRO_ENSURE_VERSION) - - -# This macro compares version numbers of the form "x.y" -# MACRO_ENSURE_VERSION( FOO_MIN_VERSION FOO_VERSION_FOUND FOO_VERSION_OK) -# will set FOO_VERSIN_OK to true if FOO_VERSION_FOUND >= FOO_MIN_VERSION -# where both have to be in a 2-part-version format, leading and trailing -# text is ok, e.g. -# MACRO_ENSURE_VERSION( "0.5" "foo 0.6" VERSION_OK) -# which means 0.5 is required and "foo 0.6" is what was found on the system - -# Copyright (c) 2006, David Faure, -# Copyright (c) 2007, Pino Toscano, -# -# Redistribution and use is allowed according to the terms of the BSD license. -# For details see the accompanying COPYING-CMAKE-SCRIPTS file. - -MACRO(MACRO_ENSURE_VERSION2 requested_version found_version var_too_old) - - # parse the parts of the version string - STRING(REGEX REPLACE "([0-9]+)\\.[0-9]+" "\\1" req_major_vers "${requested_version}") - STRING(REGEX REPLACE "[0-9]+\\.([0-9]+)" "\\1" req_minor_vers "${requested_version}") - - STRING(REGEX REPLACE "[^0-9]*([0-9]+)\\.[0-9]+.*" "\\1" found_major_vers "${found_version}") - STRING(REGEX REPLACE "[^0-9]*[0-9]+\\.([0-9]+).*" "\\1" found_minor_vers "${found_version}") - - # compute an overall version number which can be compared at once - MATH(EXPR req_vers_num "${req_major_vers}*100 + ${req_minor_vers}") - MATH(EXPR found_vers_num "${found_major_vers}*100 + ${found_minor_vers}") - - if (found_vers_num LESS req_vers_num) - set( ${var_too_old} FALSE ) - else (found_vers_num LESS req_vers_num) - set( ${var_too_old} TRUE ) - endif (found_vers_num LESS req_vers_num) - -ENDMACRO(MACRO_ENSURE_VERSION2) diff --git a/taglib/cmake_uninstall.cmake.in b/taglib/cmake_uninstall.cmake.in deleted file mode 100644 index 72e030f..0000000 --- a/taglib/cmake_uninstall.cmake.in +++ /dev/null @@ -1,21 +0,0 @@ -if (NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") - message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") -endif() - -file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) -string(REGEX REPLACE "\n" ";" files "${files}") -foreach (file ${files}) - message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") - if (EXISTS "$ENV{DESTDIR}${file}") - execute_process( - COMMAND @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}" - OUTPUT_VARIABLE rm_out - RESULT_VARIABLE rm_retval - ) - if(NOT ${rm_retval} EQUAL 0) - message(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") - endif () - else () - message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") - endif () -endforeach() diff --git a/taglib/config.h.cmake b/taglib/config.h.cmake deleted file mode 100644 index f8dcbbd..0000000 --- a/taglib/config.h.cmake +++ /dev/null @@ -1,37 +0,0 @@ -/* 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@" diff --git a/taglib/doc/README b/taglib/doc/README deleted file mode 100644 index b2ebd36..0000000 --- a/taglib/doc/README +++ /dev/null @@ -1 +0,0 @@ -Run "make docs" in the parent directory to generate the TagLib API documentation. diff --git a/taglib/doc/api-footer.html b/taglib/doc/api-footer.html deleted file mode 100644 index 9b151ee..0000000 --- a/taglib/doc/api-footer.html +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/taglib/doc/api-header.html b/taglib/doc/api-header.html deleted file mode 100644 index ab133c2..0000000 --- a/taglib/doc/api-header.html +++ /dev/null @@ -1,41 +0,0 @@ - - - - $title ($projectname) - - - - - -
- - - - - - -
- - -
- - - - - -

TagLib $projectnumber ($title)

- -
-
-
- -
diff --git a/taglib/doc/taglib-api.css b/taglib/doc/taglib-api.css deleted file mode 100644 index 3fa820e..0000000 --- a/taglib/doc/taglib-api.css +++ /dev/null @@ -1,395 +0,0 @@ -body { - font-family: sans-serif; - background: white; - color: black; - margin: 0px; - padding: 15px; -} - -a:link { - font-weight: bold; - text-decoration: none; - color: gray; -} - -a:visited { - font-weight: bold; - text-decoration: none; - color: gray; -} - -a:hover { - color: #cccccc; - text-decoration: underline; -} - -a:active { - color: #cccccc; - text-decoration: underline; -} - -img { - border-style: none; -} - -h1 { - font-family: sans-serif; -} - -h2 { - font-family: sans-serif; -} - -h3 { - font-family: sans-serif; -} - -/* container */ - -#container { - position: absolute; - border-width: thin; - border-style: solid; - width: 95%; -} - -/* intro */ - -#intro { - padding: 5px; - margin: 0px; - background: #cccccc; - border-width: medium; - border-style: solid; -} - -#intro h1 { - margin: 5px; - padding: 5px; -} - -/* links */ - -#links { - font-size: x-small; - vertical-align: bottom; -} - -#links a { - border-width: thin; - border-style: dotted; - border-color: white; - /* margin: 0px 10px 0px 0px; */ - margin: 1px; - padding: 3px; - line-height: 230% -} - -#links a:hover { - color: black; - text-decoration: underline; -} - -#links h3 { - outline-width: thin; - border-style: solid; - padding: 2px; - margin: 3px 0px 3px 0px; -} - -/* menu */ - -#menu h3 { - text-align: center; -} - -/* text */ - -#text { - margin: 0px; - padding: 5px 5px 0px 5px; - float: left; -} - -#text h3 { - border-width: thin; - border-style: solid; - padding: 2px; - margin: 3px 0px 3px 0px; -} - -#text li { - margin: 0px 0px 10px 0px; -} - -#text ul { - margin: 5px; - padding: 0px 0px 0px 20px; -} - -#leftcolumn { - float: left; - width: 300px; - margin: 0px 10px 0px 0px; - padding: 0px; -} - -#rightcolumn { - float: right; - width: 210px; - margin: 0px; - padding: 0px; -} - -/* vspacer */ - -.vspacer { - height: 10px; -} - -.silver { - border-width: thin; - border-color: black; - border-style: solid; - background: #cccccc; -} - -a.code { - text-decoration: none; - font-weight: normal; - color: #4444ee -} - -a.codeRef { - font-weight: normal; - color: #4444ee -} - -div.fragment { - width: 98%; - border: 1px solid #CCCCCC; - background-color: #f5f5f5; - padding-left: 4px; - margin: 4px; -} - -div.ah { - background-color: black; - font-weight: bold; color: #ffffff; - margin-bottom: 3px; - margin-top: 3px -} - -#text td { - width: auto; -} - -div.memdoc { - margin-top: 0px; - margin-bottom: 20px; - padding: 10px 10px 10px 40px; -} - -div.memproto { - border: thin solid black; - background-color: #f2f2ff; - width: 100%; - margin-top: 20px; - padding-top: 10px; - padding-bottom: 10px; -} - -td.paramtype { - color: #602020; -} - -table.memname { - font-weight: bold; -} - -div.groupHeader { - margin-left: 16px; - margin-top: 12px; - margin-bottom: 6px; - font-weight: bold -} - -div.groupText { - margin-left: 16px; - font-style: italic; - font-size: smaller -} - -body { - background: white; - color: black; - margin-right: 20px; - margin-left: 20px; -} - -td.indexkey { - background-color: #eeeeff; - font-weight: bold; - padding-right : 10px; - padding-top : 2px; - padding-left : 10px; - padding-bottom : 2px; - margin-left : 0px; - margin-right : 0px; - margin-top : 2px; - margin-bottom : 2px -} - -td.indexvalue { - background-color: #eeeeff; - font-style: italic; - padding-right : 10px; - padding-top : 2px; - padding-left : 10px; - padding-bottom : 2px; - margin-left : 0px; - margin-right : 0px; - margin-top : 2px; - margin-bottom : 2px -} - -tr.memlist { - background-color: #f0f0f0; -} - -p.formulaDsp { - text-align: center; -} - -img.formulaDsp { - -} - -img.formulaInl { - vertical-align: middle; -} - -span.keyword { - color: #008000 -} - -span.keywordtype { - color: #604020 -} - -span.keywordflow { - color: #e08000 -} - -span.comment { - color: #800000 -} - -span.preprocessor { - color: #806020 -} - -span.stringliteral { - color: #002080 -} - -span.charliteral { - color: #008080 -} - -.mdTable { - border: 1px solid #868686; - background-color: #f2f2ff; -} - -.mdRow { - padding: 8px 20px; -} - -.mdescLeft { - font-size: smaller; - font-family: Arial, Helvetica, sans-serif; - background-color: #FAFAFA; - padding-left: 8px; - border-top: 1px none #E0E0E0; - border-right: 1px none #E0E0E0; - border-bottom: 1px none #E0E0E0; - border-left: 1px none #E0E0E0; - margin: 0px; -} - -.mdescRight { - font-size: smaller; - font-family: Arial, Helvetica, sans-serif; - font-style: italic; - background-color: #FAFAFA; - padding-left: 4px; - border-top: 1px none #E0E0E0; - border-right: 1px none #E0E0E0; - border-bottom: 1px none #E0E0E0; - border-left: 1px none #E0E0E0; - margin: 0px; - padding-bottom: 0px; - padding-right: 8px; -} - -.memItemLeft { - padding: 1px 0px 0px 8px; - margin: 4px; - border-top-width: 1px; - border-right-width: 1px; - border-bottom-width: 1px; - border-left-width: 1px; - border-top-style: solid; - border-top-color: #E0E0E0; - border-right-color: #E0E0E0; - border-bottom-color: #E0E0E0; - border-left-color: #E0E0E0; - border-right-style: none; - border-bottom-style: none; - border-left-style: none; - background-color: #FAFAFA; - font-family: Geneva, Arial, Helvetica, sans-serif; - font-size: 12px; -} - -.memItemRight { - padding: 1px 0px 0px 8px; - margin: 4px; - border-top-width: 1px; - border-right-width: 1px; - border-bottom-width: 1px; - border-left-width: 1px; - border-top-style: solid; - border-top-color: #E0E0E0; - border-right-color: #E0E0E0; - border-bottom-color: #E0E0E0; - border-left-color: #E0E0E0; - border-right-style: none; - border-bottom-style: none; - border-left-style: none; - background-color: #FAFAFA; - font-family: Geneva, Arial, Helvetica, sans-serif; - font-size: 13px; -} - -.search { - color: #0000ee; - font-weight: bold; -} - -form.search { - margin-bottom: 0px; - margin-top: 0px; -} - -input.search { - font-size: 75%; - color: #000080; - font-weight: normal; - background-color: #eeeeff; -} - -td.tiny { - font-size: 75%; -} diff --git a/taglib/doc/taglib.png b/taglib/doc/taglib.png deleted file mode 100644 index 2791cc887670ef22450bb7f35686912c8ebf1af3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2748 zcmeHJ`!^Ge8(;2WY-L&`>?<+KB}AdomW>SC3yDgZEawX$K{m4<5!+inxP@llC zU1rZ5-~s?5U5@7osNJD|;vWb8e;w%B$_m}xeu<33;sJX^M8(7#3n_E~Stj{7*=WNgz zTf6i2SO-TZ9G>8O!PU*(<0A1A>9Uu%kFTG9Kwwbtm8&74Vd0TcH=-#wV`6{16&FuU zNK8sjrKhFe&iMTfBQq;ICpYhI{=LGY;*!$)56W2O6_r&FA63^puC1$o^0c9`srgw; zYg_wsc1LGd_a8mIFZ%iiUJkx~!{H7Mza4r1;UjNs{NEFwCa0!nX6NQVFDx!Ce_2^w z`}SQR{IULXb8GuoK}4+#03eZ#L0S=R@K%a8TnN62-U#cQ zxshDVk#FbxU`Lz@(~J1&+eu_Ot!Zb!u*!iy;VrIT89^4V-MpyV4f}5Z6)S#xz44_nH)ZwLEX1m@h{jx#s^%-I12Uo{L;lYU>S6TgGhdGB z-86#$!MWVF=DePxCFXUv3MhxFgQId@QM>wAZS7>TD&n;AB}hM;sMl-S_gyQtOMwwaMxEZ(SGTen$NAH(Dr;;wTMLm2rm%dEFDtTox@-@yo_8=#PTFHV7~^?_z$R zxYn}=x)!a^d?VBXN`@a&+4V)@HnEI?SU4HG803Max{73rO=A^u6V+|LA$#@%CB=*IUN&JV>%TnPaWua;K8=X) zpSvd-Td5$wDKjt8&kuf+pJ>TL+qB&R?R2y>PS1{tx#f1xCAyl)A(-a{^sG4}pTUpl ztg3d6gXi+mVt)PemeH1eoYGiIzLX?oAlxv0CO2Tt2$3mtQ6CBPvdnoJ@5=iiQW;6p zc>9sOuYQ&Ylk4RZvdLE0c#sqmBw7x|aAJkrfxun-y0rEm@2t7Il^velx+l*`Qw)L2 z)`j*t2l*aEy9oZ)V-~)2jw||+ifBAL3^{cV3xm5QqFn!1=#fWOGe<@0y>#7aOb9Jd z!s*C3e4j~aj#e^~#w3Az7ur%2)4Wbpj*fhVUN6Wxbu4;*IfD{0% zQoa$@Udr-hi3Y79kklmJ=+Y4wsH+lFP@NgTzB48X%f#J#Nl6_S`s?6_dSO6N;J+5P zu^UPj*dEX5-;B6#=a%-SM}qHPr}dZ-ykfMyaF`YuAyW>Vm7?dh$lnh8;Nq`WWR{&b zBBsfxt^F7=KRqz~+RzDK#!s)vj zsatPb7)ztssHyH0VO`s+bIM6K6o8->F0jXseoN3oW9__3hbWIj{JeF=U4}s5lSVi# zw#t+TqrY&FE*YfDoD}>?lf~0)V&KF4hJpzmTg#Ul{||Qvj_p^UPjnwVWj4Ru^F)Xv zLGjvWoABrk%7>zpsxf$<+mDnCq9BWrcdZYyA%PApFWC2Z%3WSOK?QL$I3(B|F3WH? z4WfZQyeVn5U4GqoK{c)PD!)VUOcm3K|6JJ^PhZK+@oaI_KdM+%MOa|b23AVKQInP^ zYGNnIs!l>mJ>D7==NK<_P6bJ}Z}6~cAe#><8Q*GOw&NI@heJfQF$9%LP_DFP-r zcOWM=?B30%IXuiaEYmisp4m}nFn(~G&yB}u3|IbQ*v^zb9NK<*e+SU)oHl8-*H!25p8|uzA|G3m GsDA+=UdN#T diff --git a/taglib/examples/CMakeLists.txt b/taglib/examples/CMakeLists.txt deleted file mode 100644 index 17d4bd6..0000000 --- a/taglib/examples/CMakeLists.txt +++ /dev/null @@ -1,50 +0,0 @@ -if(BUILD_EXAMPLES) -INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR}/../taglib - ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/toolkit - ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/ape - ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mpeg - ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mpeg/id3v1 - ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mpeg/id3v2 - ${CMAKE_CURRENT_SOURCE_DIR}/../bindings/c/ ) - -if(ENABLE_STATIC) - add_definitions(-DTAGLIB_STATIC) -endif(ENABLE_STATIC) - -########### next target ############### - -ADD_EXECUTABLE(tagreader tagreader.cpp) - -TARGET_LINK_LIBRARIES(tagreader tag ) - - -########### next target ############### - -ADD_EXECUTABLE(tagreader_c tagreader_c.c) - -TARGET_LINK_LIBRARIES(tagreader_c tag_c ) - - -########### next target ############### - -ADD_EXECUTABLE(tagwriter tagwriter.cpp) - -TARGET_LINK_LIBRARIES(tagwriter tag ) - - -########### next target ############### - -ADD_EXECUTABLE(framelist framelist.cpp) - -TARGET_LINK_LIBRARIES(framelist tag ) - - -########### next target ############### - -ADD_EXECUTABLE(strip-id3v1 strip-id3v1.cpp) - -TARGET_LINK_LIBRARIES(strip-id3v1 tag ) - - -endif(BUILD_EXAMPLES) - diff --git a/taglib/examples/framelist.cpp b/taglib/examples/framelist.cpp deleted file mode 100644 index 679aa39..0000000 --- a/taglib/examples/framelist.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* Copyright (C) 2003 Scott Wheeler - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include - -#include - -#include - -#include -#include -#include - -#include - -#include - -using namespace std; -using namespace TagLib; - -int main(int argc, char *argv[]) -{ - // process the command line args - - - for(int i = 1; i < argc; i++) { - - cout << "******************** \"" << argv[i] << "\"********************" << endl; - - MPEG::File f(argv[i]); - - ID3v2::Tag *id3v2tag = f.ID3v2Tag(); - - if(id3v2tag) { - - cout << "ID3v2." - << id3v2tag->header()->majorVersion() - << "." - << id3v2tag->header()->revisionNumber() - << ", " - << id3v2tag->header()->tagSize() - << " bytes in tag" - << endl; - - ID3v2::FrameList::ConstIterator it = id3v2tag->frameList().begin(); - for(; it != id3v2tag->frameList().end(); it++) - cout << (*it)->frameID() << " - \"" << (*it)->toString() << "\"" << endl; - } - else - cout << "file does not have a valid id3v2 tag" << endl; - - cout << endl << "ID3v1" << endl; - - ID3v1::Tag *id3v1tag = f.ID3v1Tag(); - - if(id3v1tag) { - cout << "title - \"" << id3v1tag->title() << "\"" << endl; - cout << "artist - \"" << id3v1tag->artist() << "\"" << endl; - cout << "album - \"" << id3v1tag->album() << "\"" << endl; - cout << "year - \"" << id3v1tag->year() << "\"" << endl; - cout << "comment - \"" << id3v1tag->comment() << "\"" << endl; - cout << "track - \"" << id3v1tag->track() << "\"" << endl; - cout << "genre - \"" << id3v1tag->genre() << "\"" << endl; - } - else - cout << "file does not have a valid id3v1 tag" << endl; - - APE::Tag *ape = f.APETag(); - - cout << endl << "APE" << endl; - - if(ape) { - for(APE::ItemListMap::ConstIterator it = ape->itemListMap().begin(); - it != ape->itemListMap().end(); ++it) - { - if((*it).second.type() != APE::Item::Binary) - cout << (*it).first << " - \"" << (*it).second.toString() << "\"" << endl; - else - cout << (*it).first << " - Binary data (" << (*it).second.binaryData().size() << " bytes)" << endl; - } - } - else - cout << "file does not have a valid APE tag" << endl; - - cout << endl; - } -} diff --git a/taglib/examples/strip-id3v1.cpp b/taglib/examples/strip-id3v1.cpp deleted file mode 100644 index ab36d71..0000000 --- a/taglib/examples/strip-id3v1.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* Copyright (C) 2003 Scott Wheeler - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include - -using namespace TagLib; - -int main(int argc, char *argv[]) -{ - for(int i = 1; i < argc; i++) { - - std::cout << "******************** Stripping ID3v1 Tag From: \"" << argv[i] << "\"********************" << std::endl; - - MPEG::File f(argv[i]); - f.strip(MPEG::File::ID3v1); - } -} diff --git a/taglib/examples/tagreader.cpp b/taglib/examples/tagreader.cpp deleted file mode 100644 index cc978eb..0000000 --- a/taglib/examples/tagreader.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* Copyright (C) 2003 Scott Wheeler - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include - -#include -#include -#include - -using namespace std; - -TagLib::String formatSeconds(int seconds) -{ - char secondsString[3]; - sprintf(secondsString, "%02i", seconds); - return secondsString; -} - -int main(int argc, char *argv[]) -{ - for(int i = 1; i < argc; i++) { - - cout << "******************** \"" << argv[i] << "\" ********************" << endl; - - TagLib::FileRef f(argv[i]); - - if(!f.isNull() && f.tag()) { - - TagLib::Tag *tag = f.tag(); - - cout << "-- TAG (basic) --" << endl; - cout << "title - \"" << tag->title() << "\"" << endl; - cout << "artist - \"" << tag->artist() << "\"" << endl; - cout << "album - \"" << tag->album() << "\"" << endl; - cout << "year - \"" << tag->year() << "\"" << endl; - cout << "comment - \"" << tag->comment() << "\"" << endl; - cout << "track - \"" << tag->track() << "\"" << endl; - cout << "genre - \"" << tag->genre() << "\"" << endl; - - 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()) { - - TagLib::AudioProperties *properties = f.audioProperties(); - - int seconds = properties->length() % 60; - int minutes = (properties->length() - seconds) / 60; - - cout << "-- AUDIO --" << endl; - cout << "bitrate - " << properties->bitrate() << endl; - cout << "sample rate - " << properties->sampleRate() << endl; - cout << "channels - " << properties->channels() << endl; - cout << "length - " << minutes << ":" << formatSeconds(seconds) << endl; - } - } - return 0; -} diff --git a/taglib/examples/tagreader_c.c b/taglib/examples/tagreader_c.c deleted file mode 100644 index 0436992..0000000 --- a/taglib/examples/tagreader_c.c +++ /dev/null @@ -1,81 +0,0 @@ -/* Copyright (C) 2003 Scott Wheeler - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include - -#ifndef FALSE -#define FALSE 0 -#endif - -int main(int argc, char *argv[]) -{ - int i; - int seconds; - int minutes; - TagLib_File *file; - TagLib_Tag *tag; - const TagLib_AudioProperties *properties; - - taglib_set_strings_unicode(FALSE); - - for(i = 1; i < argc; i++) { - printf("******************** \"%s\" ********************\n", argv[i]); - - file = taglib_file_new(argv[i]); - - if(file == NULL) - break; - - tag = taglib_file_tag(file); - properties = taglib_file_audioproperties(file); - - if(tag != NULL) { - printf("-- TAG --\n"); - printf("title - \"%s\"\n", taglib_tag_title(tag)); - printf("artist - \"%s\"\n", taglib_tag_artist(tag)); - printf("album - \"%s\"\n", taglib_tag_album(tag)); - printf("year - \"%i\"\n", taglib_tag_year(tag)); - printf("comment - \"%s\"\n", taglib_tag_comment(tag)); - printf("track - \"%i\"\n", taglib_tag_track(tag)); - printf("genre - \"%s\"\n", taglib_tag_genre(tag)); - } - - if(properties != NULL) { - seconds = taglib_audioproperties_length(properties) % 60; - minutes = (taglib_audioproperties_length(properties) - seconds) / 60; - - printf("-- AUDIO --\n"); - printf("bitrate - %i\n", taglib_audioproperties_bitrate(properties)); - printf("sample rate - %i\n", taglib_audioproperties_samplerate(properties)); - printf("channels - %i\n", taglib_audioproperties_channels(properties)); - printf("length - %i:%02i\n", minutes, seconds); - } - - taglib_tag_free_strings(); - taglib_file_free(file); - } - - return 0; -} diff --git a/taglib/examples/tagwriter.cpp b/taglib/examples/tagwriter.cpp deleted file mode 100644 index 63163fb..0000000 --- a/taglib/examples/tagwriter.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/* Copyright (C) 2004 Scott Wheeler - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -using namespace std; - -bool isArgument(const char *s) -{ - return strlen(s) == 2 && s[0] == '-'; -} - -bool isFile(const char *s) -{ - struct stat st; -#ifdef _WIN32 - return ::stat(s, &st) == 0 && (st.st_mode & (S_IFREG)); -#else - return ::stat(s, &st) == 0 && (st.st_mode & (S_IFREG | S_IFLNK)); -#endif -} - -void usage() -{ - cout << endl; - cout << "Usage: tagwriter " << endl; - cout << endl; - cout << "Where the valid fields are:" << endl; - cout << " -t " << endl; - cout << " -a <artist>" << endl; - cout << " -A <album>" << endl; - cout << " -c <comment>" << endl; - cout << " -g <genre>" << endl; - cout << " -y <year>" << endl; - cout << " -T <track>" << endl; - cout << endl; - - exit(1); -} - -int main(int argc, char *argv[]) -{ - TagLib::List<TagLib::FileRef> fileList; - - while(argc > 0 && isFile(argv[argc - 1])) { - - TagLib::FileRef f(argv[argc - 1]); - - if(!f.isNull() && f.tag()) - fileList.append(f); - - argc--; - } - - if(fileList.isEmpty()) - usage(); - - for(int i = 1; i < argc - 1; i += 2) { - - if(isArgument(argv[i]) && i + 1 < argc && !isArgument(argv[i + 1])) { - - char field = argv[i][1]; - TagLib::String value = argv[i + 1]; - - TagLib::List<TagLib::FileRef>::Iterator it; - for(it = fileList.begin(); it != fileList.end(); ++it) { - - TagLib::Tag *t = (*it).tag(); - - switch (field) { - case 't': - t->setTitle(value); - break; - case 'a': - t->setArtist(value); - break; - case 'A': - t->setAlbum(value); - break; - case 'c': - t->setComment(value); - break; - case 'g': - t->setGenre(value); - break; - case 'y': - t->setYear(value.toInt()); - break; - case 'T': - t->setTrack(value.toInt()); - break; - default: - usage(); - break; - } - } - } - else - usage(); - } - - TagLib::List<TagLib::FileRef>::Iterator it; - for(it = fileList.begin(); it != fileList.end(); ++it) - (*it).file()->save(); - - return 0; -} diff --git a/taglib/taglib-config.cmake b/taglib/taglib-config.cmake deleted file mode 100644 index 2c2d2db..0000000 --- a/taglib/taglib-config.cmake +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/sh - -usage() -{ - echo "usage: $0 [OPTIONS]" -cat << EOH - -options: - [--libs] - [--cflags] - [--version] - [--prefix] -EOH - exit 1; -} - -prefix=${CMAKE_INSTALL_PREFIX} -exec_prefix=${CMAKE_INSTALL_PREFIX} -libdir=${LIB_INSTALL_DIR} -includedir=${INCLUDE_INSTALL_DIR} - -flags="" - -if test $# -eq 0 ; then - usage -fi - -while test $# -gt 0 -do - case $1 in - --libs) - flags="$flags -L$libdir -ltag" - ;; - --cflags) - flags="$flags -I$includedir/taglib" - ;; - --version) - echo ${TAGLIB_LIB_MAJOR_VERSION}.${TAGLIB_LIB_MINOR_VERSION}.${TAGLIB_LIB_PATCH_VERSION} - ;; - --prefix) - echo $prefix - ;; - *) - echo "$0: unknown option $1" - echo - usage - ;; - esac - shift -done - -if test -n "$flags" -then - echo $flags -fi diff --git a/taglib/taglib-config.cmd.cmake b/taglib/taglib-config.cmd.cmake deleted file mode 100644 index 3e2b1cd..0000000 --- a/taglib/taglib-config.cmd.cmake +++ /dev/null @@ -1,36 +0,0 @@ -@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 - diff --git a/taglib/taglib.pc.cmake b/taglib/taglib.pc.cmake deleted file mode 100644 index 909b8fc..0000000 --- a/taglib/taglib.pc.cmake +++ /dev/null @@ -1,11 +0,0 @@ -prefix=${CMAKE_INSTALL_PREFIX} -exec_prefix=${CMAKE_INSTALL_PREFIX} -libdir=${LIB_INSTALL_DIR} -includedir=${INCLUDE_INSTALL_DIR} - -Name: TagLib -Description: Audio meta-data library -Requires: -Version: ${TAGLIB_LIB_MAJOR_VERSION}.${TAGLIB_LIB_MINOR_VERSION}.${TAGLIB_LIB_PATCH_VERSION} -Libs: -L${LIB_INSTALL_DIR} -ltag -Cflags: -I${INCLUDE_INSTALL_DIR}/taglib diff --git a/taglib/taglib/CMakeLists.txt b/taglib/taglib/CMakeLists.txt deleted file mode 100644 index 23fa60d..0000000 --- a/taglib/taglib/CMakeLists.txt +++ /dev/null @@ -1,335 +0,0 @@ -set(CMAKE_INCLUDE_CURRENT_DIR ON) -include_directories( - ${CMAKE_CURRENT_SOURCE_DIR}/toolkit - ${CMAKE_CURRENT_SOURCE_DIR}/asf - ${CMAKE_CURRENT_SOURCE_DIR}/mpeg - ${CMAKE_CURRENT_SOURCE_DIR}/ogg - ${CMAKE_CURRENT_SOURCE_DIR}/ogg/flac - ${CMAKE_CURRENT_SOURCE_DIR}/flac - ${CMAKE_CURRENT_SOURCE_DIR}/mpc - ${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 - ${CMAKE_CURRENT_SOURCE_DIR}/ape - ${CMAKE_CURRENT_SOURCE_DIR}/wavpack - ${CMAKE_CURRENT_SOURCE_DIR}/trueaudio - ${CMAKE_CURRENT_SOURCE_DIR}/riff - ${CMAKE_CURRENT_SOURCE_DIR}/riff/aiff - ${CMAKE_CURRENT_SOURCE_DIR}/riff/wav - ${CMAKE_CURRENT_SOURCE_DIR}/mod - ${CMAKE_CURRENT_SOURCE_DIR}/s3m - ${CMAKE_CURRENT_SOURCE_DIR}/it - ${CMAKE_CURRENT_SOURCE_DIR}/xm -) - -if(ZLIB_FOUND) - include_directories(${ZLIB_INCLUDE_DIR}) -endif() - -set(tag_HDRS - tag.h - fileref.h - audioproperties.h - taglib_export.h - ${CMAKE_BINARY_DIR}/taglib_config.h - toolkit/taglib.h - toolkit/tstring.h - toolkit/tlist.h - toolkit/tlist.tcc - toolkit/tstringlist.h - toolkit/tbytevector.h - toolkit/tbytevectorlist.h - toolkit/tbytevectorstream.h - toolkit/tiostream.h - toolkit/tfile.h - toolkit/tfilestream.h - toolkit/tmap.h - toolkit/tmap.tcc - toolkit/tpropertymap.h - toolkit/trefcounter.h - toolkit/tdebuglistener.h - mpeg/mpegfile.h - mpeg/mpegproperties.h - mpeg/mpegheader.h - mpeg/xingheader.h - mpeg/id3v1/id3v1tag.h - mpeg/id3v1/id3v1genres.h - mpeg/id3v2/id3v2extendedheader.h - mpeg/id3v2/id3v2frame.h - mpeg/id3v2/id3v2header.h - mpeg/id3v2/id3v2synchdata.h - mpeg/id3v2/id3v2footer.h - mpeg/id3v2/id3v2framefactory.h - mpeg/id3v2/id3v2tag.h - 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 - mpeg/id3v2/frames/textidentificationframe.h - mpeg/id3v2/frames/uniquefileidentifierframe.h - mpeg/id3v2/frames/unknownframe.h - mpeg/id3v2/frames/unsynchronizedlyricsframe.h - mpeg/id3v2/frames/urllinkframe.h - ogg/oggfile.h - ogg/oggpage.h - ogg/oggpageheader.h - ogg/xiphcomment.h - ogg/vorbis/vorbisfile.h - ogg/vorbis/vorbisproperties.h - 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 - flac/flacmetadatablock.h - ape/apefile.h - ape/apeproperties.h - ape/apetag.h - ape/apefooter.h - ape/apeitem.h - mpc/mpcfile.h - mpc/mpcproperties.h - wavpack/wavpackfile.h - wavpack/wavpackproperties.h - trueaudio/trueaudiofile.h - trueaudio/trueaudioproperties.h - riff/rifffile.h - riff/aiff/aifffile.h - 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 - asf/asfattribute.h - asf/asfpicture.h - mp4/mp4file.h - mp4/mp4atom.h - mp4/mp4tag.h - mp4/mp4item.h - mp4/mp4properties.h - mp4/mp4coverart.h - mod/modfilebase.h - mod/modfile.h - mod/modtag.h - mod/modproperties.h - it/itfile.h - it/itproperties.h - s3m/s3mfile.h - s3m/s3mproperties.h - xm/xmfile.h - xm/xmproperties.h -) - -set(mpeg_SRCS - mpeg/mpegfile.cpp - mpeg/mpegproperties.cpp - mpeg/mpegheader.cpp - mpeg/xingheader.cpp -) - -set(id3v1_SRCS - mpeg/id3v1/id3v1tag.cpp - mpeg/id3v1/id3v1genres.cpp -) - -set(id3v2_SRCS - mpeg/id3v2/id3v2framefactory.cpp - mpeg/id3v2/id3v2synchdata.cpp - mpeg/id3v2/id3v2tag.cpp - mpeg/id3v2/id3v2header.cpp - mpeg/id3v2/id3v2frame.cpp - mpeg/id3v2/id3v2footer.cpp - mpeg/id3v2/id3v2extendedheader.cpp - ) - -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 - mpeg/id3v2/frames/textidentificationframe.cpp - mpeg/id3v2/frames/uniquefileidentifierframe.cpp - mpeg/id3v2/frames/unknownframe.cpp - mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp - mpeg/id3v2/frames/urllinkframe.cpp -) - -set(ogg_SRCS - ogg/oggfile.cpp - ogg/oggpage.cpp - ogg/oggpageheader.cpp - ogg/xiphcomment.cpp -) - -set(vorbis_SRCS - ogg/vorbis/vorbisfile.cpp - ogg/vorbis/vorbisproperties.cpp -) - -set(flacs_SRCS - flac/flacfile.cpp - flac/flacpicture.cpp - flac/flacproperties.cpp - flac/flacmetadatablock.cpp - flac/flacunknownmetadatablock.cpp -) - -set(oggflacs_SRCS - ogg/flac/oggflacfile.cpp -) - -set(mpc_SRCS - mpc/mpcfile.cpp - mpc/mpcproperties.cpp -) - -set(mp4_SRCS - mp4/mp4file.cpp - mp4/mp4atom.cpp - mp4/mp4tag.cpp - mp4/mp4item.cpp - mp4/mp4properties.cpp - mp4/mp4coverart.cpp -) - -set(ape_SRCS - ape/apetag.cpp - ape/apefooter.cpp - ape/apeitem.cpp - ape/apefile.cpp - ape/apeproperties.cpp -) - -set(wavpack_SRCS - wavpack/wavpackfile.cpp - wavpack/wavpackproperties.cpp -) - -set(speex_SRCS - ogg/speex/speexfile.cpp - ogg/speex/speexproperties.cpp -) - -set(opus_SRCS - ogg/opus/opusfile.cpp - ogg/opus/opusproperties.cpp -) - -set(trueaudio_SRCS - trueaudio/trueaudiofile.cpp - trueaudio/trueaudioproperties.cpp -) - -set(asf_SRCS - asf/asftag.cpp - asf/asffile.cpp - asf/asfproperties.cpp - asf/asfattribute.cpp - asf/asfpicture.cpp -) - -set(riff_SRCS - riff/rifffile.cpp -) - -set(aiff_SRCS - riff/aiff/aifffile.cpp - riff/aiff/aiffproperties.cpp -) - -set(wav_SRCS - riff/wav/wavfile.cpp - riff/wav/wavproperties.cpp - riff/wav/infotag.cpp -) - -set(mod_SRCS - mod/modfilebase.cpp - mod/modfile.cpp - mod/modtag.cpp - mod/modproperties.cpp -) - -set(s3m_SRCS - s3m/s3mfile.cpp - s3m/s3mproperties.cpp -) - -set(it_SRCS - it/itfile.cpp - it/itproperties.cpp -) - -set(xm_SRCS - xm/xmfile.cpp - xm/xmproperties.cpp -) - -set(toolkit_SRCS - toolkit/tstring.cpp - toolkit/tstringlist.cpp - toolkit/tbytevector.cpp - toolkit/tbytevectorlist.cpp - toolkit/tbytevectorstream.cpp - toolkit/tiostream.cpp - toolkit/tfile.cpp - toolkit/tfilestream.cpp - toolkit/tdebug.cpp - toolkit/tpropertymap.cpp - toolkit/trefcounter.cpp - toolkit/tdebuglistener.cpp - toolkit/unicode.cpp -) - -set(tag_LIB_SRCS - ${mpeg_SRCS} ${id3v1_SRCS} ${id3v2_SRCS} ${frames_SRCS} ${ogg_SRCS} - ${vorbis_SRCS} ${oggflacs_SRCS} ${mpc_SRCS} ${ape_SRCS} ${toolkit_SRCS} ${flacs_SRCS} - ${wavpack_SRCS} ${speex_SRCS} ${trueaudio_SRCS} ${riff_SRCS} ${aiff_SRCS} ${wav_SRCS} - ${asf_SRCS} ${mp4_SRCS} ${mod_SRCS} ${s3m_SRCS} ${it_SRCS} ${xm_SRCS} ${opus_SRCS} - tag.cpp - tagunion.cpp - fileref.cpp - audioproperties.cpp -) - -add_library(tag ${tag_LIB_SRCS} ${tag_HDRS}) - -if(ZLIB_FOUND) - target_link_libraries(tag ${ZLIB_LIBRARIES}) -endif() - -set_target_properties(tag PROPERTIES - VERSION ${TAGLIB_SOVERSION_MAJOR}.${TAGLIB_SOVERSION_MINOR}.${TAGLIB_SOVERSION_PATCH} - SOVERSION ${TAGLIB_SOVERSION_MAJOR} - INSTALL_NAME_DIR ${LIB_INSTALL_DIR} - DEFINE_SYMBOL MAKE_TAGLIB_LIB - LINK_INTERFACE_LIBRARIES "" - PUBLIC_HEADER "${tag_HDRS}" -) -if(BUILD_FRAMEWORK) - set_target_properties(tag PROPERTIES FRAMEWORK TRUE) -endif() - -install(TARGETS tag - FRAMEWORK DESTINATION ${FRAMEWORK_INSTALL_DIR} - LIBRARY DESTINATION ${LIB_INSTALL_DIR} - RUNTIME DESTINATION ${BIN_INSTALL_DIR} - ARCHIVE DESTINATION ${LIB_INSTALL_DIR} - PUBLIC_HEADER DESTINATION ${INCLUDE_INSTALL_DIR}/taglib -) - diff --git a/taglib/taglib/ape/ape-tag-format.txt b/taglib/taglib/ape/ape-tag-format.txt deleted file mode 100644 index 21ff1c8..0000000 --- a/taglib/taglib/ape/ape-tag-format.txt +++ /dev/null @@ -1,170 +0,0 @@ -================================================================================ -= APE Tag Specification, Version 2.000 -================================================================================ - -Original Content (C) 2004, Frank Klemm <frank.klemm@elster.offl.uni-jena.de> -Formatting / Editing (C) 2004, Scott Wheeler <wheeler@kde.org> - -================================================================================ -= Contents -================================================================================ - -1 - APE Tag General Structure -2 - APE Tag Header / Footer Format -3 - APE Tag Flags -4 - APE Tag Item Format -5 - APE Tag Item Supported Keys -6 - APE Tag Item Content -7 - Data Types -7.1 - Data Types / UTF-8 -7.2 - Data Types / Dates -7.3 - Data Types / Timestamps - -================================================================================ -= 1 - APE Tag General Structure -================================================================================ - -Member of Basic Components of SV8 Stream Note: - -It is strongly recommended that the data size be stored in the tags. The size -should normally be in the roughly one kilobyte, never more than 8 kilobytes. - -Larger data should be stored externally using link entries. Linked data is much -easier to process by normal programs, so for instance JPEG data should not be -included inside the audio file. - -APE Tag Version 2.000 (with header, recommended): - -/================================\ -| APE Tag Header | 32 bytes | -|-------------------|------------| -| APE Tag Item 1 | > 10 bytes | -| APE Tag Item 2 | > 10 bytes | -| APE Tag Item n-1 | > 10 bytes | -| APE Tag Item n | > 10 bytes | -|-------------------|------------| -| APE Tag Footer | 32 bytes | -\================================/ - - -APE tag items should be sorted ascending by size. When streaming, parts of the -APE tag may be dropped to reduce the danger of drop outs between tracks. This -is not required, but is strongly recommended. It would be desirable for the i -tems to be sorted by importance / size, but this is not feasible. This -convention should only be broken when adding less important small items and it -is not desirable to rewrite the entire tag. An APE tag at the end of a file -(the recommended location) must have at least a footer; an APE tag at the -beginning of a file (strongly discouraged) must have at least a header. - -APE Tag Version 1.000 (without header, deprecated) - -/================================\ -| APE Tag Item 1 | > 10 bytes | -| APE Tag Item 2 | > 10 bytes | -| APE Tag Item n-1 | > 10 bytes | -| APE Tag Item n | > 10 bytes | -|-------------------|------------| -| APE Tag Footer | 32 bytes | -\================================/ - -================================================================================ -= 2 - APE Tag Header / Footer Format -================================================================================ - -Contains number, length and attributes of all tag items - -Header and Footer are different in 1 bit in the Tags Flags to distinguish -between them. - -Member of APE Tag 2.0 - -/===========================================================================\ -| Preamble | 8 bytes | { 'A', 'P', 'E', 'T', 'A', 'G', 'E', 'X' } | -|----------------|---------|------------------------------------------------| -| Version Number | 4 bytes | 1000 = Version 1.000, 2000 = Version 2.000 | -|----------------|---------|------------------------------------------------| -| Tag Size | 4 bytes | Tag size in bytes including footer and all tag | -| | | items excluding the header (for 1.000 | -| | | compatibility) | -|----------------|---------|------------------------------------------------| -| Item Count | 4 bytes | Number of items in the tag | -|----------------|---------|------------------------------------------------| -| Tag Flags | 4 bytes | Global flags | -|----------------|---------|------------------------------------------------| -| Reserved | 8 bytes | Must be zeroed | -\===========================================================================/ - -================================================================================ -= 3 - APE Tag Flags -================================================================================ - -The general flag structure for either items or headers / footers is the same. -Bits 31, 30 and 29 are specific to headers / footers, whereas 2 through 0 are -item specific. - -Note: APE Tags from Version 1.0 do not use any of the following. All flags in -that version are zeroed and ignored when reading. - -/=================================================================\ -| Contains Header | Bit 31 | 1 - has header | 0 - no header | -|-----------------|-------------|---------------------------------| -| Contains Footer | Bit 30 | 1 - has footer | 0 - no footer | -|-----------------|-------------|---------------------------------| -| Is Header | Bit 29 | 1 - is header | 0 - is footer | -|-----------------|-------------|---------------------------------| -| Undefined | Bits 28 - 3 | Undefined, must be zeroed | -|-----------------|-------------|---------------------------------| -| Encoding | Bits 2 - 1 | 00 - UTF-8 | -| | | 01 - Binary Data * | -| | | 10 - External Reference ** | -| | | 11 - Reserved | -|-----------------|-------------|---------------------------------| -| Read Only | Bit 0 | 1 - read only | 0 - read/write | -\=================================================================/ - - (*) Should be ignored by tools for editing text values -(**) Allowed external reference formats: - - http://host/directory/filename.ext - - ftp://host/directory/filename.ext - - filename.ext - - /directory/filename.ext - - DRIVE:/directory/filename.ext - - Note: External references are also UTF-8 encoded. - -================================================================================ -= 4 - APE Tag Item Format -================================================================================ - -APE Tag Items are stored as key-value pairs. APE Tags Item Key are case -sensitive, however it is illegal to use keys which only differ in case and -it is recommended that tag reading not be case sensitive. - -Every key can only occur (at most) once. It is not possible to repeat a key -to signify updated contents. - -Tags can be partially or completely repeated in the streaming format. This -makes it possible to display an artist and / or title if it was missed at the -beginning of the stream. It is recommended that the important information like -artist, album and title should occur approximately every 2 minutes in the -stream and again 5 to 10 seconds before the end. However, care should be tak -en not to replicate this information too often or during passages with high -bitrate demands to avoid unnecessary drop-outs. - -/==============================================================================\ -| Content Size | 4 bytes | Length of the value in bytes | -|----------------|---------------|---------------------------------------------| -| Flags | 4 bytes | Item flags | -|----------------|---------------|---------------------------------------------| -| Key | 2 - 255 bytes | Item key | -|----------------|---------------|---------------------------------------------| -| Key Terminator | 1 byte | Null byte that indicates the end of the key | -|----------------|---------------|---------------------------------------------| -| Value | variable | Content (formatted according to the flags) | -\==============================================================================/ - -================================================================================ - -Sections 5 - 7 haven't yet been converted from: - -http://www.personal.uni-jena.de/~pfk/mpp/sv8/apetag.html diff --git a/taglib/taglib/ape/apefile.cpp b/taglib/taglib/ape/apefile.cpp deleted file mode 100644 index 3cb9d9a..0000000 --- a/taglib/taglib/ape/apefile.cpp +++ /dev/null @@ -1,314 +0,0 @@ -/*************************************************************************** - copyright : (C) 2010 by Alex Novichkov - email : novichko@atnet.ru - - copyright : (C) 2006 by Lukáš Lalinský - email : lalinsky@gmail.com - (original WavPack implementation) - - copyright : (C) 2004 by Allan Sandfeld Jensen - email : kde@carewolf.org - (original MPC 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 <tbytevector.h> -#include <tstring.h> -#include <tdebug.h> -#include <tagunion.h> -#include <id3v1tag.h> -#include <tpropertymap.h> - -#include "apefile.h" - -#include "apetag.h" -#include "apefooter.h" - -using namespace TagLib; - -namespace -{ - enum { ApeAPEIndex = 0, ApeID3v1Index = 1 }; -} - -class APE::File::FilePrivate -{ -public: - FilePrivate() : - APELocation(-1), - APESize(0), - ID3v1Location(-1), - properties(0), - hasAPE(false), - hasID3v1(false) {} - - ~FilePrivate() - { - delete properties; - } - - long APELocation; - uint APESize; - - long ID3v1Location; - - TagUnion tag; - - Properties *properties; - - // These indicate whether the file *on disk* has these tags, not if - // this data structure does. This is used in computing offsets. - - bool hasAPE; - bool hasID3v1; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -APE::File::File(FileName file, bool readProperties, - Properties::ReadStyle propertiesStyle) : TagLib::File(file) -{ - d = new FilePrivate; - if(isOpen()) - read(readProperties, propertiesStyle); -} - -APE::File::File(IOStream *stream, bool readProperties, - Properties::ReadStyle propertiesStyle) : TagLib::File(stream) -{ - d = new FilePrivate; - if(isOpen()) - read(readProperties, propertiesStyle); -} - -APE::File::~File() -{ - delete d; -} - -TagLib::Tag *APE::File::tag() const -{ - return &d->tag; -} - -PropertyMap APE::File::properties() const -{ - if(d->hasAPE) - return d->tag.access<APE::Tag>(ApeAPEIndex, false)->properties(); - if(d->hasID3v1) - return d->tag.access<ID3v1::Tag>(ApeID3v1Index, false)->properties(); - return PropertyMap(); -} - -void APE::File::removeUnsupportedProperties(const StringList &properties) -{ - if(d->hasAPE) - d->tag.access<APE::Tag>(ApeAPEIndex, false)->removeUnsupportedProperties(properties); - if(d->hasID3v1) - d->tag.access<ID3v1::Tag>(ApeID3v1Index, false)->removeUnsupportedProperties(properties); -} - -PropertyMap APE::File::setProperties(const PropertyMap &properties) -{ - if(d->hasID3v1) - d->tag.access<ID3v1::Tag>(ApeID3v1Index, false)->setProperties(properties); - return d->tag.access<APE::Tag>(ApeAPEIndex, true)->setProperties(properties); -} - -APE::Properties *APE::File::audioProperties() const -{ - return d->properties; -} - -bool APE::File::save() -{ - if(readOnly()) { - debug("APE::File::save() -- File is read only."); - return false; - } - - // Update ID3v1 tag - - if(ID3v1Tag()) { - if(d->hasID3v1) { - seek(d->ID3v1Location); - writeBlock(ID3v1Tag()->render()); - } - else { - seek(0, End); - d->ID3v1Location = tell(); - writeBlock(ID3v1Tag()->render()); - d->hasID3v1 = true; - } - } - else { - if(d->hasID3v1) { - removeBlock(d->ID3v1Location, 128); - d->hasID3v1 = false; - if(d->hasAPE) { - if(d->APELocation > d->ID3v1Location) - d->APELocation -= 128; - } - } - } - - // Update APE tag - - if(APETag()) { - if(d->hasAPE) - insert(APETag()->render(), d->APELocation, d->APESize); - else { - if(d->hasID3v1) { - insert(APETag()->render(), d->ID3v1Location, 0); - d->APESize = APETag()->footer()->completeTagSize(); - d->hasAPE = true; - d->APELocation = d->ID3v1Location; - d->ID3v1Location += d->APESize; - } - else { - seek(0, End); - d->APELocation = tell(); - writeBlock(APETag()->render()); - d->APESize = APETag()->footer()->completeTagSize(); - d->hasAPE = true; - } - } - } - else { - if(d->hasAPE) { - removeBlock(d->APELocation, d->APESize); - d->hasAPE = false; - if(d->hasID3v1) { - if(d->ID3v1Location > d->APELocation) { - d->ID3v1Location -= d->APESize; - } - } - } - } - - return true; -} - -ID3v1::Tag *APE::File::ID3v1Tag(bool create) -{ - return d->tag.access<ID3v1::Tag>(ApeID3v1Index, create); -} - -APE::Tag *APE::File::APETag(bool create) -{ - return d->tag.access<APE::Tag>(ApeAPEIndex, create); -} - -void APE::File::strip(int tags) -{ - if(tags & ID3v1) { - d->tag.set(ApeID3v1Index, 0); - APETag(true); - } - - if(tags & APE) { - d->tag.set(ApeAPEIndex, 0); - - if(!ID3v1Tag()) - APETag(true); - } -} - -bool APE::File::hasAPETag() const -{ - return d->hasAPE; -} - -bool APE::File::hasID3v1Tag() const -{ - return d->hasID3v1; -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -void APE::File::read(bool readProperties, Properties::ReadStyle /* propertiesStyle */) -{ - // Look for an ID3v1 tag - - d->ID3v1Location = findID3v1(); - - if(d->ID3v1Location >= 0) { - d->tag.set(ApeID3v1Index, new ID3v1::Tag(this, d->ID3v1Location)); - d->hasID3v1 = true; - } - - // Look for an APE tag - - d->APELocation = findAPE(); - - if(d->APELocation >= 0) { - d->tag.set(ApeAPEIndex, new APE::Tag(this, d->APELocation)); - d->APESize = APETag()->footer()->completeTagSize(); - d->APELocation = d->APELocation + APETag()->footer()->size() - d->APESize; - d->hasAPE = true; - } - - if(!d->hasID3v1) - APETag(true); - - // Look for APE audio properties - - if(readProperties) { - d->properties = new Properties(this); - } -} - -long APE::File::findAPE() -{ - if(!isValid()) - return -1; - - if(d->hasID3v1) - seek(-160, End); - else - seek(-32, End); - - long p = tell(); - - if(readBlock(8) == APE::Tag::fileIdentifier()) - return p; - - return -1; -} - -long APE::File::findID3v1() -{ - if(!isValid()) - return -1; - - seek(-128, End); - long p = tell(); - - if(readBlock(3) == ID3v1::Tag::fileIdentifier()) - return p; - - return -1; -} diff --git a/taglib/taglib/ape/apefile.h b/taglib/taglib/ape/apefile.h deleted file mode 100644 index f7b509f..0000000 --- a/taglib/taglib/ape/apefile.h +++ /dev/null @@ -1,229 +0,0 @@ -/*************************************************************************** - copyright : (C) 2010 by Alex Novichkov - email : novichko@atnet.ru - - copyright : (C) 2006 by Lukáš Lalinský - email : lalinsky@gmail.com - (original WavPack implementation) - - copyright : (C) 2004 by Allan Sandfeld Jensen - email : kde@carewolf.org - (original MPC 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_APEFILE_H -#define TAGLIB_APEFILE_H - -#include "tfile.h" -#include "taglib_export.h" -#include "apeproperties.h" - -namespace TagLib { - - class Tag; - - namespace ID3v1 { class Tag; } - namespace APE { class Tag; } - - //! An implementation of APE metadata - - /*! - * This is implementation of APE metadata. - * - * This supports ID3v1 and APE (v1 and v2) style comments as well as reading stream - * properties from the file. - */ - - namespace APE { - - //! An implementation of TagLib::File with APE specific methods - - /*! - * 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. - */ - - class TAGLIB_EXPORT File : public TagLib::File - { - public: - /*! - * This set of flags is used for various operations and is suitable for - * being OR-ed together. - */ - enum TagTypes { - //! Empty set. Matches no tag types. - NoTags = 0x0000, - //! Matches ID3v1 tags. - ID3v1 = 0x0001, - //! Matches APE tags. - APE = 0x0002, - //! Matches all tag types. - AllTags = 0xffff - }; - - /*! - * 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); - - /*! - * 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); - - /*! - * Destroys this instance of the File. - */ - virtual ~File(); - - /*! - * Returns the Tag for this file. This will be an APE tag, an ID3v1 tag - * or a combination of the two. - */ - virtual TagLib::Tag *tag() const; - - /*! - * Implements the unified property interface -- export function. - * If the file contains both an APE and an ID3v1 tag, only APE - * will be converted to the PropertyMap. - */ - PropertyMap properties() const; - - /*! - * Removes unsupported properties. Forwards to the actual Tag's - * removeUnsupportedProperties() function. - */ - void removeUnsupportedProperties(const StringList &properties); - - /*! - * Implements the unified property interface -- import function. - * Creates an APEv2 tag if necessary. A 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. - */ - virtual Properties *audioProperties() const; - - /*! - * Saves the file. - * - * \note According to the official Monkey's Audio SDK, an APE file - * can only have either ID3V1 or APE tags, so a parameter is used here. - */ - virtual bool save(); - - /*! - * Returns a pointer to the ID3v1 tag of the file. - * - * 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 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 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); - - /*! - * This will remove the tags that match the OR-ed together TagTypes from the - * file. By default it removes all tags. - * - * \note This will also invalidate pointers to the tags - * as their memory will be freed. - * \note In order to make the removal permanent save() still needs to be called - */ - void strip(int tags = AllTags); - - /*! - * Returns whether or not the file on disk actually has an APE tag. - * - * \see APETag() - */ - bool hasAPETag() const; - - /*! - * Returns whether or not the file on disk actually has an ID3v1 tag. - * - * \see ID3v1Tag() - */ - bool hasID3v1Tag() const; - - private: - File(const File &); - File &operator=(const File &); - - void read(bool readProperties, Properties::ReadStyle propertiesStyle); - void scan(); - long findID3v1(); - long findAPE(); - - class FilePrivate; - FilePrivate *d; - }; - } -} - -#endif diff --git a/taglib/taglib/ape/apefooter.cpp b/taglib/taglib/ape/apefooter.cpp deleted file mode 100644 index 539832b..0000000 --- a/taglib/taglib/ape/apefooter.cpp +++ /dev/null @@ -1,236 +0,0 @@ -/*************************************************************************** - copyright : (C) 2004 by Allan Sandfeld Jensen - (C) 2002 - 2008 by Scott Wheeler (id3v2header.cpp) - email : kde@carewolf.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <iostream> -#include <bitset> - -#include <tstring.h> -#include <tdebug.h> - -#include "apefooter.h" - -using namespace TagLib; -using namespace APE; - -class APE::Footer::FooterPrivate -{ -public: - FooterPrivate() : version(0), - footerPresent(true), - headerPresent(false), - isHeader(false), - itemCount(0), - tagSize(0) {} - - ~FooterPrivate() {} - - uint version; - - bool footerPresent; - bool headerPresent; - - bool isHeader; - - uint itemCount; - uint tagSize; - - static const uint size = 32; -}; - -//////////////////////////////////////////////////////////////////////////////// -// static members -//////////////////////////////////////////////////////////////////////////////// - -TagLib::uint APE::Footer::size() -{ - return FooterPrivate::size; -} - -ByteVector APE::Footer::fileIdentifier() -{ - return ByteVector::fromCString("APETAGEX"); -} - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -APE::Footer::Footer() -{ - d = new FooterPrivate; -} - -APE::Footer::Footer(const ByteVector &data) -{ - d = new FooterPrivate; - parse(data); -} - -APE::Footer::~Footer() -{ - delete d; -} - -TagLib::uint APE::Footer::version() const -{ - return d->version; -} - -bool APE::Footer::headerPresent() const -{ - return d->headerPresent; -} - -bool APE::Footer::footerPresent() const -{ - return d->footerPresent; -} - -bool APE::Footer::isHeader() const -{ - return d->isHeader; -} - -void APE::Footer::setHeaderPresent(bool b) const -{ - d->headerPresent = b; -} - -TagLib::uint APE::Footer::itemCount() const -{ - return d->itemCount; -} - -void APE::Footer::setItemCount(uint s) -{ - d->itemCount = s; -} - -TagLib::uint APE::Footer::tagSize() const -{ - return d->tagSize; -} - -TagLib::uint APE::Footer::completeTagSize() const -{ - if(d->headerPresent) - return d->tagSize + d->size; - else - return d->tagSize; -} - -void APE::Footer::setTagSize(uint s) -{ - d->tagSize = s; -} - -void APE::Footer::setData(const ByteVector &data) -{ - parse(data); -} - -ByteVector APE::Footer::renderFooter() const -{ - return render(false); -} - -ByteVector APE::Footer::renderHeader() const -{ - if (!d->headerPresent) return ByteVector(); - - return render(true); -} - -//////////////////////////////////////////////////////////////////////////////// -// protected members -//////////////////////////////////////////////////////////////////////////////// - -void APE::Footer::parse(const ByteVector &data) -{ - if(data.size() < size()) - return; - - // The first eight bytes, data[0..7], are the File Identifier, "APETAGEX". - - // Read the version number - - d->version = data.toUInt(8, false); - - // Read the tag size - - d->tagSize = data.toUInt(12, false); - - // Read the item count - - d->itemCount = data.toUInt(16, false); - - // Read the flags - - std::bitset<32> flags(TAGLIB_CONSTRUCT_BITSET(data.toUInt(20, false))); - - d->headerPresent = flags[31]; - d->footerPresent = !flags[30]; - d->isHeader = flags[29]; - -} - -ByteVector APE::Footer::render(bool isHeader) const -{ - ByteVector v; - - // add the file identifier -- "APETAGEX" - - v.append(fileIdentifier()); - - // add the version number -- we always render a 2.000 tag regardless of what - // the tag originally was. - - v.append(ByteVector::fromUInt(2000, false)); - - // add the tag size - - v.append(ByteVector::fromUInt(d->tagSize, false)); - - // add the item count - - v.append(ByteVector::fromUInt(d->itemCount, false)); - - // render and add the flags - - std::bitset<32> flags; - - flags[31] = d->headerPresent; - flags[30] = false; // footer is always present - flags[29] = isHeader; - - v.append(ByteVector::fromUInt(flags.to_ulong(), false)); - - // add the reserved 64bit - - v.append(ByteVector::fromLongLong(0)); - - return v; -} diff --git a/taglib/taglib/ape/apefooter.h b/taglib/taglib/ape/apefooter.h deleted file mode 100644 index 080f930..0000000 --- a/taglib/taglib/ape/apefooter.h +++ /dev/null @@ -1,173 +0,0 @@ -/*************************************************************************** - copyright : (C) 2004 by Allan Sandfeld Jensen - email : kde@carewolf.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_APEFOOTER_H -#define TAGLIB_APEFOOTER_H - -#include "tbytevector.h" -#include "taglib_export.h" - -namespace TagLib { - - namespace APE { - - //! An implementation of APE footers - - /*! - * This class implements APE footers (and headers). It attempts to follow, both - * semantically and programatically, the structure specified in - * the APE v2.0 standard. The API is based on the properties of APE footer and - * headers specified there. - */ - - class TAGLIB_EXPORT Footer - { - public: - /*! - * Constructs an empty APE footer. - */ - Footer(); - - /*! - * Constructs an APE footer based on \a data. parse() is called - * immediately. - */ - Footer(const ByteVector &data); - - /*! - * Destroys the footer. - */ - virtual ~Footer(); - - /*! - * Returns the version number. (Note: This is the 1000 or 2000.) - */ - uint version() const; - - /*! - * Returns true if a header is present in the tag. - */ - bool headerPresent() const; - - /*! - * Returns true if a footer is present in the tag. - */ - bool footerPresent() const; - - /*! - * Returns true this is actually the header. - */ - bool isHeader() const; - - /*! - * Sets whether the header should be rendered or not - */ - void setHeaderPresent(bool b) const; - - /*! - * Returns the number of items in the tag. - */ - uint itemCount() const; - - /*! - * Set the item count to \a s. - * \see itemCount() - */ - void setItemCount(uint s); - - /*! - * Returns the tag size in bytes. This is the size of the frame content and footer. - * The size of the \e entire tag will be this plus the header size, if present. - * - * \see completeTagSize() - */ - uint tagSize() const; - - /*! - * Returns the tag size, including if present, the header - * size. - * - * \see tagSize() - */ - uint completeTagSize() const; - - /*! - * Set the tag size to \a s. - * \see tagSize() - */ - void setTagSize(uint s); - - /*! - * Returns the size of the footer. Presently this is always 32 bytes. - */ - static uint size(); - - /*! - * Returns the string used to identify an APE tag inside of a file. - * Presently this is always "APETAGEX". - */ - static ByteVector fileIdentifier(); - - /*! - * Sets the data that will be used as the footer. 32 bytes, - * starting from \a data will be used. - */ - void setData(const ByteVector &data); - - /*! - * Renders the footer back to binary format. - */ - ByteVector renderFooter() const; - - /*! - * Renders the header corresponding to the footer. If headerPresent is - * set to false, it returns an empty ByteVector. - */ - ByteVector renderHeader() const; - - protected: - /*! - * Called by setData() to parse the footer data. It makes this information - * available through the public API. - */ - void parse(const ByteVector &data); - - /*! - * Called by renderFooter and renderHeader - */ - ByteVector render(bool isHeader) const; - - private: - Footer(const Footer &); - Footer &operator=(const Footer &); - - class FooterPrivate; - FooterPrivate *d; - }; - - } -} - -#endif diff --git a/taglib/taglib/ape/apeitem.cpp b/taglib/taglib/ape/apeitem.cpp deleted file mode 100644 index 3490173..0000000 --- a/taglib/taglib/ape/apeitem.cpp +++ /dev/null @@ -1,286 +0,0 @@ -/*************************************************************************** - copyright : (C) 2004 by Allan Sandfeld Jensen - email : kde@carewolf.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 <tbytevectorlist.h> -#include <tdebug.h> - -#include "apeitem.h" - -using namespace TagLib; -using namespace APE; - -class APE::Item::ItemPrivate -{ -public: - ItemPrivate() : type(Text), readOnly(false) {} - - Item::ItemTypes type; - String key; - ByteVector value; - StringList text; - bool readOnly; -}; - -APE::Item::Item() -{ - d = new ItemPrivate; -} - -APE::Item::Item(const String &key, const String &value) -{ - d = new ItemPrivate; - d->key = key; - d->text.append(value); -} - -APE::Item::Item(const String &key, const StringList &values) -{ - d = new ItemPrivate; - d->key = key; - d->text = values; -} - -APE::Item::Item(const String &key, const ByteVector &value, bool binary) -{ - d = new ItemPrivate; - d->key = key; - if(binary) { - d->type = Binary; - d->value = value; - } - else - d->text.append(value); -} - -APE::Item::Item(const Item &item) -{ - d = new ItemPrivate(*item.d); -} - -APE::Item::~Item() -{ - delete d; -} - -Item &APE::Item::operator=(const Item &item) -{ - delete d; - d = new ItemPrivate(*item.d); - return *this; -} - -void APE::Item::setReadOnly(bool readOnly) -{ - d->readOnly = readOnly; -} - -bool APE::Item::isReadOnly() const -{ - return d->readOnly; -} - -void APE::Item::setType(APE::Item::ItemTypes val) -{ - d->type = val; -} - -APE::Item::ItemTypes APE::Item::type() const -{ - return d->type; -} - -String APE::Item::key() const -{ - return d->key; -} - -ByteVector APE::Item::binaryData() const -{ - return d->value; -} - -void APE::Item::setBinaryData(const ByteVector &value) -{ - d->type = Binary; - d->value = value; - d->text.clear(); -} - -ByteVector APE::Item::value() const -{ - // This seems incorrect as it won't be actually rendering the value to keep it - // up to date. - - return d->value; -} - -void APE::Item::setKey(const String &key) -{ - d->key = key; -} - -void APE::Item::setValue(const String &value) -{ - d->type = Text; - d->text = value; - d->value.clear(); -} - -void APE::Item::setValues(const StringList &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->value.clear(); -} - -void APE::Item::appendValues(const StringList &values) -{ - d->type = Text; - d->text.append(values); - d->value.clear(); -} - -int APE::Item::size() const -{ - // SFB: Why is d->key.size() used when size() returns the length in UniChars and not UTF-8? - int result = 8 + d->key.size() /* d->key.data(String::UTF8).size() */ + 1; - switch (d->type) { - case Text: - if(d->text.size()) { - StringList::ConstIterator it = d->text.begin(); - - result += it->data(String::UTF8).size(); - it++; - for(; it != d->text.end(); ++it) - result += 1 + it->data(String::UTF8).size(); - } - break; - - case Binary: - case Locator: - result += d->value.size(); - break; - } - return result; -} - -StringList APE::Item::toStringList() const -{ - return d->text; -} - -StringList APE::Item::values() const -{ - return d->text; -} - -String APE::Item::toString() const -{ - if(d->type == Text && !isEmpty()) - return d->text.front(); - else - return String::null; -} - -bool APE::Item::isEmpty() const -{ - switch(d->type) { - case Text: - if(d->text.isEmpty()) - return true; - if(d->text.size() == 1 && d->text.front().isEmpty()) - return true; - return false; - case Binary: - case Locator: - return d->value.isEmpty(); - default: - return false; - } -} - -void APE::Item::parse(const ByteVector &data) -{ - // 11 bytes is the minimum size for an APE item - - if(data.size() < 11) { - debug("APE::Item::parse() -- no data in item"); - return; - } - - const uint valueLength = data.toUInt(0, false); - const uint flags = data.toUInt(4, false); - - d->key = String(data.mid(8), String::UTF8); - - 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(value, '\0'), String::UTF8); - else - d->value = value; -} - -ByteVector APE::Item::render() const -{ - ByteVector data; - TagLib::uint flags = ((d->readOnly) ? 1 : 0) | (d->type << 1); - ByteVector value; - - if(isEmpty()) - return data; - - if(d->type == Text) { - StringList::ConstIterator it = d->text.begin(); - - value.append(it->data(String::UTF8)); - it++; - for(; it != d->text.end(); ++it) { - value.append('\0'); - value.append(it->data(String::UTF8)); - } - d->value = value; - } - else - value.append(d->value); - - data.append(ByteVector::fromUInt(value.size(), false)); - data.append(ByteVector::fromUInt(flags, false)); - data.append(d->key.data(String::UTF8)); - data.append(ByteVector('\0')); - data.append(value); - - return data; -} diff --git a/taglib/taglib/ape/apeitem.h b/taglib/taglib/ape/apeitem.h deleted file mode 100644 index 0588d18..0000000 --- a/taglib/taglib/ape/apeitem.h +++ /dev/null @@ -1,219 +0,0 @@ -/*************************************************************************** - copyright : (C) 2004 by Allan Sandfeld Jensen - email : kde@carewolf.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_APEITEM_H -#define TAGLIB_APEITEM_H - -#include "tbytevector.h" -#include "tstring.h" -#include "tstringlist.h" - -namespace TagLib { - - namespace APE { - - //! An implementation of APE-items - - /*! - * This class provides the features of items in the APEv2 standard. - */ - class TAGLIB_EXPORT Item - { - public: - /*! - * Enum of types an Item can have. The value of 3 is reserved. - */ - enum ItemTypes { - //! Item contains text information coded in UTF-8 - Text = 0, - //! Item contains binary information - Binary = 1, - //! Item is a locator of external stored information - Locator = 2 - }; - /*! - * Constructs an empty item. - */ - Item(); - - /*! - * Constructs a text item with \a key and \a value. - */ - // BIC: Remove this, StringList has a constructor from a single string - Item(const String &key, const String &value); - - /*! - * Constructs a text item with \a key and \a values. - */ - Item(const String &key, const StringList &values); - - /*! - * Constructs an item with \a key and \a value. - * If \a binary is true a Binary item will be created, otherwise \a value will be interpreted as text - */ - Item(const String &key, const ByteVector &value, bool binary); - - /*! - * Construct an item as a copy of \a item. - */ - Item(const Item &item); - - /*! - * Destroys the item. - */ - virtual ~Item(); - - /*! - * Copies the contents of \a item into this item. - */ - Item &operator=(const Item &item); - - /*! - * Returns the key. - */ - String key() const; - - /*! - * Returns the binary value. - * If the item type is not \a Binary, always returns an empty ByteVector. - */ - ByteVector binaryData() const; - - /*! - * Set the binary value to \a value - * The item's type will also be set to \a Binary - */ - void setBinaryData(const ByteVector &value); - -#ifndef DO_NOT_DOCUMENT - /* Remove in next binary incompatible release */ - ByteVector value() const; -#endif - - /*! - * Sets the key for the item to \a key. - */ - void setKey(const String &key); - - /*! - * Sets the text value of the item to \a value and clears any previous contents. - * - * \see toString() - */ - void setValue(const String &value); - - /*! - * Sets the text value of the item to the list of values in \a value and clears - * any previous contents. - * - * \see toStringList() - */ - void setValues(const StringList &values); - - /*! - * Appends \a value to create (or extend) the current list of text values. - * - * \see toString() - */ - void appendValue(const String &value); - - /*! - * Appends \a values to extend the current list of text values. - * - * \see toStringList() - */ - void appendValues(const StringList &values); - - /*! - * Returns the size of the full item. - */ - int size() const; - - /*! - * 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; - -#ifndef DO_NOT_DOCUMENT - /* Remove in next binary incompatible release */ - StringList toStringList() const; -#endif - - /*! - * Returns the list of text values. If the data type is not \a Text, always - * returns an empty StringList. - */ - StringList values() const; - - /*! - * Render the item to a ByteVector. - */ - ByteVector render() const; - - /*! - * Parse the item from the ByteVector \a data. - */ - void parse(const ByteVector& data); - - /*! - * Set the item to read-only. - */ - void setReadOnly(bool readOnly); - - /*! - * Return true if the item is read-only. - */ - bool isReadOnly() const; - - /*! - * Sets the type of the item to \a type. - * - * \see ItemTypes - */ - void setType(ItemTypes type); - - /*! - * Returns the type of the item. - */ - ItemTypes type() const; - - /*! - * Returns if the item has any real content. - */ - bool isEmpty() const; - - private: - class ItemPrivate; - ItemPrivate *d; - }; - } - -} - -#endif - - diff --git a/taglib/taglib/ape/apeproperties.cpp b/taglib/taglib/ape/apeproperties.cpp deleted file mode 100644 index 4940ede..0000000 --- a/taglib/taglib/ape/apeproperties.cpp +++ /dev/null @@ -1,232 +0,0 @@ -/*************************************************************************** - copyright : (C) 2010 by Alex Novichkov - email : novichko@atnet.ru - - copyright : (C) 2006 by Lukáš Lalinský - email : lalinsky@gmail.com - (original WavPack 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 <bitset> -#include "id3v2tag.h" -#include "apeproperties.h" -#include "apefile.h" - -using namespace TagLib; - -class APE::Properties::PropertiesPrivate -{ -public: - PropertiesPrivate(File *file, long streamLength) : - length(0), - bitrate(0), - sampleRate(0), - channels(0), - version(0), - bitsPerSample(0), - sampleFrames(0), - file(file), - streamLength(streamLength) {} - - int length; - int bitrate; - int sampleRate; - int channels; - int version; - int bitsPerSample; - uint sampleFrames; - File *file; - long streamLength; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -APE::Properties::Properties(File *file, ReadStyle style) : AudioProperties(style) -{ - d = new PropertiesPrivate(file, file->length()); - read(); -} - -APE::Properties::~Properties() -{ - delete d; -} - -int APE::Properties::length() const -{ - return d->length; -} - -int APE::Properties::bitrate() const -{ - return d->bitrate; -} - -int APE::Properties::sampleRate() const -{ - return d->sampleRate; -} - -int APE::Properties::channels() const -{ - return d->channels; -} - -int APE::Properties::version() const -{ - return d->version; -} - -int APE::Properties::bitsPerSample() const -{ - return d->bitsPerSample; -} - -TagLib::uint APE::Properties::sampleFrames() const -{ - return d->sampleFrames; -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - - -void APE::Properties::read() -{ - // First we are searching the descriptor - long offset = findDescriptor(); - if(offset < 0) - return; - - // Then we read the header common for all versions of APE - d->file->seek(offset); - ByteVector commonHeader = d->file->readBlock(6); - if(!commonHeader.startsWith("MAC ")) - return; - d->version = commonHeader.toUShort(4, false); - - if(d->version >= 3980) { - analyzeCurrent(); - } - else { - analyzeOld(); - } -} - -long APE::Properties::findDescriptor() -{ - long ID3v2Location = findID3v2(); - long ID3v2OriginalSize = 0; - bool hasID3v2 = false; - if(ID3v2Location >= 0) { - ID3v2::Tag tag(d->file, ID3v2Location); - ID3v2OriginalSize = tag.header()->completeTagSize(); - if(tag.header()->tagSize() > 0) - hasID3v2 = true; - } - - long offset = 0; - if(hasID3v2) - offset = d->file->find("MAC ", ID3v2Location + ID3v2OriginalSize); - else - offset = d->file->find("MAC "); - - if(offset < 0) { - debug("APE::Properties::findDescriptor() -- APE descriptor not found"); - return -1; - } - - return offset; -} - -long APE::Properties::findID3v2() -{ - if(!d->file->isValid()) - return -1; - - d->file->seek(0); - - if(d->file->readBlock(3) == ID3v2::Header::fileIdentifier()) - return 0; - - return -1; -} - -void APE::Properties::analyzeCurrent() -{ - // Read the descriptor - d->file->seek(2, File::Current); - ByteVector descriptor = d->file->readBlock(44); - const uint descriptorBytes = descriptor.toUInt(0, false); - - if ((descriptorBytes - 52) > 0) - d->file->seek(descriptorBytes - 52, File::Current); - - // Read the header - ByteVector header = d->file->readBlock(24); - - // Get the APE info - d->channels = header.toShort(18, false); - d->sampleRate = header.toUInt(20, false); - d->bitsPerSample = header.toShort(16, false); - //d->compressionLevel = - - 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; -} - -void APE::Properties::analyzeOld() -{ - ByteVector header = d->file->readBlock(26); - const uint totalFrames = header.toUInt(18, false); - - // Fail on 0 length APE files (catches non-finalized APE files) - if(totalFrames == 0) - return; - - const short compressionLevel = header.toShort(0, false); - uint blocksPerFrame; - if(d->version >= 3950) - blocksPerFrame = 73728 * 4; - else if(d->version >= 3900 || (d->version >= 3800 && compressionLevel == 4000)) - blocksPerFrame = 73728; - else - blocksPerFrame = 9216; - 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; -} - diff --git a/taglib/taglib/ape/apeproperties.h b/taglib/taglib/ape/apeproperties.h deleted file mode 100644 index f154ec3..0000000 --- a/taglib/taglib/ape/apeproperties.h +++ /dev/null @@ -1,99 +0,0 @@ -/*************************************************************************** - copyright : (C) 2010 by Alex Novichkov - email : novichko@atnet.ru - - copyright : (C) 2006 by Lukáš Lalinský - email : lalinsky@gmail.com - (original WavPack 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_APEPROPERTIES_H -#define TAGLIB_APEPROPERTIES_H - -#include "taglib_export.h" -#include "audioproperties.h" - -namespace TagLib { - - namespace APE { - - class File; - - //! An implementation of audio property reading for APE - - /*! - * This reads the data from an APE stream found in the AudioProperties - * API. - */ - - class TAGLIB_EXPORT Properties : public AudioProperties - { - public: - /*! - * Create an instance of APE::Properties with the data read from the - * ByteVector \a data. - */ - Properties(File *f, ReadStyle style = Average); - - /*! - * Destroys this APE::Properties instance. - */ - virtual ~Properties(); - - // Reimplementations. - - virtual int length() const; - virtual int bitrate() const; - virtual int sampleRate() const; - virtual int channels() const; - - /*! - * Returns number of bits per sample. - */ - int bitsPerSample() const; - uint sampleFrames() const; - - /*! - * Returns APE version. - */ - int version() const; - - private: - Properties(const Properties &); - Properties &operator=(const Properties &); - - void read(); - - long findDescriptor(); - long findID3v2(); - - void analyzeCurrent(); - void analyzeOld(); - - class PropertiesPrivate; - PropertiesPrivate *d; - }; - } -} - -#endif diff --git a/taglib/taglib/ape/apetag.cpp b/taglib/taglib/ape/apetag.cpp deleted file mode 100644 index 664ee3a..0000000 --- a/taglib/taglib/ape/apetag.cpp +++ /dev/null @@ -1,383 +0,0 @@ -/*************************************************************************** - copyright : (C) 2004 by Allan Sandfeld Jensen - email : kde@carewolf.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/ * - ***************************************************************************/ - -#ifdef __SUNPRO_CC -// Sun Studio finds multiple specializations of Map because -// it considers specializations with and without class types -// to be different; this define forces Map to use only the -// specialization with the class keyword. -#define WANT_CLASS_INSTANTIATION_OF_MAP (1) -#endif - -#include <tfile.h> -#include <tstring.h> -#include <tmap.h> -#include <tpropertymap.h> - -#include "apetag.h" -#include "apefooter.h" -#include "apeitem.h" - -using namespace TagLib; -using namespace APE; - -class APE::Tag::TagPrivate -{ -public: - TagPrivate() : file(0), footerLocation(-1), tagLength(0) {} - - TagLib::File *file; - long footerLocation; - long tagLength; - - Footer footer; - - ItemListMap itemListMap; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public methods -//////////////////////////////////////////////////////////////////////////////// - -APE::Tag::Tag() : TagLib::Tag() -{ - d = new TagPrivate; -} - -APE::Tag::Tag(TagLib::File *file, long footerLocation) : TagLib::Tag() -{ - d = new TagPrivate; - d->file = file; - d->footerLocation = footerLocation; - - read(); -} - -APE::Tag::~Tag() -{ - delete d; -} - -ByteVector APE::Tag::fileIdentifier() -{ - return ByteVector::fromCString("APETAGEX"); -} - -String APE::Tag::title() const -{ - if(d->itemListMap["TITLE"].isEmpty()) - return String::null; - return d->itemListMap["TITLE"].toString(); -} - -String APE::Tag::artist() const -{ - if(d->itemListMap["ARTIST"].isEmpty()) - return String::null; - return d->itemListMap["ARTIST"].toString(); -} - -String APE::Tag::album() const -{ - if(d->itemListMap["ALBUM"].isEmpty()) - return String::null; - return d->itemListMap["ALBUM"].toString(); -} - -String APE::Tag::comment() const -{ - if(d->itemListMap["COMMENT"].isEmpty()) - return String::null; - return d->itemListMap["COMMENT"].toString(); -} - -String APE::Tag::genre() const -{ - if(d->itemListMap["GENRE"].isEmpty()) - return String::null; - return d->itemListMap["GENRE"].toString(); -} - -TagLib::uint APE::Tag::year() const -{ - if(d->itemListMap["YEAR"].isEmpty()) - return 0; - return d->itemListMap["YEAR"].toString().toInt(); -} - -TagLib::uint APE::Tag::track() const -{ - if(d->itemListMap["TRACK"].isEmpty()) - return 0; - return d->itemListMap["TRACK"].toString().toInt(); -} - -void APE::Tag::setTitle(const String &s) -{ - addValue("TITLE", s, true); -} - -void APE::Tag::setArtist(const String &s) -{ - addValue("ARTIST", s, true); -} - -void APE::Tag::setAlbum(const String &s) -{ - addValue("ALBUM", s, true); -} - -void APE::Tag::setComment(const String &s) -{ - addValue("COMMENT", s, true); -} - -void APE::Tag::setGenre(const String &s) -{ - addValue("GENRE", s, true); -} - -void APE::Tag::setYear(uint i) -{ - if(i <= 0) - removeItem("YEAR"); - else - addValue("YEAR", String::number(i), true); -} - -void APE::Tag::setTrack(uint i) -{ - if(i <= 0) - removeItem("TRACK"); - else - addValue("TRACK", String::number(i), true); -} - -// conversions of tag keys between what we use in PropertyMap and what's usual -// for APE tags -static const TagLib::uint keyConversionsSize = 5; //usual, APE -static const char *keyConversions[][2] = {{"TRACKNUMBER", "TRACK" }, - {"DATE", "YEAR" }, - {"ALBUMARTIST", "ALBUM ARTIST"}, - {"DISCNUMBER", "DISC" }, - {"REMIXER", "MIXARTIST" }}; - -PropertyMap APE::Tag::properties() const -{ - PropertyMap properties; - ItemListMap::ConstIterator it = itemListMap().begin(); - for(; it != itemListMap().end(); ++it) { - String tagName = it->first.upper(); - // if the item is Binary or Locator, or if the key is an invalid string, - // add to unsupportedData - if(it->second.type() != Item::Text || tagName.isNull()) - properties.unsupportedData().append(it->first); - else { - // Some tags need to be handled specially - for(uint i = 0; i < keyConversionsSize; ++i) - if(tagName == keyConversions[i][1]) - tagName = keyConversions[i][0]; - properties[tagName].append(it->second.toStringList()); - } - } - return properties; -} - -void APE::Tag::removeUnsupportedProperties(const StringList &properties) -{ - StringList::ConstIterator it = properties.begin(); - for(; it != properties.end(); ++it) - removeItem(*it); -} - -PropertyMap APE::Tag::setProperties(const PropertyMap &origProps) -{ - PropertyMap properties(origProps); // make a local copy that can be modified - - // see comment in properties() - for(uint i = 0; i < keyConversionsSize; ++i) - if(properties.contains(keyConversions[i][0])) { - properties.insert(keyConversions[i][1], properties[keyConversions[i][0]]); - properties.erase(keyConversions[i][0]); - } - - // first check if tags need to be removed completely - StringList toRemove; - ItemListMap::ConstIterator remIt = itemListMap().begin(); - for(; remIt != itemListMap().end(); ++remIt) { - String key = remIt->first.upper(); - // only remove if a) key is valid, b) type is text, c) key not contained in new properties - if(!key.isNull() && remIt->second.type() == APE::Item::Text && !properties.contains(key)) - toRemove.append(remIt->first); - } - - for (StringList::Iterator removeIt = toRemove.begin(); removeIt != toRemove.end(); removeIt++) - removeItem(*removeIt); - - // now sync in the "forward direction" - PropertyMap::ConstIterator it = properties.begin(); - PropertyMap invalid; - for(; it != properties.end(); ++it) { - const String &tagName = it->first; - if(!checkKey(tagName)) - invalid.insert(it->first, it->second); - else if(!(itemListMap().contains(tagName)) || !(itemListMap()[tagName].values() == it->second)) { - if(it->second.size() == 0) - removeItem(tagName); - else { - StringList::ConstIterator valueIt = it->second.begin(); - addValue(tagName, *valueIt, true); - ++valueIt; - for(; valueIt != it->second.end(); ++valueIt) - addValue(tagName, *valueIt, false); - } - } - } - return invalid; -} - -bool APE::Tag::checkKey(const String &key) -{ - if(key.size() < 2 || key.size() > 16) - return false; - for(String::ConstIterator it = key.begin(); it != key.end(); it++) - // only allow printable ASCII including space (32..127) - if (*it < 32 || *it >= 128) - return false; - String upperKey = key.upper(); - if (upperKey=="ID3" || upperKey=="TAG" || upperKey=="OGGS" || upperKey=="MP+") - return false; - return true; -} - -APE::Footer *APE::Tag::footer() const -{ - return &d->footer; -} - -const APE::ItemListMap& APE::Tag::itemListMap() const -{ - return d->itemListMap; -} - -void APE::Tag::removeItem(const String &key) -{ - Map<const String, Item>::Iterator it = d->itemListMap.find(key.upper()); - if(it != d->itemListMap.end()) - d->itemListMap.erase(it); -} - -void APE::Tag::addValue(const String &key, const String &value, bool replace) -{ - if(replace) - removeItem(key); - if(!key.isEmpty() && !value.isEmpty()) { - if(!replace && d->itemListMap.contains(key)) { - // Text items may contain more than one value - if(APE::Item::Text == d->itemListMap.begin()->second.type()) - d->itemListMap[key.upper()].appendValue(value); - // Binary or locator items may have only one value - else - setItem(key, Item(key, value)); - } - else - setItem(key, Item(key, value)); - } -} - -void APE::Tag::setData(const String &key, const ByteVector &value) -{ - removeItem(key); - if(!key.isEmpty() && !value.isEmpty()) - setItem(key, Item(key, value, true)); -} - -void APE::Tag::setItem(const String &key, const Item &item) -{ - if(!key.isEmpty()) - d->itemListMap.insert(key.upper(), item); -} - -bool APE::Tag::isEmpty() const -{ - return d->itemListMap.isEmpty(); -} - -//////////////////////////////////////////////////////////////////////////////// -// protected methods -//////////////////////////////////////////////////////////////////////////////// - -void APE::Tag::read() -{ - if(d->file && d->file->isValid()) { - - d->file->seek(d->footerLocation); - d->footer.setData(d->file->readBlock(Footer::size())); - - if(d->footer.tagSize() <= Footer::size() || - d->footer.tagSize() > uint(d->file->length())) - return; - - d->file->seek(d->footerLocation + Footer::size() - d->footer.tagSize()); - parse(d->file->readBlock(d->footer.tagSize() - Footer::size())); - } -} - -ByteVector APE::Tag::render() const -{ - ByteVector data; - uint itemCount = 0; - - { - for(Map<const String, Item>::ConstIterator it = d->itemListMap.begin(); - it != d->itemListMap.end(); ++it) - { - data.append(it->second.render()); - itemCount++; - } - } - - d->footer.setItemCount(itemCount); - d->footer.setTagSize(data.size() + Footer::size()); - d->footer.setHeaderPresent(true); - - return d->footer.renderHeader() + data + d->footer.renderFooter(); -} - -void APE::Tag::parse(const ByteVector &data) -{ - uint pos = 0; - - // 11 bytes is the minimum size for an APE item - - for(uint i = 0; i < d->footer.itemCount() && pos <= data.size() - 11; i++) { - APE::Item item; - item.parse(data.mid(pos)); - - d->itemListMap.insert(item.key().upper(), item); - - pos += item.size(); - } -} diff --git a/taglib/taglib/ape/apetag.h b/taglib/taglib/ape/apetag.h deleted file mode 100644 index c1f12e2..0000000 --- a/taglib/taglib/ape/apetag.h +++ /dev/null @@ -1,208 +0,0 @@ -/*************************************************************************** - copyright : (C) 2004 by Allan Sandfeld Jensen - email : kde@carewolf.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_APETAG_H -#define TAGLIB_APETAG_H - -#include "tag.h" -#include "tbytevector.h" -#include "tmap.h" -#include "tstring.h" -#include "taglib_export.h" - -#include "apeitem.h" - -namespace TagLib { - - class File; - - //! An implementation of the APE tagging format - - namespace APE { - - class Footer; - - /*! - * A mapping between a list of item names, or keys, and the associated item. - * - * \see APE::Tag::itemListMap() - */ - typedef Map<const String, Item> ItemListMap; - - - //! An APE tag implementation - - class TAGLIB_EXPORT Tag : public TagLib::Tag - { - public: - /*! - * Create an APE tag with default values. - */ - Tag(); - - /*! - * Create an APE tag and parse the data in \a file with APE footer at - * \a tagOffset. - */ - Tag(TagLib::File *file, long footerLocation); - - /*! - * Destroys this Tag instance. - */ - virtual ~Tag(); - - /*! - * Renders the in memory values to a ByteVector suitable for writing to - * the file. - */ - ByteVector render() const; - - /*! - * Returns the string "APETAGEX" suitable for usage in locating the tag in a - * file. - */ - static ByteVector fileIdentifier(); - - // Reimplementations. - - virtual String title() const; - virtual String artist() const; - virtual String album() const; - virtual String comment() const; - virtual String genre() const; - virtual uint year() const; - virtual 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); - - /*! - * Implements the unified tag dictionary interface -- export function. - * APE tags are perfectly compatible with the dictionary interface because they - * support both arbitrary tag names and multiple values. Currently only - * APE items of type *Text* are handled by the dictionary interface; all *Binary* - * and *Locator* items will be put into the unsupportedData list and can be - * deleted on request using removeUnsupportedProperties(). The same happens - * to Text items if their key is invalid for PropertyMap (which should actually - * never happen). - * - * The only conversion done by this export function is to rename the APE tags - * TRACK to TRACKNUMBER, YEAR to DATE, and ALBUM ARTIST to ALBUMARTIST, respectively, - * in order to be compliant with the names used in other formats. - */ - PropertyMap properties() const; - - void removeUnsupportedProperties(const StringList &properties); - - /*! - * Implements the unified tag dictionary interface -- import function. The same - * comments as for the export function apply; additionally note that the APE tag - * specification requires keys to have between 2 and 16 printable ASCII characters - * with the exception of the fixed strings "ID3", "TAG", "OGGS", and "MP+". - */ - PropertyMap setProperties(const PropertyMap &); - - /*! - * Check if the given String is a valid APE tag key. - */ - static bool checkKey(const String&); - - /*! - * Returns a pointer to the tag's footer. - */ - Footer *footer() const; - - /*! - * Returns a reference to the item list map. This is an ItemListMap of - * all of the items in the tag. - * - * This is the most powerfull structure for accessing the items of the tag. - * - * APE tags are case-insensitive, all keys in this map have been converted - * to upper case. - * - * \warning You should not modify this data structure directly, instead - * use setItem() and removeItem(). - */ - const ItemListMap &itemListMap() const; - - /*! - * Removes the \a key item from the tag - */ - void removeItem(const String &key); - - /*! - * Adds to the text item specified by \a key the data \a value. If \a replace - * is true, then all of the other values on the same key will be removed - * first. If a binary item exists for \a key it will be removed first. - */ - void addValue(const String &key, const String &value, bool replace = true); - - /*! - * Set the binary data for the key specified by \a item to \a value - * This will convert the item to type \a Binary if it isn't already and - * all of the other values on the same key will be removed. - */ - void setData(const String &key, const ByteVector &value); - - /*! - * Sets the \a key item to the value of \a item. If an item with the \a key is already - * present, it will be replaced. - */ - void setItem(const String &key, const Item &item); - - /*! - * Returns true if the tag does not contain any data. - */ - bool isEmpty() const; - - protected: - - /*! - * Reads from the file specified in the constructor. - */ - void read(); - - /*! - * Parses the body of the tag in \a data. - */ - void parse(const ByteVector &data); - - private: - Tag(const Tag &); - Tag &operator=(const Tag &); - - class TagPrivate; - TagPrivate *d; - }; - } -} - -#endif diff --git a/taglib/taglib/asf/asfattribute.cpp b/taglib/taglib/asf/asfattribute.cpp deleted file mode 100644 index 4ee2d0a..0000000 --- a/taglib/taglib/asf/asfattribute.cpp +++ /dev/null @@ -1,350 +0,0 @@ -/************************************************************************** - copyright : (C) 2005-2007 by Lukáš Lalinský - email : lalinsky@gmail.com - **************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <taglib.h> -#include <tdebug.h> -#include "trefcounter.h" -#include "asfattribute.h" -#include "asffile.h" - -using namespace TagLib; - -class ASF::Attribute::AttributePrivate : public RefCounter -{ -public: - AttributePrivate() - : pictureValue(ASF::Picture::fromInvalid()), - stream(0), - language(0) {} - AttributeTypes type; - String stringValue; - ByteVector byteVectorValue; - ASF::Picture pictureValue; - union { - unsigned int intValue; - unsigned short shortValue; - unsigned long long longLongValue; - bool boolValue; - }; - int stream; - int language; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -ASF::Attribute::Attribute() -{ - d = new AttributePrivate; - d->type = UnicodeType; -} - -ASF::Attribute::Attribute(const ASF::Attribute &other) - : d(other.d) -{ - d->ref(); -} - -ASF::Attribute &ASF::Attribute::operator=(const ASF::Attribute &other) -{ - if(d->deref()) - delete d; - d = other.d; - d->ref(); - return *this; -} - -ASF::Attribute::~Attribute() -{ - if(d->deref()) - delete d; -} - -ASF::Attribute::Attribute(const String &value) -{ - d = new AttributePrivate; - d->type = UnicodeType; - d->stringValue = value; -} - -ASF::Attribute::Attribute(const ByteVector &value) -{ - d = new AttributePrivate; - d->type = BytesType; - d->byteVectorValue = value; -} - -ASF::Attribute::Attribute(const ASF::Picture &value) -{ - d = new AttributePrivate; - d->type = BytesType; - d->pictureValue = value; -} - -ASF::Attribute::Attribute(unsigned int value) -{ - d = new AttributePrivate; - d->type = DWordType; - d->intValue = value; -} - -ASF::Attribute::Attribute(unsigned long long value) -{ - d = new AttributePrivate; - d->type = QWordType; - d->longLongValue = value; -} - -ASF::Attribute::Attribute(unsigned short value) -{ - d = new AttributePrivate; - d->type = WordType; - d->shortValue = value; -} - -ASF::Attribute::Attribute(bool value) -{ - d = new AttributePrivate; - d->type = BoolType; - d->boolValue = value; -} - -ASF::Attribute::AttributeTypes ASF::Attribute::type() const -{ - return d->type; -} - -String ASF::Attribute::toString() const -{ - return d->stringValue; -} - -ByteVector ASF::Attribute::toByteVector() const -{ - if(d->pictureValue.isValid()) - return d->pictureValue.render(); - return d->byteVectorValue; -} - -unsigned short ASF::Attribute::toBool() const -{ - return d->shortValue; -} - -unsigned short ASF::Attribute::toUShort() const -{ - return d->shortValue; -} - -unsigned int ASF::Attribute::toUInt() const -{ - return d->intValue; -} - -unsigned long long ASF::Attribute::toULongLong() const -{ - return d->longLongValue; -} - -ASF::Picture ASF::Attribute::toPicture() const -{ - return d->pictureValue; -} - -String ASF::Attribute::parse(ASF::File &f, int kind) -{ - uint size, nameLength; - String name; - d->pictureValue = Picture::fromInvalid(); - // extended content descriptor - if(kind == 0) { - nameLength = f.readWORD(); - name = f.readString(nameLength); - d->type = ASF::Attribute::AttributeTypes(f.readWORD()); - size = f.readWORD(); - } - // metadata & metadata library - else { - int temp = f.readWORD(); - // metadata library - if(kind == 2) { - d->language = temp; - } - d->stream = f.readWORD(); - nameLength = f.readWORD(); - d->type = ASF::Attribute::AttributeTypes(f.readWORD()); - size = f.readDWORD(); - name = f.readString(nameLength); - } - - if(kind != 2 && size > 65535) { - debug("ASF::Attribute::parse() -- Value larger than 64kB"); - } - - switch(d->type) { - case WordType: - d->shortValue = f.readWORD(); - break; - - case BoolType: - if(kind == 0) { - d->boolValue = f.readDWORD() == 1; - } - else { - d->boolValue = f.readWORD() == 1; - } - break; - - case DWordType: - d->intValue = f.readDWORD(); - break; - - case QWordType: - d->longLongValue = f.readQWORD(); - break; - - case UnicodeType: - d->stringValue = f.readString(size); - break; - - case BytesType: - case GuidType: - d->byteVectorValue = f.readBlock(size); - break; - } - - if(d->type == BytesType && name == "WM/Picture") { - d->pictureValue.parse(d->byteVectorValue); - if(d->pictureValue.isValid()) { - d->byteVectorValue.clear(); - } - } - - return name; -} - -int ASF::Attribute::dataSize() const -{ - switch (d->type) { - case WordType: - return 2; - case BoolType: - return 4; - case DWordType: - return 4; - case QWordType: - return 5; - case UnicodeType: - return d->stringValue.size() * 2 + 2; - case BytesType: - if(d->pictureValue.isValid()) - return d->pictureValue.dataSize(); - case GuidType: - return d->byteVectorValue.size(); - } - return 0; -} - -ByteVector ASF::Attribute::render(const String &name, int kind) const -{ - ByteVector data; - - switch (d->type) { - case WordType: - data.append(ByteVector::fromShort(d->shortValue, false)); - break; - - case BoolType: - if(kind == 0) { - data.append(ByteVector::fromUInt(d->boolValue ? 1 : 0, false)); - } - else { - data.append(ByteVector::fromShort(d->boolValue ? 1 : 0, false)); - } - break; - - case DWordType: - data.append(ByteVector::fromUInt(d->intValue, false)); - break; - - case QWordType: - data.append(ByteVector::fromLongLong(d->longLongValue, false)); - break; - - case UnicodeType: - data.append(File::renderString(d->stringValue)); - break; - - case BytesType: - if(d->pictureValue.isValid()) { - data.append(d->pictureValue.render()); - break; - } - case GuidType: - data.append(d->byteVectorValue); - break; - } - - if(kind == 0) { - data = File::renderString(name, true) + - ByteVector::fromShort((int)d->type, false) + - ByteVector::fromShort(data.size(), false) + - data; - } - else { - ByteVector nameData = File::renderString(name); - data = ByteVector::fromShort(kind == 2 ? d->language : 0, false) + - ByteVector::fromShort(d->stream, false) + - ByteVector::fromShort(nameData.size(), false) + - ByteVector::fromShort((int)d->type, false) + - ByteVector::fromUInt(data.size(), false) + - nameData + - data; - } - - return data; -} - -int ASF::Attribute::language() const -{ - return d->language; -} - -void ASF::Attribute::setLanguage(int value) -{ - d->language = value; -} - -int ASF::Attribute::stream() const -{ - return d->stream; -} - -void ASF::Attribute::setStream(int value) -{ - d->stream = value; -} - diff --git a/taglib/taglib/asf/asfattribute.h b/taglib/taglib/asf/asfattribute.h deleted file mode 100644 index 54eb0c7..0000000 --- a/taglib/taglib/asf/asfattribute.h +++ /dev/null @@ -1,203 +0,0 @@ -/************************************************************************** - copyright : (C) 2005-2007 by Lukáš Lalinský - email : lalinsky@gmail.com - **************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_ASFATTRIBUTE_H -#define TAGLIB_ASFATTRIBUTE_H - -#include "tstring.h" -#include "tbytevector.h" -#include "taglib_export.h" -#include "asfpicture.h" - -namespace TagLib -{ - - namespace ASF - { - - class File; - class Picture; - - class TAGLIB_EXPORT Attribute - { - public: - - /*! - * Enum of types an Attribute can have. - */ - enum AttributeTypes { - UnicodeType = 0, - BytesType = 1, - BoolType = 2, - DWordType = 3, - QWordType = 4, - WordType = 5, - GuidType = 6 - }; - - /*! - * Constructs an empty attribute. - */ - Attribute(); - - /*! - * Constructs an attribute with \a key and a UnicodeType \a value. - */ - Attribute(const String &value); - - /*! - * Constructs an attribute with \a key and a BytesType \a value. - */ - Attribute(const ByteVector &value); - - /*! - * Constructs an attribute with \a key and a Picture \a value. - * - * This attribute is compatible with the ID3 frame, APIC. The ID3 specification for the APIC frame stipulates that, - * while there may be any number of APIC frames associated with a file, - * only one may be of type 1 and only one may be of type 2. - * - * The specification also states that the description of the picture can be no longer than 64 characters, but can be empty. - * WM/Picture attributes added with TagLib::ASF are not automatically validated to conform to ID3 specifications. - * You must add code in your application to perform validations if you want to maintain complete compatibility with ID3. - */ - Attribute(const Picture &value); - - /*! - * Constructs an attribute with \a key and a DWordType \a value. - */ - Attribute(unsigned int value); - - /*! - * Constructs an attribute with \a key and a QWordType \a value. - */ - Attribute(unsigned long long value); - - /*! - * Constructs an attribute with \a key and a WordType \a value. - */ - Attribute(unsigned short value); - - /*! - * Constructs an attribute with \a key and a BoolType \a value. - */ - Attribute(bool value); - - /*! - * Construct an attribute as a copy of \a other. - */ - Attribute(const Attribute &item); - - /*! - * Copies the contents of \a other into this item. - */ - ASF::Attribute &operator=(const Attribute &other); - - /*! - * Destroys the attribute. - */ - virtual ~Attribute(); - - /*! - * Returns type of the value. - */ - AttributeTypes type() const; - - /*! - * Returns the BoolType \a value. - */ - unsigned short toBool() const; - - /*! - * Returns the WordType \a value. - */ - unsigned short toUShort() const; - - /*! - * Returns the DWordType \a value. - */ - unsigned int toUInt() const; - - /*! - * Returns the QWordType \a value. - */ - unsigned long long toULongLong() const; - - /*! - * Returns the UnicodeType \a value. - */ - String toString() const; - - /*! - * Returns the BytesType \a value. - */ - ByteVector toByteVector() const; - - /*! - * Returns the Picture \a value. - */ - Picture toPicture() const; - - /*! - * Returns the language number, or 0 is no stream number was set. - */ - int language() const; - - /*! - * Sets the language number. - */ - void setLanguage(int value); - - /*! - * Returns the stream number, or 0 is no stream number was set. - */ - int stream() const; - - /*! - * Sets the stream number. - */ - void setStream(int value); - -#ifndef DO_NOT_DOCUMENT - /* THIS IS PRIVATE, DON'T TOUCH IT! */ - String parse(ASF::File &file, int kind = 0); -#endif - - //! Returns the size of the stored data - int dataSize() const; - - private: - friend class File; - - ByteVector render(const String &name, int kind = 0) const; - - class AttributePrivate; - AttributePrivate *d; - }; - } - -} - -#endif diff --git a/taglib/taglib/asf/asffile.cpp b/taglib/taglib/asf/asffile.cpp deleted file mode 100644 index 241998c..0000000 --- a/taglib/taglib/asf/asffile.cpp +++ /dev/null @@ -1,630 +0,0 @@ -/************************************************************************** - copyright : (C) 2005-2007 by Lukáš Lalinský - email : lalinsky@gmail.com - **************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <tdebug.h> -#include <tbytevectorlist.h> -#include <tpropertymap.h> -#include <tstring.h> -#include "asffile.h" -#include "asftag.h" -#include "asfproperties.h" - -using namespace TagLib; - -class ASF::File::FilePrivate -{ -public: - FilePrivate(): - size(0), - tag(0), - properties(0), - contentDescriptionObject(0), - extendedContentDescriptionObject(0), - headerExtensionObject(0), - metadataObject(0), - metadataLibraryObject(0) {} - unsigned long long size; - ASF::Tag *tag; - ASF::Properties *properties; - List<ASF::File::BaseObject *> objects; - ASF::File::ContentDescriptionObject *contentDescriptionObject; - ASF::File::ExtendedContentDescriptionObject *extendedContentDescriptionObject; - ASF::File::HeaderExtensionObject *headerExtensionObject; - ASF::File::MetadataObject *metadataObject; - ASF::File::MetadataLibraryObject *metadataLibraryObject; -}; - -static ByteVector headerGuid("\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16); -static ByteVector filePropertiesGuid("\xA1\xDC\xAB\x8C\x47\xA9\xCF\x11\x8E\xE4\x00\xC0\x0C\x20\x53\x65", 16); -static ByteVector streamPropertiesGuid("\x91\x07\xDC\xB7\xB7\xA9\xCF\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65", 16); -static ByteVector contentDescriptionGuid("\x33\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16); -static ByteVector extendedContentDescriptionGuid("\x40\xA4\xD0\xD2\x07\xE3\xD2\x11\x97\xF0\x00\xA0\xC9\x5E\xA8\x50", 16); -static ByteVector headerExtensionGuid("\xb5\x03\xbf_.\xa9\xcf\x11\x8e\xe3\x00\xc0\x0c Se", 16); -static ByteVector metadataGuid("\xEA\xCB\xF8\xC5\xAF[wH\204g\xAA\214D\xFAL\xCA", 16); -static ByteVector metadataLibraryGuid("\224\034#D\230\224\321I\241A\x1d\x13NEpT", 16); -static ByteVector contentEncryptionGuid("\xFB\xB3\x11\x22\x23\xBD\xD2\x11\xB4\xB7\x00\xA0\xC9\x55\xFC\x6E", 16); -static ByteVector extendedContentEncryptionGuid("\x14\xE6\x8A\x29\x22\x26 \x17\x4C\xB9\x35\xDA\xE0\x7E\xE9\x28\x9C", 16); -static ByteVector advancedContentEncryptionGuid("\xB6\x9B\x07\x7A\xA4\xDA\x12\x4E\xA5\xCA\x91\xD3\x8D\xC1\x1A\x8D", 16); - -class ASF::File::BaseObject -{ -public: - ByteVector data; - virtual ~BaseObject() {} - virtual ByteVector guid() = 0; - virtual void parse(ASF::File *file, unsigned int size); - virtual ByteVector render(ASF::File *file); -}; - -class ASF::File::UnknownObject : public ASF::File::BaseObject -{ - ByteVector myGuid; -public: - UnknownObject(const ByteVector &guid); - ByteVector guid(); -}; - -class ASF::File::FilePropertiesObject : public ASF::File::BaseObject -{ -public: - ByteVector guid(); - void parse(ASF::File *file, uint size); -}; - -class ASF::File::StreamPropertiesObject : public ASF::File::BaseObject -{ -public: - ByteVector guid(); - void parse(ASF::File *file, uint size); -}; - -class ASF::File::ContentDescriptionObject : public ASF::File::BaseObject -{ -public: - ByteVector guid(); - void parse(ASF::File *file, uint size); - ByteVector render(ASF::File *file); -}; - -class ASF::File::ExtendedContentDescriptionObject : public ASF::File::BaseObject -{ -public: - ByteVectorList attributeData; - ByteVector guid(); - void parse(ASF::File *file, uint size); - ByteVector render(ASF::File *file); -}; - -class ASF::File::MetadataObject : public ASF::File::BaseObject -{ -public: - ByteVectorList attributeData; - ByteVector guid(); - void parse(ASF::File *file, uint size); - ByteVector render(ASF::File *file); -}; - -class ASF::File::MetadataLibraryObject : public ASF::File::BaseObject -{ -public: - ByteVectorList attributeData; - ByteVector guid(); - void parse(ASF::File *file, uint size); - ByteVector render(ASF::File *file); -}; - -class ASF::File::HeaderExtensionObject : public ASF::File::BaseObject -{ -public: - List<ASF::File::BaseObject *> objects; - ~HeaderExtensionObject(); - ByteVector guid(); - void parse(ASF::File *file, uint size); - ByteVector render(ASF::File *file); -}; - -ASF::File::HeaderExtensionObject::~HeaderExtensionObject() -{ - for(unsigned int i = 0; i < objects.size(); i++) { - delete objects[i]; - } -} - -void ASF::File::BaseObject::parse(ASF::File *file, unsigned int size) -{ - data.clear(); - if (size > 24 && size <= (unsigned int)(file->length())) - data = file->readBlock(size - 24); - else - data = ByteVector::null; -} - -ByteVector ASF::File::BaseObject::render(ASF::File * /*file*/) -{ - return guid() + ByteVector::fromLongLong(data.size() + 24, false) + data; -} - -ASF::File::UnknownObject::UnknownObject(const ByteVector &guid) : myGuid(guid) -{ -} - -ByteVector ASF::File::UnknownObject::guid() -{ - return myGuid; -} - -ByteVector ASF::File::FilePropertiesObject::guid() -{ - return filePropertiesGuid; -} - -void ASF::File::FilePropertiesObject::parse(ASF::File *file, uint size) -{ - BaseObject::parse(file, size); - file->d->properties->setLength( - (int)(data.toLongLong(40, false) / 10000000L - data.toLongLong(56, false) / 1000L)); -} - -ByteVector ASF::File::StreamPropertiesObject::guid() -{ - return streamPropertiesGuid; -} - -void ASF::File::StreamPropertiesObject::parse(ASF::File *file, uint size) -{ - BaseObject::parse(file, size); - 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() -{ - return contentDescriptionGuid; -} - -void ASF::File::ContentDescriptionObject::parse(ASF::File *file, uint /*size*/) -{ - file->d->contentDescriptionObject = this; - int titleLength = file->readWORD(); - int artistLength = file->readWORD(); - int copyrightLength = file->readWORD(); - int commentLength = file->readWORD(); - int ratingLength = file->readWORD(); - file->d->tag->setTitle(file->readString(titleLength)); - file->d->tag->setArtist(file->readString(artistLength)); - file->d->tag->setCopyright(file->readString(copyrightLength)); - file->d->tag->setComment(file->readString(commentLength)); - file->d->tag->setRating(file->readString(ratingLength)); -} - -ByteVector ASF::File::ContentDescriptionObject::render(ASF::File *file) -{ - ByteVector v1 = file->renderString(file->d->tag->title()); - ByteVector v2 = file->renderString(file->d->tag->artist()); - ByteVector v3 = file->renderString(file->d->tag->copyright()); - ByteVector v4 = file->renderString(file->d->tag->comment()); - ByteVector v5 = file->renderString(file->d->tag->rating()); - data.clear(); - data.append(ByteVector::fromShort(v1.size(), false)); - data.append(ByteVector::fromShort(v2.size(), false)); - data.append(ByteVector::fromShort(v3.size(), false)); - data.append(ByteVector::fromShort(v4.size(), false)); - data.append(ByteVector::fromShort(v5.size(), false)); - data.append(v1); - data.append(v2); - data.append(v3); - data.append(v4); - data.append(v5); - return BaseObject::render(file); -} - -ByteVector ASF::File::ExtendedContentDescriptionObject::guid() -{ - return extendedContentDescriptionGuid; -} - -void ASF::File::ExtendedContentDescriptionObject::parse(ASF::File *file, uint /*size*/) -{ - file->d->extendedContentDescriptionObject = this; - int count = file->readWORD(); - while(count--) { - ASF::Attribute attribute; - String name = attribute.parse(*file); - file->d->tag->addAttribute(name, attribute); - } -} - -ByteVector ASF::File::ExtendedContentDescriptionObject::render(ASF::File *file) -{ - data.clear(); - data.append(ByteVector::fromShort(attributeData.size(), false)); - data.append(attributeData.toByteVector(ByteVector::null)); - return BaseObject::render(file); -} - -ByteVector ASF::File::MetadataObject::guid() -{ - return metadataGuid; -} - -void ASF::File::MetadataObject::parse(ASF::File *file, uint /*size*/) -{ - file->d->metadataObject = this; - int count = file->readWORD(); - while(count--) { - ASF::Attribute attribute; - String name = attribute.parse(*file, 1); - file->d->tag->addAttribute(name, attribute); - } -} - -ByteVector ASF::File::MetadataObject::render(ASF::File *file) -{ - data.clear(); - data.append(ByteVector::fromShort(attributeData.size(), false)); - data.append(attributeData.toByteVector(ByteVector::null)); - return BaseObject::render(file); -} - -ByteVector ASF::File::MetadataLibraryObject::guid() -{ - return metadataLibraryGuid; -} - -void ASF::File::MetadataLibraryObject::parse(ASF::File *file, uint /*size*/) -{ - file->d->metadataLibraryObject = this; - int count = file->readWORD(); - while(count--) { - ASF::Attribute attribute; - String name = attribute.parse(*file, 2); - file->d->tag->addAttribute(name, attribute); - } -} - -ByteVector ASF::File::MetadataLibraryObject::render(ASF::File *file) -{ - data.clear(); - data.append(ByteVector::fromShort(attributeData.size(), false)); - data.append(attributeData.toByteVector(ByteVector::null)); - return BaseObject::render(file); -} - -ByteVector ASF::File::HeaderExtensionObject::guid() -{ - return headerExtensionGuid; -} - -void ASF::File::HeaderExtensionObject::parse(ASF::File *file, uint /*size*/) -{ - file->d->headerExtensionObject = this; - file->seek(18, File::Current); - long long dataSize = file->readDWORD(); - long long dataPos = 0; - while(dataPos < dataSize) { - ByteVector guid = file->readBlock(16); - if(guid.size() != 16) { - file->setValid(false); - break; - } - bool ok; - long long size = file->readQWORD(&ok); - if(!ok) { - file->setValid(false); - break; - } - BaseObject *obj; - if(guid == metadataGuid) { - obj = new MetadataObject(); - } - else if(guid == metadataLibraryGuid) { - obj = new MetadataLibraryObject(); - } - else { - obj = new UnknownObject(guid); - } - obj->parse(file, (unsigned int)size); - objects.append(obj); - dataPos += size; - } -} - -ByteVector ASF::File::HeaderExtensionObject::render(ASF::File *file) -{ - data.clear(); - for(unsigned int i = 0; i < objects.size(); i++) { - data.append(objects[i]->render(file)); - } - data = ByteVector("\x11\xD2\xD3\xAB\xBA\xA9\xcf\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65\x06\x00", 18) + ByteVector::fromUInt(data.size(), false) + data; - return BaseObject::render(file); -} - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -ASF::File::File(FileName file, bool readProperties, Properties::ReadStyle propertiesStyle) - : TagLib::File(file) -{ - d = new FilePrivate; - if(isOpen()) - read(readProperties, propertiesStyle); -} - -ASF::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle propertiesStyle) - : TagLib::File(stream) -{ - d = new FilePrivate; - if(isOpen()) - read(readProperties, propertiesStyle); -} - -ASF::File::~File() -{ - for(unsigned int i = 0; i < d->objects.size(); i++) { - delete d->objects[i]; - } - if(d->tag) { - delete d->tag; - } - if(d->properties) { - delete d->properties; - } - delete d; -} - -ASF::Tag *ASF::File::tag() const -{ - return d->tag; -} - -PropertyMap ASF::File::properties() const -{ - return d->tag->properties(); -} - -void ASF::File::removeUnsupportedProperties(const StringList &properties) -{ - d->tag->removeUnsupportedProperties(properties); -} - -PropertyMap ASF::File::setProperties(const PropertyMap &properties) -{ - return d->tag->setProperties(properties); -} - -ASF::Properties *ASF::File::audioProperties() const -{ - return d->properties; -} - -void ASF::File::read(bool /*readProperties*/, Properties::ReadStyle /*propertiesStyle*/) -{ - if(!isValid()) - return; - - ByteVector guid = readBlock(16); - if(guid != headerGuid) { - debug("ASF: Not an ASF file."); - setValid(false); - return; - } - - d->tag = new ASF::Tag(); - d->properties = new ASF::Properties(); - - bool ok; - d->size = readQWORD(&ok); - if(!ok) { - setValid(false); - return; - } - int numObjects = readDWORD(&ok); - if(!ok) { - setValid(false); - return; - } - seek(2, Current); - - for(int i = 0; i < numObjects; i++) { - ByteVector guid = readBlock(16); - if(guid.size() != 16) { - setValid(false); - break; - } - long size = (long)readQWORD(&ok); - if(!ok) { - setValid(false); - break; - } - BaseObject *obj; - if(guid == filePropertiesGuid) { - obj = new FilePropertiesObject(); - } - else if(guid == streamPropertiesGuid) { - obj = new StreamPropertiesObject(); - } - else if(guid == contentDescriptionGuid) { - obj = new ContentDescriptionObject(); - } - else if(guid == extendedContentDescriptionGuid) { - obj = new ExtendedContentDescriptionObject(); - } - else if(guid == headerExtensionGuid) { - obj = new HeaderExtensionObject(); - } - else { - if(guid == contentEncryptionGuid || - guid == extendedContentEncryptionGuid || - guid == advancedContentEncryptionGuid) { - d->properties->setEncrypted(true); - } - obj = new UnknownObject(guid); - } - obj->parse(this, size); - d->objects.append(obj); - } -} - -bool ASF::File::save() -{ - if(readOnly()) { - debug("ASF::File::save() -- File is read only."); - return false; - } - - if(!isValid()) { - debug("ASF::File::save() -- Trying to save invalid file."); - return false; - } - - if(!d->contentDescriptionObject) { - d->contentDescriptionObject = new ContentDescriptionObject(); - d->objects.append(d->contentDescriptionObject); - } - if(!d->extendedContentDescriptionObject) { - d->extendedContentDescriptionObject = new ExtendedContentDescriptionObject(); - d->objects.append(d->extendedContentDescriptionObject); - } - if(!d->headerExtensionObject) { - d->headerExtensionObject = new HeaderExtensionObject(); - d->objects.append(d->headerExtensionObject); - } - if(!d->metadataObject) { - d->metadataObject = new MetadataObject(); - d->headerExtensionObject->objects.append(d->metadataObject); - } - if(!d->metadataLibraryObject) { - d->metadataLibraryObject = new MetadataLibraryObject(); - d->headerExtensionObject->objects.append(d->metadataLibraryObject); - } - - ASF::AttributeListMap::ConstIterator it = d->tag->attributeListMap().begin(); - for(; it != d->tag->attributeListMap().end(); it++) { - const String &name = it->first; - const AttributeList &attributes = it->second; - bool inExtendedContentDescriptionObject = false; - bool inMetadataObject = false; - for(unsigned int j = 0; j < attributes.size(); j++) { - const Attribute &attribute = attributes[j]; - bool largeValue = attribute.dataSize() > 65535; - if(!inExtendedContentDescriptionObject && !largeValue && attribute.language() == 0 && attribute.stream() == 0) { - d->extendedContentDescriptionObject->attributeData.append(attribute.render(name)); - inExtendedContentDescriptionObject = true; - } - else if(!inMetadataObject && !largeValue && attribute.language() == 0 && attribute.stream() != 0) { - d->metadataObject->attributeData.append(attribute.render(name, 1)); - inMetadataObject = true; - } - else { - d->metadataLibraryObject->attributeData.append(attribute.render(name, 2)); - } - } - } - - ByteVector data; - for(unsigned int i = 0; i < d->objects.size(); i++) { - 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, (TagLib::ulong)d->size); - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// protected members -//////////////////////////////////////////////////////////////////////////////// - -int ASF::File::readBYTE(bool *ok) -{ - ByteVector v = readBlock(1); - if(v.size() != 1) { - if(ok) *ok = false; - return 0; - } - if(ok) *ok = true; - return v[0]; -} - -int ASF::File::readWORD(bool *ok) -{ - ByteVector v = readBlock(2); - if(v.size() != 2) { - if(ok) *ok = false; - return 0; - } - if(ok) *ok = true; - return v.toUShort(false); -} - -unsigned int ASF::File::readDWORD(bool *ok) -{ - ByteVector v = readBlock(4); - if(v.size() != 4) { - if(ok) *ok = false; - return 0; - } - if(ok) *ok = true; - return v.toUInt(false); -} - -long long ASF::File::readQWORD(bool *ok) -{ - ByteVector v = readBlock(8); - if(v.size() != 8) { - if(ok) *ok = false; - return 0; - } - if(ok) *ok = true; - return v.toLongLong(false); -} - -String ASF::File::readString(int length) -{ - ByteVector data = readBlock(length); - unsigned int size = data.size(); - while (size >= 2) { - if(data[size - 1] != '\0' || data[size - 2] != '\0') { - break; - } - size -= 2; - } - if(size != data.size()) { - data.resize(size); - } - return String(data, String::UTF16LE); -} - -ByteVector ASF::File::renderString(const String &str, bool includeLength) -{ - ByteVector data = str.data(String::UTF16LE) + ByteVector::fromShort(0, false); - if(includeLength) { - data = ByteVector::fromShort(data.size(), false) + data; - } - return data; -} - diff --git a/taglib/taglib/asf/asffile.h b/taglib/taglib/asf/asffile.h deleted file mode 100644 index 5ccf2fd..0000000 --- a/taglib/taglib/asf/asffile.h +++ /dev/null @@ -1,148 +0,0 @@ -/************************************************************************** - copyright : (C) 2005-2007 by Lukáš Lalinský - email : lalinsky@gmail.com - **************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_ASFFILE_H -#define TAGLIB_ASFFILE_H - -#include "tag.h" -#include "tfile.h" -#include "taglib_export.h" -#include "asfproperties.h" -#include "asftag.h" - -namespace TagLib { - - //! An implementation of ASF (WMA) metadata - namespace ASF { - - /*! - * This implements and provides an interface for ASF files to the - * TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing - * the abstract TagLib::File API as well as providing some additional - * information specific to ASF files. - */ - class TAGLIB_EXPORT File : public TagLib::File - { - public: - - /*! - * Constructs an ASF 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, - Properties::ReadStyle propertiesStyle = Properties::Average); - - /*! - * Constructs an ASF 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, - Properties::ReadStyle propertiesStyle = Properties::Average); - - /*! - * Destroys this instance of the File. - */ - virtual ~File(); - - /*! - * Returns a pointer to the ASF tag of the file. - * - * ASF::Tag implements the tag interface, so this serves as the - * reimplementation of TagLib::File::tag(). - * - * \note The Tag <b>is still</b> owned by the ASF::File and should not be - * deleted by the user. It will be deleted when the file (object) is - * destroyed. - */ - virtual Tag *tag() const; - - /*! - * Implements the unified property interface -- export function. - */ - PropertyMap properties() const; - - /*! - * Removes unsupported properties. Forwards to the actual Tag's - * removeUnsupportedProperties() function. - */ - void removeUnsupportedProperties(const StringList &properties); - - /*! - * Implements the unified property interface -- import function. - */ - PropertyMap setProperties(const PropertyMap &); - - /*! - * Returns the ASF audio properties for this file. - */ - virtual Properties *audioProperties() const; - - /*! - * Save the file. - * - * This returns true if the save was successful. - */ - virtual bool save(); - - private: - int readBYTE(bool *ok = 0); - int readWORD(bool *ok = 0); - unsigned int readDWORD(bool *ok = 0); - long long readQWORD(bool *ok = 0); - static ByteVector renderString(const String &str, bool includeLength = false); - String readString(int len); - void read(bool readProperties, Properties::ReadStyle propertiesStyle); - - friend class Attribute; - friend class Picture; - - class BaseObject; - class UnknownObject; - class FilePropertiesObject; - class StreamPropertiesObject; - class ContentDescriptionObject; - class ExtendedContentDescriptionObject; - class HeaderExtensionObject; - class MetadataObject; - class MetadataLibraryObject; - - class FilePrivate; - FilePrivate *d; - }; - - } - -} - -#endif diff --git a/taglib/taglib/asf/asfpicture.cpp b/taglib/taglib/asf/asfpicture.cpp deleted file mode 100644 index 999f920..0000000 --- a/taglib/taglib/asf/asfpicture.cpp +++ /dev/null @@ -1,179 +0,0 @@ -/************************************************************************** - copyright : (C) 2010 by Anton Sergunov - email : setosha@gmail.com - **************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <taglib.h> -#include <tdebug.h> -#include "trefcounter.h" -#include "asfattribute.h" -#include "asffile.h" -#include "asfpicture.h" - -using namespace TagLib; - -class ASF::Picture::PicturePrivate : public RefCounter -{ -public: - bool valid; - Type type; - String mimeType; - String description; - ByteVector picture; -}; - -//////////////////////////////////////////////////////////////////////////////// -// Picture class members -//////////////////////////////////////////////////////////////////////////////// - -ASF::Picture::Picture() -{ - d = new PicturePrivate(); - d->valid = true; -} - -ASF::Picture::Picture(const Picture& other) - : d(other.d) -{ - d->ref(); -} - -ASF::Picture::~Picture() -{ - if(d->deref()) - delete d; -} - -bool ASF::Picture::isValid() const -{ - return d->valid; -} - -String ASF::Picture::mimeType() const -{ - return d->mimeType; -} - -void ASF::Picture::setMimeType(const String &value) -{ - d->mimeType = value; -} - -ASF::Picture::Type ASF::Picture::type() const -{ - return d->type; -} - -void ASF::Picture::setType(const ASF::Picture::Type& t) -{ - d->type = t; -} - -String ASF::Picture::description() const -{ - return d->description; -} - -void ASF::Picture::setDescription(const String &desc) -{ - d->description = desc; -} - -ByteVector ASF::Picture::picture() const -{ - return d->picture; -} - -void ASF::Picture::setPicture(const ByteVector &p) -{ - d->picture = p; -} - -int ASF::Picture::dataSize() const -{ - return - 9 + (d->mimeType.length() + d->description.length()) * 2 + - d->picture.size(); -} - -ASF::Picture& ASF::Picture::operator=(const ASF::Picture& other) -{ - if(other.d != d) { - if(d->deref()) - delete d; - d = other.d; - d->ref(); - } - return *this; -} - -ByteVector ASF::Picture::render() const -{ - if(!isValid()) - return ByteVector::null; - return - ByteVector((char)d->type) + - ByteVector::fromUInt(d->picture.size(), false) + - ASF::File::renderString(d->mimeType) + - ASF::File::renderString(d->description) + - d->picture; -} - -void ASF::Picture::parse(const ByteVector& bytes) -{ - d->valid = false; - if(bytes.size() < 9) - return; - int pos = 0; - d->type = (Type)bytes[0]; ++pos; - const uint dataLen = bytes.toUInt(pos, false); pos+=4; - - const ByteVector nullStringTerminator(2, 0); - - int endPos = bytes.find(nullStringTerminator, pos, 2); - if(endPos < 0) - return; - d->mimeType = String(bytes.mid(pos, endPos - pos), String::UTF16LE); - pos = endPos+2; - - endPos = bytes.find(nullStringTerminator, pos, 2); - if(endPos < 0) - return; - d->description = String(bytes.mid(pos, endPos - pos), String::UTF16LE); - pos = endPos+2; - - if(dataLen + pos != bytes.size()) - return; - - d->picture = bytes.mid(pos, dataLen); - d->valid = true; - return; -} - -ASF::Picture ASF::Picture::fromInvalid() -{ - Picture ret; - ret.d->valid = false; - return ret; -} - diff --git a/taglib/taglib/asf/asfpicture.h b/taglib/taglib/asf/asfpicture.h deleted file mode 100644 index aa0a060..0000000 --- a/taglib/taglib/asf/asfpicture.h +++ /dev/null @@ -1,217 +0,0 @@ -/************************************************************************** - copyright : (C) 2010 by Anton Sergunov - email : setosha@gmail.com - **************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef ASFPICTURE_H -#define ASFPICTURE_H - -#include "tstring.h" -#include "tbytevector.h" -#include "taglib_export.h" -#include "attachedpictureframe.h" - -namespace TagLib -{ - namespace ASF - { - - //! An ASF attached picture interface implementation - - /*! - * This is an implementation of ASF attached pictures interface. Pictures may be - * included in attributes, one per WM/Picture attribute (but there may be multiple WM/Picture - * attribute in a single tag). These pictures are usually in either JPEG or - * PNG format. - * \see Attribute::toPicture() - * \see Attribute::Attribute(const Picture& picture) - */ - class TAGLIB_EXPORT Picture { - public: - - /*! - * This describes the function or content of the picture. - */ - enum Type { - //! A type not enumerated below - Other = 0x00, - //! 32x32 PNG image that should be used as the file icon - FileIcon = 0x01, - //! File icon of a different size or format - OtherFileIcon = 0x02, - //! Front cover image of the album - FrontCover = 0x03, - //! Back cover image of the album - BackCover = 0x04, - //! Inside leaflet page of the album - LeafletPage = 0x05, - //! Image from the album itself - Media = 0x06, - //! Picture of the lead artist or soloist - LeadArtist = 0x07, - //! Picture of the artist or performer - Artist = 0x08, - //! Picture of the conductor - Conductor = 0x09, - //! Picture of the band or orchestra - Band = 0x0A, - //! Picture of the composer - Composer = 0x0B, - //! Picture of the lyricist or text writer - Lyricist = 0x0C, - //! Picture of the recording location or studio - RecordingLocation = 0x0D, - //! Picture of the artists during recording - DuringRecording = 0x0E, - //! Picture of the artists during performance - DuringPerformance = 0x0F, - //! Picture from a movie or video related to the track - MovieScreenCapture = 0x10, - //! Picture of a large, coloured fish - ColouredFish = 0x11, - //! Illustration related to the track - Illustration = 0x12, - //! Logo of the band or performer - BandLogo = 0x13, - //! Logo of the publisher (record company) - PublisherLogo = 0x14 - }; - - /*! - * Constructs an empty picture. - */ - Picture(); - - /*! - * Construct an picture as a copy of \a other. - */ - Picture(const Picture& other); - - /*! - * Destroys the picture. - */ - virtual ~Picture(); - - /*! - * Copies the contents of \a other into this picture. - */ - Picture& operator=(const Picture& other); - - /*! - * Returns true if Picture stores valid picture - */ - bool isValid() const; - - /*! - * Returns the mime type of the image. This should in most cases be - * "image/png" or "image/jpeg". - * \see setMimeType(const String &) - * \see picture() - * \see setPicture(const ByteArray&) - */ - String mimeType() const; - - /*! - * Sets the mime type of the image. This should in most cases be - * "image/png" or "image/jpeg". - * \see setMimeType(const String &) - * \see picture() - * \see setPicture(const ByteArray&) - */ - void setMimeType(const String &value); - - /*! - * Returns the type of the image. - * - * \see Type - * \see setType() - */ - Type type() const; - - /*! - * Sets the type for the image. - * - * \see Type - * \see type() - */ - void setType(const ASF::Picture::Type& t); - - /*! - * Returns a text description of the image. - * - * \see setDescription() - */ - String description() const; - - /*! - * Sets a textual description of the image to \a desc. - * - * \see description() - */ - void setDescription(const String &desc); - - /*! - * Returns the image data as a ByteVector. - * - * \note ByteVector has a data() method that returns a const char * which - * should make it easy to export this data to external programs. - * - * \see setPicture() - * \see mimeType() - */ - ByteVector picture() const; - - /*! - * Sets the image data to \a p. \a p should be of the type specified in - * this frame's mime-type specification. - * - * \see picture() - * \see mimeType() - * \see setMimeType() - */ - void setPicture(const ByteVector &p); - - /*! - * Returns picture as binary raw data \a value - */ - ByteVector render() const; - - /*! - * Returns picture as binary raw data \a value - */ - int dataSize() const; - -#ifndef DO_NOT_DOCUMENT - /* THIS IS PRIVATE, DON'T TOUCH IT! */ - void parse(const ByteVector& ); - static Picture fromInvalid(); - friend class Attribute; -#endif - private: - class PicturePrivate; - PicturePrivate *d; - }; - } -} - -#endif // ASFPICTURE_H diff --git a/taglib/taglib/asf/asfproperties.cpp b/taglib/taglib/asf/asfproperties.cpp deleted file mode 100644 index b82c131..0000000 --- a/taglib/taglib/asf/asfproperties.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/************************************************************************** - copyright : (C) 2005-2007 by Lukáš Lalinský - email : lalinsky@gmail.com - **************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <tdebug.h> -#include <tstring.h> -#include "asfproperties.h" - -using namespace TagLib; - -class ASF::Properties::PropertiesPrivate -{ -public: - PropertiesPrivate(): length(0), bitrate(0), sampleRate(0), channels(0), encrypted(false) {} - int length; - int bitrate; - int sampleRate; - int channels; - bool encrypted; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -ASF::Properties::Properties() : AudioProperties(AudioProperties::Average) -{ - d = new PropertiesPrivate; -} - -ASF::Properties::~Properties() -{ - if(d) - delete d; -} - -int ASF::Properties::length() const -{ - return d->length; -} - -int ASF::Properties::bitrate() const -{ - return d->bitrate; -} - -int ASF::Properties::sampleRate() const -{ - return d->sampleRate; -} - -int ASF::Properties::channels() const -{ - return d->channels; -} - -bool ASF::Properties::isEncrypted() const -{ - return d->encrypted; -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -void ASF::Properties::setLength(int length) -{ - d->length = length; -} - -void ASF::Properties::setBitrate(int length) -{ - d->bitrate = length; -} - -void ASF::Properties::setSampleRate(int length) -{ - d->sampleRate = length; -} - -void ASF::Properties::setChannels(int length) -{ - d->channels = length; -} - -void ASF::Properties::setEncrypted(bool encrypted) -{ - d->encrypted = encrypted; -} - diff --git a/taglib/taglib/asf/asfproperties.h b/taglib/taglib/asf/asfproperties.h deleted file mode 100644 index 95730d8..0000000 --- a/taglib/taglib/asf/asfproperties.h +++ /dev/null @@ -1,76 +0,0 @@ -/************************************************************************** - copyright : (C) 2005-2007 by Lukáš Lalinský - email : lalinsky@gmail.com - **************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_ASFPROPERTIES_H -#define TAGLIB_ASFPROPERTIES_H - -#include "audioproperties.h" -#include "tstring.h" -#include "taglib_export.h" - -namespace TagLib { - - namespace ASF { - - //! An implementation of ASF audio properties - class TAGLIB_EXPORT Properties : public AudioProperties - { - public: - - /*! - * Create an instance of ASF::Properties. - */ - Properties(); - - /*! - * Destroys this ASF::Properties instance. - */ - virtual ~Properties(); - - // Reimplementations. - virtual int length() const; - virtual int bitrate() const; - virtual int sampleRate() const; - virtual int channels() const; - bool isEncrypted() const; - -#ifndef DO_NOT_DOCUMENT - void setLength(int value); - void setBitrate(int value); - void setSampleRate(int value); - void setChannels(int value); - void setEncrypted(bool value); -#endif - - private: - class PropertiesPrivate; - PropertiesPrivate *d; - }; - - } - -} - -#endif diff --git a/taglib/taglib/asf/asftag.cpp b/taglib/taglib/asf/asftag.cpp deleted file mode 100644 index c07abe9..0000000 --- a/taglib/taglib/asf/asftag.cpp +++ /dev/null @@ -1,354 +0,0 @@ -/************************************************************************** - copyright : (C) 2005-2007 by Lukáš Lalinský - email : lalinsky@gmail.com - **************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <tpropertymap.h> -#include "asftag.h" - -using namespace TagLib; - -class ASF::Tag::TagPrivate -{ -public: - String title; - String artist; - String copyright; - String comment; - String rating; - AttributeListMap attributeListMap; -}; - -ASF::Tag::Tag() -: TagLib::Tag() -{ - d = new TagPrivate; -} - -ASF::Tag::~Tag() -{ - if(d) - delete d; -} - -String ASF::Tag::title() const -{ - return d->title; -} - -String ASF::Tag::artist() const -{ - return d->artist; -} - -String ASF::Tag::album() const -{ - if(d->attributeListMap.contains("WM/AlbumTitle")) - return d->attributeListMap["WM/AlbumTitle"][0].toString(); - return String::null; -} - -String ASF::Tag::copyright() const -{ - return d->copyright; -} - -String ASF::Tag::comment() const -{ - return d->comment; -} - -String ASF::Tag::rating() const -{ - return d->rating; -} - -unsigned int ASF::Tag::year() const -{ - if(d->attributeListMap.contains("WM/Year")) - return d->attributeListMap["WM/Year"][0].toString().toInt(); - return 0; -} - -unsigned int ASF::Tag::track() const -{ - if(d->attributeListMap.contains("WM/TrackNumber")) { - const ASF::Attribute attr = d->attributeListMap["WM/TrackNumber"][0]; - if(attr.type() == ASF::Attribute::DWordType) - return attr.toUInt(); - else - return attr.toString().toInt(); - } - if(d->attributeListMap.contains("WM/Track")) - return d->attributeListMap["WM/Track"][0].toUInt(); - return 0; -} - -String ASF::Tag::genre() const -{ - if(d->attributeListMap.contains("WM/Genre")) - return d->attributeListMap["WM/Genre"][0].toString(); - return String::null; -} - -void ASF::Tag::setTitle(const String &value) -{ - d->title = value; -} - -void ASF::Tag::setArtist(const String &value) -{ - d->artist = value; -} - -void ASF::Tag::setCopyright(const String &value) -{ - d->copyright = value; -} - -void ASF::Tag::setComment(const String &value) -{ - d->comment = value; -} - -void ASF::Tag::setRating(const String &value) -{ - d->rating = value; -} - -void ASF::Tag::setAlbum(const String &value) -{ - setAttribute("WM/AlbumTitle", value); -} - -void ASF::Tag::setGenre(const String &value) -{ - setAttribute("WM/Genre", value); -} - -void ASF::Tag::setYear(uint value) -{ - setAttribute("WM/Year", String::number(value)); -} - -void ASF::Tag::setTrack(uint value) -{ - setAttribute("WM/TrackNumber", String::number(value)); -} - -ASF::AttributeListMap& ASF::Tag::attributeListMap() -{ - return d->attributeListMap; -} - -void ASF::Tag::removeItem(const String &key) -{ - AttributeListMap::Iterator it = d->attributeListMap.find(key); - if(it != d->attributeListMap.end()) - d->attributeListMap.erase(it); -} - -void ASF::Tag::setAttribute(const String &name, const Attribute &attribute) -{ - AttributeList value; - value.append(attribute); - d->attributeListMap.insert(name, value); -} - -void ASF::Tag::addAttribute(const String &name, const Attribute &attribute) -{ - if(d->attributeListMap.contains(name)) { - d->attributeListMap[name].append(attribute); - } - else { - setAttribute(name, attribute); - } -} - -bool ASF::Tag::isEmpty() const -{ - return TagLib::Tag::isEmpty() && - copyright().isEmpty() && - rating().isEmpty() && - 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; -} diff --git a/taglib/taglib/asf/asftag.h b/taglib/taglib/asf/asftag.h deleted file mode 100644 index f68579d..0000000 --- a/taglib/taglib/asf/asftag.h +++ /dev/null @@ -1,190 +0,0 @@ -/************************************************************************** - copyright : (C) 2005-2007 by Lukáš Lalinský - email : lalinsky@gmail.com - **************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_ASFTAG_H -#define TAGLIB_ASFTAG_H - -#include "tag.h" -#include "tlist.h" -#include "tmap.h" -#include "taglib_export.h" -#include "asfattribute.h" - -namespace TagLib { - - namespace ASF { - - typedef List<Attribute> AttributeList; - typedef Map<String, AttributeList> AttributeListMap; - - class TAGLIB_EXPORT Tag : public TagLib::Tag { - - friend class File; - - public: - - Tag(); - - virtual ~Tag(); - - /*! - * Returns the track name. - */ - virtual String title() const; - - /*! - * Returns the artist name. - */ - virtual String artist() const; - - /*! - * Returns the album name; if no album name is present in the tag - * String::null will be returned. - */ - virtual String album() const; - - /*! - * Returns the track comment. - */ - virtual String comment() const; - - /*! - * Returns the genre name; if no genre is present in the tag String::null - * will be returned. - */ - virtual String genre() const; - - /*! - * Returns the rating. - */ - virtual String rating() const; - - /*! - * Returns the genre name; if no genre is present in the tag String::null - * will be returned. - */ - virtual String copyright() const; - - /*! - * Returns the year; if there is no year set, this will return 0. - */ - virtual uint year() const; - - /*! - * Returns the track number; if there is no track number set, this will - * return 0. - */ - virtual uint track() const; - - /*! - * Sets the title to \a s. - */ - virtual void setTitle(const String &s); - - /*! - * Sets the artist to \a s. - */ - virtual void setArtist(const String &s); - - /*! - * Sets the album to \a s. If \a s is String::null then this value will be - * cleared. - */ - virtual void setAlbum(const String &s); - - /*! - * Sets the comment to \a s. - */ - virtual void setComment(const String &s); - - /*! - * Sets the rating to \a s. - */ - virtual void setRating(const String &s); - - /*! - * Sets the copyright to \a s. - */ - virtual void setCopyright(const String &s); - - /*! - * Sets the genre to \a s. - */ - virtual void setGenre(const String &s); - - /*! - * Sets the year to \a i. If \a s is 0 then this value will be cleared. - */ - virtual void setYear(uint i); - - /*! - * Sets the track to \a i. If \a s is 0 then this value will be cleared. - */ - virtual void setTrack(uint i); - - /*! - * Returns true if the tag does not contain any data. This should be - * reimplemented in subclasses that provide more than the basic tagging - * abilities in this class. - */ - virtual bool isEmpty() const; - - /*! - * Returns a reference to the item list map. This is an AttributeListMap of - * all of the items in the tag. - * - * This is the most powerfull structure for accessing the items of the tag. - */ - AttributeListMap &attributeListMap(); - - /*! - * Removes the \a key attribute from the tag - */ - void removeItem(const String &name); - - /*! - * Sets the \a key attribute to the value of \a attribute. If an attribute - * with the \a key is already present, it will be replaced. - */ - void setAttribute(const String &name, const Attribute &attribute); - - /*! - * Sets the \a key attribute to the value of \a attribute. If an attribute - * with the \a key is already present, it will be added to the list. - */ - void addAttribute(const String &name, const Attribute &attribute); - - PropertyMap properties() const; - void removeUnsupportedProperties(const StringList& properties); - PropertyMap setProperties(const PropertyMap &properties); - - private: - - class TagPrivate; - TagPrivate *d; - }; - } -} -#endif diff --git a/taglib/taglib/audioproperties.cpp b/taglib/taglib/audioproperties.cpp deleted file mode 100644 index 298b97d..0000000 --- a/taglib/taglib/audioproperties.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include "audioproperties.h" - -using namespace TagLib; - -class AudioProperties::AudioPropertiesPrivate -{ - -}; - -//////////////////////////////////////////////////////////////////////////////// -// public methods -//////////////////////////////////////////////////////////////////////////////// - -AudioProperties::~AudioProperties() -{ - -} - -//////////////////////////////////////////////////////////////////////////////// -// protected methods -//////////////////////////////////////////////////////////////////////////////// - -AudioProperties::AudioProperties(ReadStyle) -{ - -} diff --git a/taglib/taglib/audioproperties.h b/taglib/taglib/audioproperties.h deleted file mode 100644 index e9844fa..0000000 --- a/taglib/taglib/audioproperties.h +++ /dev/null @@ -1,110 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_AUDIOPROPERTIES_H -#define TAGLIB_AUDIOPROPERTIES_H - -#include "taglib_export.h" - -namespace TagLib { - - //! A simple, abstract interface to common audio properties - - /*! - * The values here are common to most audio formats. For more specific, codec - * dependant values, please see see the subclasses APIs. This is meant to - * compliment the TagLib::File and TagLib::Tag APIs in providing a simple - * interface that is sufficient for most applications. - */ - - class TAGLIB_EXPORT AudioProperties - { - public: - - /*! - * Reading audio properties from a file can sometimes be very time consuming - * and for the most accurate results can often involve reading the entire - * file. Because in many situations speed is critical or the accuracy of the - * values is not particularly important this allows the level of desired - * accuracy to be set. - */ - enum ReadStyle { - //! Read as little of the file as possible - Fast, - //! Read more of the file and make better values guesses - Average, - //! Read as much of the file as needed to report accurate values - Accurate - }; - - /*! - * Destroys this AudioProperties instance. - */ - virtual ~AudioProperties(); - - /*! - * Returns the length of the file in seconds. - */ - virtual int length() const = 0; - - /*! - * Returns the most appropriate bit rate for the file in kb/s. For constant - * bitrate formats this is simply the bitrate of the file. For variable - * bitrate formats this is either the average or nominal bitrate. - */ - virtual int bitrate() const = 0; - - /*! - * Returns the sample rate in Hz. - */ - virtual int sampleRate() const = 0; - - /*! - * Returns the number of audio channels. - */ - virtual int channels() const = 0; - - protected: - - /*! - * Construct an audio properties instance. This is protected as this class - * should not be instantiated directly, but should be instantiated via its - * subclasses and can be fetched from the FileRef or File APIs. - * - * \see ReadStyle - */ - AudioProperties(ReadStyle style); - - private: - AudioProperties(const AudioProperties &); - AudioProperties &operator=(const AudioProperties &); - - class AudioPropertiesPrivate; - AudioPropertiesPrivate *d; - }; - -} - -#endif diff --git a/taglib/taglib/fileref.cpp b/taglib/taglib/fileref.cpp deleted file mode 100644 index 4403a5f..0000000 --- a/taglib/taglib/fileref.cpp +++ /dev/null @@ -1,286 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - - copyright : (C) 2010 by Alex Novichkov - email : novichko@atnet.ru - (added APE file support) - ***************************************************************************/ - -/*************************************************************************** - * 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 <tfile.h> -#include <tstring.h> -#include <tdebug.h> -#include "trefcounter.h" - -#include "fileref.h" -#include "asffile.h" -#include "mpegfile.h" -#include "vorbisfile.h" -#include "flacfile.h" -#include "oggflacfile.h" -#include "mpcfile.h" -#include "mp4file.h" -#include "wavpackfile.h" -#include "speexfile.h" -#include "opusfile.h" -#include "trueaudiofile.h" -#include "aifffile.h" -#include "wavfile.h" -#include "apefile.h" -#include "modfile.h" -#include "s3mfile.h" -#include "itfile.h" -#include "xmfile.h" - -using namespace TagLib; - -class FileRef::FileRefPrivate : public RefCounter -{ -public: - FileRefPrivate(File *f) : RefCounter(), file(f) {} - ~FileRefPrivate() { - delete file; - } - - File *file; - static List<const FileTypeResolver *> fileTypeResolvers; -}; - -List<const FileRef::FileTypeResolver *> FileRef::FileRefPrivate::fileTypeResolvers; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -FileRef::FileRef() -{ - d = new FileRefPrivate(0); -} - -FileRef::FileRef(FileName fileName, bool readAudioProperties, - AudioProperties::ReadStyle audioPropertiesStyle) -{ - d = new FileRefPrivate(create(fileName, readAudioProperties, audioPropertiesStyle)); -} - -FileRef::FileRef(File *file) -{ - d = new FileRefPrivate(file); -} - -FileRef::FileRef(const FileRef &ref) : d(ref.d) -{ - d->ref(); -} - -FileRef::~FileRef() -{ - if(d->deref()) - delete d; -} - -Tag *FileRef::tag() const -{ - if(isNull()) { - debug("FileRef::tag() - Called without a valid file."); - return 0; - } - return d->file->tag(); -} - -AudioProperties *FileRef::audioProperties() const -{ - if(isNull()) { - debug("FileRef::audioProperties() - Called without a valid file."); - return 0; - } - return d->file->audioProperties(); -} - -File *FileRef::file() const -{ - return d->file; -} - -bool FileRef::save() -{ - if(isNull()) { - debug("FileRef::save() - Called without a valid file."); - return false; - } - return d->file->save(); -} - -const FileRef::FileTypeResolver *FileRef::addFileTypeResolver(const FileRef::FileTypeResolver *resolver) // static -{ - FileRefPrivate::fileTypeResolvers.prepend(resolver); - return resolver; -} - -StringList FileRef::defaultFileExtensions() -{ - StringList l; - - l.append("ogg"); - l.append("flac"); - l.append("oga"); - l.append("mp3"); - l.append("mpc"); - l.append("wv"); - l.append("spx"); - l.append("tta"); - l.append("m4a"); - l.append("m4r"); - l.append("m4b"); - l.append("m4p"); - l.append("3g2"); - l.append("mp4"); - l.append("wma"); - l.append("asf"); - l.append("aif"); - l.append("aiff"); - l.append("wav"); - l.append("ape"); - l.append("mod"); - l.append("module"); // alias for "mod" - l.append("nst"); // alias for "mod" - l.append("wow"); // alias for "mod" - l.append("s3m"); - l.append("it"); - l.append("xm"); - - return l; -} - -bool FileRef::isNull() const -{ - return !d->file || !d->file->isValid(); -} - -FileRef &FileRef::operator=(const FileRef &ref) -{ - if(&ref == this) - return *this; - - if(d->deref()) - delete d; - - d = ref.d; - d->ref(); - - return *this; -} - -bool FileRef::operator==(const FileRef &ref) const -{ - return ref.d->file == d->file; -} - -bool FileRef::operator!=(const FileRef &ref) const -{ - return ref.d->file != d->file; -} - -File *FileRef::create(FileName fileName, bool readAudioProperties, - AudioProperties::ReadStyle audioPropertiesStyle) // static -{ - - List<const FileTypeResolver *>::ConstIterator it = FileRefPrivate::fileTypeResolvers.begin(); - - for(; it != FileRefPrivate::fileTypeResolvers.end(); ++it) { - File *file = (*it)->createFile(fileName, readAudioProperties, audioPropertiesStyle); - if(file) - return file; - } - - // Ok, this is really dumb for now, but it works for testing. - - String ext; - { -#ifdef _WIN32 - - String s = fileName.toString(); - -#else - - 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. - - if(!ext.isEmpty()) { - if(ext == "MP3") - return new MPEG::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "OGG") - return new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "OGA") { - /* .oga can be any audio in the Ogg container. First try FLAC, then Vorbis. */ - File *file = new Ogg::FLAC::File(fileName, readAudioProperties, audioPropertiesStyle); - if (file->isValid()) - return file; - delete file; - return new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle); - } - if(ext == "FLAC") - return new FLAC::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "MPC") - return new MPC::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "WV") - return new WavPack::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "SPX") - return new Ogg::Speex::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "OPUS") - return new Ogg::Opus::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "TTA") - return new TrueAudio::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "M4A" || ext == "M4R" || ext == "M4B" || ext == "M4P" || ext == "MP4" || ext == "3G2") - return new MP4::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "WMA" || ext == "ASF") - return new ASF::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "AIF" || ext == "AIFF") - return new RIFF::AIFF::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "WAV") - return new RIFF::WAV::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "APE") - return new APE::File(fileName, readAudioProperties, audioPropertiesStyle); - // module, nst and wow are possible but uncommon extensions - if(ext == "MOD" || ext == "MODULE" || ext == "NST" || ext == "WOW") - return new Mod::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "S3M") - return new S3M::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "IT") - return new IT::File(fileName, readAudioProperties, audioPropertiesStyle); - if(ext == "XM") - return new XM::File(fileName, readAudioProperties, audioPropertiesStyle); - } - - return 0; -} diff --git a/taglib/taglib/fileref.h b/taglib/taglib/fileref.h deleted file mode 100644 index 0f0c21a..0000000 --- a/taglib/taglib/fileref.h +++ /dev/null @@ -1,263 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_FILEREF_H -#define TAGLIB_FILEREF_H - -#include "tfile.h" -#include "tstringlist.h" - -#include "taglib_export.h" -#include "audioproperties.h" - -namespace TagLib { - - class Tag; - - //! This class provides a simple abstraction for creating and handling files - - /*! - * FileRef exists to provide a minimal, generic and value-based wrapper around - * a File. It is lightweight and implicitly shared, and as such suitable for - * pass-by-value use. This hides some of the uglier details of TagLib::File - * and the non-generic portions of the concrete file implementations. - * - * This class is useful in a "simple usage" situation where it is desirable - * to be able to get and set some of the tag information that is similar - * across file types. - * - * Also note that it is probably a good idea to plug this into your mime - * type system rather than using the constructor that accepts a file name using - * the FileTypeResolver. - * - * \see FileTypeResolver - * \see addFileTypeResolver() - */ - - class TAGLIB_EXPORT FileRef - { - public: - - //! A class for pluggable file type resolution. - - /*! - * This class is used to add extend TagLib's very basic file name based file - * type resolution. - * - * This can be accomplished with: - * - * \code - * - * class MyFileTypeResolver : FileTypeResolver - * { - * TagLib::File *createFile(TagLib::FileName *fileName, bool, AudioProperties::ReadStyle) - * { - * if(someCheckForAnMP3File(fileName)) - * return new TagLib::MPEG::File(fileName); - * return 0; - * } - * } - * - * FileRef::addFileTypeResolver(new MyFileTypeResolver); - * - * \endcode - * - * Naturally a less contrived example would be slightly more complex. This - * can be used to plug in mime-type detection systems or to add new file types - * to TagLib. - */ - - class TAGLIB_EXPORT FileTypeResolver - { - TAGLIB_IGNORE_MISSING_DESTRUCTOR - public: - /*! - * This method must be overridden to provide an additional file type - * resolver. If the resolver is able to determine the file type it should - * return a valid File object; if not it should return 0. - * - * \note The created file is then owned by the FileRef and should not be - * deleted. Deletion will happen automatically when the FileRef passes - * out of scope. - */ - virtual File *createFile(FileName fileName, - bool readAudioProperties = true, - AudioProperties::ReadStyle - audioPropertiesStyle = AudioProperties::Average) const = 0; - }; - - /*! - * Creates a null FileRef. - */ - FileRef(); - - /*! - * Create a FileRef from \a fileName. If \a readAudioProperties is true then - * the audio properties will be read using \a audioPropertiesStyle. If - * \a readAudioProperties is false then \a audioPropertiesStyle will be - * ignored. - * - * Also see the note in the class documentation about why you may not want to - * use this method in your application. - */ - explicit FileRef(FileName fileName, - bool readAudioProperties = true, - AudioProperties::ReadStyle - audioPropertiesStyle = AudioProperties::Average); - - /*! - * Contruct a FileRef using \a file. The FileRef now takes ownership of the - * pointer and will delete the File when it passes out of scope. - */ - explicit FileRef(File *file); - - /*! - * Make a copy of \a ref. - */ - FileRef(const FileRef &ref); - - /*! - * Destroys this FileRef instance. - */ - virtual ~FileRef(); - - /*! - * Returns a pointer to represented file's tag. - * - * \warning This pointer will become invalid when this FileRef and all - * copies pass out of scope. - * - * \warning Do not cast it to any subclasses of \class Tag. - * Use tag returning methods of appropriate subclasses of \class File instead. - * - * \see File::tag() - */ - Tag *tag() const; - - /*! - * Returns the audio properties for this FileRef. If no audio properties - * were read then this will returns a null pointer. - */ - AudioProperties *audioProperties() const; - - /*! - * Returns a pointer to the file represented by this handler class. - * - * As a general rule this call should be avoided since if you need to work - * with file objects directly, you are probably better served instantiating - * the File subclasses (i.e. MPEG::File) manually and working with their APIs. - * - * This <i>handle</i> exists to provide a minimal, generic and value-based - * wrapper around a File. Accessing the file directly generally indicates - * a moving away from this simplicity (and into things beyond the scope of - * FileRef). - * - * \warning This pointer will become invalid when this FileRef and all - * copies pass out of scope. - */ - File *file() const; - - /*! - * Saves the file. Returns true on success. - */ - bool save(); - - /*! - * Adds a FileTypeResolver to the list of those used by TagLib. Each - * additional FileTypeResolver is added to the front of a list of resolvers - * that are tried. If the FileTypeResolver returns zero the next resolver - * is tried. - * - * Returns a pointer to the added resolver (the same one that's passed in -- - * this is mostly so that static inialializers have something to use for - * assignment). - * - * \see FileTypeResolver - */ - static const FileTypeResolver *addFileTypeResolver(const FileTypeResolver *resolver); - - /*! - * As is mentioned elsewhere in this class's documentation, the default file - * type resolution code provided by TagLib only works by comparing file - * extensions. - * - * This method returns the list of file extensions that are used by default. - * - * The extensions are all returned in lowercase, though the comparison used - * by TagLib for resolution is case-insensitive. - * - * \note This does not account for any additional file type resolvers that - * are plugged in. Also note that this is not intended to replace a propper - * mime-type resolution system, but is just here for reference. - * - * \see FileTypeResolver - */ - static StringList defaultFileExtensions(); - - /*! - * Returns true if the file (and as such other pointers) are null. - */ - bool isNull() const; - - /*! - * Assign the file pointed to by \a ref to this FileRef. - */ - FileRef &operator=(const FileRef &ref); - - /*! - * Returns true if this FileRef and \a ref point to the same File object. - */ - bool operator==(const FileRef &ref) const; - - /*! - * Returns true if this FileRef and \a ref do not point to the same File - * object. - */ - bool operator!=(const FileRef &ref) const; - - /*! - * A simple implementation of file type guessing. If \a readAudioProperties - * is true then the audio properties will be read using - * \a audioPropertiesStyle. If \a readAudioProperties is false then - * \a audioPropertiesStyle will be ignored. - * - * \note You generally shouldn't use this method, but instead the constructor - * directly. - * - * \deprecated - */ - static File *create(FileName fileName, - bool readAudioProperties = true, - AudioProperties::ReadStyle audioPropertiesStyle = AudioProperties::Average); - - - private: - class FileRefPrivate; - FileRefPrivate *d; - }; - -} // namespace TagLib - -#endif diff --git a/taglib/taglib/flac/flacfile.cpp b/taglib/taglib/flac/flacfile.cpp deleted file mode 100644 index 823170a..0000000 --- a/taglib/taglib/flac/flacfile.cpp +++ /dev/null @@ -1,568 +0,0 @@ -/*************************************************************************** - copyright : (C) 2003-2004 by Allan Sandfeld Jensen - email : kde@carewolf.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <tbytevector.h> -#include <tstring.h> -#include <tlist.h> -#include <tdebug.h> -#include <tagunion.h> -#include <tpropertymap.h> - -#include <id3v2header.h> -#include <id3v2tag.h> -#include <id3v1tag.h> -#include <xiphcomment.h> - -#include "flacpicture.h" -#include "flacfile.h" -#include "flacmetadatablock.h" -#include "flacunknownmetadatablock.h" - -using namespace TagLib; - -namespace -{ - enum { FlacXiphIndex = 0, FlacID3v2Index = 1, FlacID3v1Index = 2 }; - enum { MinPaddingLength = 4096 }; - enum { LastBlockFlag = 0x80 }; -} - -class FLAC::File::FilePrivate -{ -public: - FilePrivate() : - ID3v2FrameFactory(ID3v2::FrameFactory::instance()), - ID3v2Location(-1), - ID3v2OriginalSize(0), - ID3v1Location(-1), - properties(0), - flacStart(0), - streamStart(0), - streamLength(0), - scanned(false), - hasXiphComment(false), - hasID3v2(false), - hasID3v1(false) - { - } - - ~FilePrivate() - { - uint size = blocks.size(); - for(uint i = 0; i < size; i++) { - delete blocks[i]; - } - delete properties; - } - - const ID3v2::FrameFactory *ID3v2FrameFactory; - long ID3v2Location; - uint ID3v2OriginalSize; - - long ID3v1Location; - - TagUnion tag; - - Properties *properties; - ByteVector streamInfoData; - ByteVector xiphCommentData; - List<MetadataBlock *> blocks; - - long flacStart; - long streamStart; - long streamLength; - bool scanned; - - bool hasXiphComment; - bool hasID3v2; - bool hasID3v1; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -FLAC::File::File(FileName file, bool readProperties, - Properties::ReadStyle propertiesStyle) : - TagLib::File(file) -{ - d = new FilePrivate; - if(isOpen()) - read(readProperties, propertiesStyle); -} - -FLAC::File::File(FileName file, ID3v2::FrameFactory *frameFactory, - bool readProperties, Properties::ReadStyle propertiesStyle) : - TagLib::File(file) -{ - d = new FilePrivate; - d->ID3v2FrameFactory = frameFactory; - if(isOpen()) - read(readProperties, propertiesStyle); -} - -FLAC::File::File(IOStream *stream, ID3v2::FrameFactory *frameFactory, - bool readProperties, Properties::ReadStyle propertiesStyle) : - TagLib::File(stream) -{ - d = new FilePrivate; - d->ID3v2FrameFactory = frameFactory; - if(isOpen()) - read(readProperties, propertiesStyle); -} - -FLAC::File::~File() -{ - delete d; -} - -TagLib::Tag *FLAC::File::tag() const -{ - return &d->tag; -} - -PropertyMap FLAC::File::properties() const -{ - // once Tag::properties() is virtual, this case distinction could actually be done - // within TagUnion. - if(d->hasXiphComment) - return d->tag.access<Ogg::XiphComment>(FlacXiphIndex, false)->properties(); - if(d->hasID3v2) - return d->tag.access<ID3v2::Tag>(FlacID3v2Index, false)->properties(); - if(d->hasID3v1) - return d->tag.access<ID3v1::Tag>(FlacID3v1Index, false)->properties(); - return PropertyMap(); -} - -void FLAC::File::removeUnsupportedProperties(const StringList &unsupported) -{ - if(d->hasXiphComment) - d->tag.access<Ogg::XiphComment>(FlacXiphIndex, false)->removeUnsupportedProperties(unsupported); - if(d->hasID3v2) - d->tag.access<ID3v2::Tag>(FlacID3v2Index, false)->removeUnsupportedProperties(unsupported); - if(d->hasID3v1) - d->tag.access<ID3v1::Tag>(FlacID3v1Index, false)->removeUnsupportedProperties(unsupported); -} - -PropertyMap FLAC::File::setProperties(const PropertyMap &properties) -{ - return d->tag.access<Ogg::XiphComment>(FlacXiphIndex, true)->setProperties(properties); -} - -FLAC::Properties *FLAC::File::audioProperties() const -{ - return d->properties; -} - - -bool FLAC::File::save() -{ - if(readOnly()) { - debug("FLAC::File::save() - Cannot save to a read only file."); - return false; - } - - if(!isValid()) { - debug("FLAC::File::save() -- Trying to save invalid file."); - return false; - } - - // Create new vorbis comments - - Tag::duplicate(&d->tag, xiphComment(true), false); - - d->xiphCommentData = xiphComment()->render(false); - - // Replace metadata blocks - - bool foundVorbisCommentBlock = false; - List<MetadataBlock *> newBlocks; - for(uint i = 0; i < d->blocks.size(); i++) { - MetadataBlock *block = d->blocks[i]; - if(block->code() == MetadataBlock::VorbisComment) { - // Set the new Vorbis Comment block - delete block; - block = new UnknownMetadataBlock(MetadataBlock::VorbisComment, d->xiphCommentData); - foundVorbisCommentBlock = true; - } - if(block->code() == MetadataBlock::Padding) { - delete block; - continue; - } - newBlocks.append(block); - } - if(!foundVorbisCommentBlock) { - newBlocks.append(new UnknownMetadataBlock(MetadataBlock::VorbisComment, d->xiphCommentData)); - foundVorbisCommentBlock = true; - } - d->blocks = newBlocks; - - // Render data for the metadata blocks - - ByteVector data; - for(uint i = 0; i < newBlocks.size(); i++) { - FLAC::MetadataBlock *block = newBlocks[i]; - ByteVector blockData = block->render(); - ByteVector blockHeader = ByteVector::fromUInt(blockData.size()); - blockHeader[0] = block->code(); - data.append(blockHeader); - data.append(blockData); - } - - // Adjust the padding block(s) - - long originalLength = d->streamStart - d->flacStart; - int paddingLength = originalLength - data.size() - 4; - if (paddingLength < 0) { - paddingLength = MinPaddingLength; - } - ByteVector padding = ByteVector::fromUInt(paddingLength); - padding.resize(paddingLength + 4); - padding[0] = (char)(FLAC::MetadataBlock::Padding | LastBlockFlag); - data.append(padding); - - // Write the data to the file - - insert(data, d->flacStart, originalLength); - d->hasXiphComment = true; - - // Update ID3 tags - - if(ID3v2Tag()) { - if(d->hasID3v2) { - if(d->ID3v2Location < d->flacStart) - debug("FLAC::File::save() -- This can't be right -- an ID3v2 tag after the " - "start of the FLAC bytestream? Not writing the ID3v2 tag."); - else - insert(ID3v2Tag()->render(), d->ID3v2Location, d->ID3v2OriginalSize); - } - else - insert(ID3v2Tag()->render(), 0, 0); - } - - if(ID3v1Tag()) { - seek(-128, End); - writeBlock(ID3v1Tag()->render()); - } - - return true; -} - -ID3v2::Tag *FLAC::File::ID3v2Tag(bool create) -{ - if(!create || d->tag[FlacID3v2Index]) - return static_cast<ID3v2::Tag *>(d->tag[FlacID3v2Index]); - - d->tag.set(FlacID3v2Index, new ID3v2::Tag); - return static_cast<ID3v2::Tag *>(d->tag[FlacID3v2Index]); -} - -ID3v1::Tag *FLAC::File::ID3v1Tag(bool create) -{ - return d->tag.access<ID3v1::Tag>(FlacID3v1Index, create); -} - -Ogg::XiphComment *FLAC::File::xiphComment(bool create) -{ - return d->tag.access<Ogg::XiphComment>(FlacXiphIndex, create); -} - -void FLAC::File::setID3v2FrameFactory(const ID3v2::FrameFactory *factory) -{ - d->ID3v2FrameFactory = factory; -} - - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -void FLAC::File::read(bool readProperties, Properties::ReadStyle propertiesStyle) -{ - // Look for an ID3v2 tag - - d->ID3v2Location = findID3v2(); - - if(d->ID3v2Location >= 0) { - - d->tag.set(FlacID3v2Index, new ID3v2::Tag(this, d->ID3v2Location, d->ID3v2FrameFactory)); - - d->ID3v2OriginalSize = ID3v2Tag()->header()->completeTagSize(); - - if(ID3v2Tag()->header()->tagSize() <= 0) - d->tag.set(FlacID3v2Index, 0); - else - d->hasID3v2 = true; - } - - // Look for an ID3v1 tag - - d->ID3v1Location = findID3v1(); - - if(d->ID3v1Location >= 0) { - d->tag.set(FlacID3v1Index, new ID3v1::Tag(this, d->ID3v1Location)); - d->hasID3v1 = true; - } - - // Look for FLAC metadata, including vorbis comments - - scan(); - - if(!isValid()) - return; - - if(d->hasXiphComment) - d->tag.set(FlacXiphIndex, new Ogg::XiphComment(xiphCommentData())); - else - d->tag.set(FlacXiphIndex, new Ogg::XiphComment); - - if(readProperties) - d->properties = new Properties(streamInfoData(), streamLength(), propertiesStyle); -} - -ByteVector FLAC::File::streamInfoData() -{ - return isValid() ? d->streamInfoData : ByteVector(); -} - -ByteVector FLAC::File::xiphCommentData() const -{ - return (isValid() && d->hasXiphComment) ? d->xiphCommentData : ByteVector(); -} - -long FLAC::File::streamLength() -{ - return d->streamLength; -} - -void FLAC::File::scan() -{ - // Scan the metadata pages - - if(d->scanned) - return; - - if(!isValid()) - return; - - long nextBlockOffset; - - if(d->hasID3v2) - nextBlockOffset = find("fLaC", d->ID3v2Location + d->ID3v2OriginalSize); - else - nextBlockOffset = find("fLaC"); - - if(nextBlockOffset < 0) { - debug("FLAC::File::scan() -- FLAC stream not found"); - setValid(false); - return; - } - - nextBlockOffset += 4; - d->flacStart = nextBlockOffset; - - seek(nextBlockOffset); - - ByteVector header = readBlock(4); - - // Header format (from spec): - // <1> Last-metadata-block flag - // <7> BLOCK_TYPE - // 0 : STREAMINFO - // 1 : PADDING - // .. - // 4 : VORBIS_COMMENT - // .. - // <24> Length of metadata to follow - - char blockType = header[0] & 0x7f; - bool isLastBlock = (header[0] & 0x80) != 0; - uint length = header.toUInt(1U, 3U); - - // First block should be the stream_info metadata - - if(blockType != MetadataBlock::StreamInfo) { - debug("FLAC::File::scan() -- invalid FLAC stream"); - setValid(false); - return; - } - - d->streamInfoData = readBlock(length); - d->blocks.append(new UnknownMetadataBlock(blockType, d->streamInfoData)); - nextBlockOffset += length + 4; - - // Search through the remaining metadata - while(!isLastBlock) { - - header = readBlock(4); - blockType = header[0] & 0x7f; - isLastBlock = (header[0] & 0x80) != 0; - length = header.toUInt(1U, 3U); - - ByteVector data = readBlock(length); - if(data.size() != length || length == 0) { - debug("FLAC::File::scan() -- FLAC stream corrupted"); - setValid(false); - return; - } - - MetadataBlock *block = 0; - - // Found the vorbis-comment - if(blockType == MetadataBlock::VorbisComment) { - if(!d->hasXiphComment) { - d->xiphCommentData = data; - d->hasXiphComment = true; - } - else { - debug("FLAC::File::scan() -- multiple Vorbis Comment blocks found, using the first one"); - } - } - else if(blockType == MetadataBlock::Picture) { - FLAC::Picture *picture = new FLAC::Picture(); - if(picture->parse(data)) { - block = picture; - } - else { - debug("FLAC::File::scan() -- invalid picture found, discarting"); - delete picture; - } - } - - if(!block) { - block = new UnknownMetadataBlock(blockType, data); - } - if(block->code() != MetadataBlock::Padding) { - d->blocks.append(block); - } - else { - delete block; - } - - nextBlockOffset += length + 4; - - if(nextBlockOffset >= File::length()) { - debug("FLAC::File::scan() -- FLAC stream corrupted"); - setValid(false); - return; - } - seek(nextBlockOffset); - } - - // End of metadata, now comes the datastream - - d->streamStart = nextBlockOffset; - d->streamLength = File::length() - d->streamStart; - - if(d->hasID3v1) - d->streamLength -= 128; - - d->scanned = true; -} - -long FLAC::File::findID3v1() -{ - if(!isValid()) - return -1; - - seek(-128, End); - long p = tell(); - - if(readBlock(3) == ID3v1::Tag::fileIdentifier()) - return p; - - return -1; -} - -long FLAC::File::findID3v2() -{ - if(!isValid()) - return -1; - - seek(0); - - if(readBlock(3) == ID3v2::Header::fileIdentifier()) - return 0; - - return -1; -} - -List<FLAC::Picture *> FLAC::File::pictureList() -{ - List<Picture *> pictures; - for(uint i = 0; i < d->blocks.size(); i++) { - Picture *picture = dynamic_cast<Picture *>(d->blocks[i]); - if(picture) { - pictures.append(picture); - } - } - return pictures; -} - -void FLAC::File::addPicture(Picture *picture) -{ - d->blocks.append(picture); -} - -void FLAC::File::removePicture(Picture *picture, bool del) -{ - MetadataBlock *block = picture; - List<MetadataBlock *>::Iterator it = d->blocks.find(block); - if(it != d->blocks.end()) - d->blocks.erase(it); - - if(del) - delete picture; -} - -void FLAC::File::removePictures() -{ - List<MetadataBlock *> newBlocks; - for(uint i = 0; i < d->blocks.size(); i++) { - Picture *picture = dynamic_cast<Picture *>(d->blocks[i]); - if(picture) { - delete picture; - } - else { - newBlocks.append(d->blocks[i]); - } - } - d->blocks = newBlocks; -} - -bool FLAC::File::hasXiphComment() const -{ - return d->hasXiphComment; -} - -bool FLAC::File::hasID3v1Tag() const -{ - return d->hasID3v1; -} - -bool FLAC::File::hasID3v2Tag() const -{ - return d->hasID3v2; -} diff --git a/taglib/taglib/flac/flacfile.h b/taglib/taglib/flac/flacfile.h deleted file mode 100644 index 0963f4a..0000000 --- a/taglib/taglib/flac/flacfile.h +++ /dev/null @@ -1,305 +0,0 @@ -/*************************************************************************** - copyright : (C) 2003 by Allan Sandfeld Jensen - email : kde@carewolf.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_FLACFILE_H -#define TAGLIB_FLACFILE_H - -#include "taglib_export.h" -#include "tfile.h" -#include "tlist.h" -#include "tag.h" - -#include "flacpicture.h" -#include "flacproperties.h" - -namespace TagLib { - - class Tag; - namespace ID3v2 { class FrameFactory; class Tag; } - namespace ID3v1 { class Tag; } - namespace Ogg { class XiphComment; } - - //! An implementation of FLAC metadata - - /*! - * This is implementation of FLAC metadata for non-Ogg FLAC files. At some - * point when Ogg / FLAC is more common there will be a similar implementation - * under the Ogg hiearchy. - * - * This supports ID3v1, ID3v2 and Xiph style comments as well as reading stream - * properties from the file. - */ - - namespace FLAC { - - //! An implementation of TagLib::File with FLAC specific methods - - /*! - * This implements and provides an interface for FLAC 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 FLAC files. - */ - - class TAGLIB_EXPORT File : public TagLib::File - { - public: - /*! - * Constructs a FLAC file from \a file. If \a readProperties is true the - * file's audio properties will also be read. - * - * \note In the current implementation, \a propertiesStyle is ignored. - * - * \deprecated This constructor will be dropped in favor of the one below - * in a future version. - */ - File(FileName file, bool readProperties = true, - Properties::ReadStyle propertiesStyle = Properties::Average); - - /*! - * Constructs an 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, - bool readProperties = true, - Properties::ReadStyle propertiesStyle = Properties::Average); - - /*! - * 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, - bool readProperties = true, - Properties::ReadStyle propertiesStyle = Properties::Average); - - /*! - * Destroys this instance of the File. - */ - virtual ~File(); - - /*! - * Returns the Tag for this file. This will be a union of XiphComment, - * ID3v1 and ID3v2 tags. - * - * \see ID3v2Tag() - * \see ID3v1Tag() - * \see XiphComment() - */ - virtual TagLib::Tag *tag() const; - - /*! - * Implements the unified property interface -- export function. - * If the file contains more than one tag (e.g. XiphComment and ID3v1), - * only the first one (in the order XiphComment, ID3v2, ID3v1) will be - * converted to the PropertyMap. - */ - PropertyMap properties() const; - - void removeUnsupportedProperties(const StringList &); - - /*! - * Implements the unified property interface -- import function. - * This always creates a Xiph comment, if none exists. The return value - * relates to the Xiph comment only. - * Ignores any changes to ID3v1 or ID3v2 comments since they are not allowed - * in the FLAC specification. - */ - PropertyMap setProperties(const PropertyMap &); - - /*! - * Returns the FLAC::Properties for this file. If no audio properties - * were read then this will return a null pointer. - */ - virtual Properties *audioProperties() const; - - /*! - * Save the file. This will primarily save the XiphComment, but - * will also keep any old ID3-tags up to date. If the file - * has no XiphComment, one will be constructed from the ID3-tags. - * - * This returns true if the save was successful. - */ - virtual bool save(); - - /*! - * Returns a pointer to the ID3v2 tag of the file. - * - * 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 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. - * - * 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 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 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 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); - - /*! - * Set the ID3v2::FrameFactory to something other than the default. This - * can be used to specify the way that ID3v2 frames will be interpreted - * when - * - * \see ID3v2FrameFactory - */ - void setID3v2FrameFactory(const ID3v2::FrameFactory *factory); - - /*! - * Returns the block of data used by FLAC::Properties for parsing the - * stream properties. - * - * \deprecated This method will not be public in a future release. - */ - ByteVector streamInfoData(); // BIC: remove - - /*! - * Returns the length of the audio-stream, used by FLAC::Properties for - * calculating the bitrate. - * - * \deprecated This method will not be public in a future release. - */ - long streamLength(); // BIC: remove - - /*! - * Returns a list of pictures attached to the FLAC file. - */ - List<Picture *> pictureList(); - - /*! - * Removes an attached picture. If \a del is true the picture's memory - * will be freed; if it is false, it must be deleted by the user. - */ - void removePicture(Picture *picture, bool del = true); - - /*! - * Remove all attached images. - */ - void removePictures(); - - /*! - * Add a new picture to the file. The file takes ownership of the - * picture and will handle freeing its memory. - * - * \note The file will be saved only after calling save(). - */ - void addPicture(Picture *picture); - - /*! - * Returns whether or not the file on disk actually has a XiphComment. - * - * \see xiphComment() - */ - bool hasXiphComment() const; - - /*! - * Returns whether or not the file on disk actually has an ID3v1 tag. - * - * \see ID3v1Tag() - */ - bool hasID3v1Tag() const; - - /*! - * Returns whether or not the file on disk actually has an ID3v2 tag. - * - * \see ID3v2Tag() - */ - bool hasID3v2Tag() const; - - private: - File(const File &); - File &operator=(const File &); - - void read(bool readProperties, Properties::ReadStyle propertiesStyle); - void scan(); - long findID3v2(); - long findID3v1(); - ByteVector xiphCommentData() const; - long findPaddingBreak(long nextPageOffset, long targetOffset, bool *isLast); - - class FilePrivate; - FilePrivate *d; - }; - } -} - -#endif diff --git a/taglib/taglib/flac/flacmetadatablock.cpp b/taglib/taglib/flac/flacmetadatablock.cpp deleted file mode 100644 index 17ab05f..0000000 --- a/taglib/taglib/flac/flacmetadatablock.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/************************************************************************** - copyright : (C) 2010 by Lukáš Lalinský - email : lalinsky@gmail.com - **************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <taglib.h> -#include <tdebug.h> -#include "flacmetadatablock.h" - -using namespace TagLib; - -class FLAC::MetadataBlock::MetadataBlockPrivate -{ -public: - MetadataBlockPrivate() {} - -}; - -FLAC::MetadataBlock::MetadataBlock() -{ - d = 0; -} - -FLAC::MetadataBlock::~MetadataBlock() -{ -} - diff --git a/taglib/taglib/flac/flacmetadatablock.h b/taglib/taglib/flac/flacmetadatablock.h deleted file mode 100644 index 41bca31..0000000 --- a/taglib/taglib/flac/flacmetadatablock.h +++ /dev/null @@ -1,75 +0,0 @@ -/************************************************************************** - copyright : (C) 2010 by Lukáš Lalinský - email : lalinsky@gmail.com - **************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_FLACMETADATABLOCK_H -#define TAGLIB_FLACMETADATABLOCK_H - -#include "tlist.h" -#include "tbytevector.h" -#include "taglib_export.h" - -namespace TagLib { - - namespace FLAC { - - class TAGLIB_EXPORT MetadataBlock - { - public: - MetadataBlock(); - virtual ~MetadataBlock(); - - enum BlockType { - StreamInfo = 0, - Padding, - Application, - SeekTable, - VorbisComment, - CueSheet, - Picture - }; - - /*! - * Returns the FLAC metadata block type. - */ - virtual int code() const = 0; - - /*! - * Render the content of the block. - */ - virtual ByteVector render() const = 0; - - private: - MetadataBlock(const MetadataBlock &item); - MetadataBlock &operator=(const MetadataBlock &item); - - class MetadataBlockPrivate; - MetadataBlockPrivate *d; - }; - - } - -} - -#endif diff --git a/taglib/taglib/flac/flacpicture.cpp b/taglib/taglib/flac/flacpicture.cpp deleted file mode 100644 index a2a9000..0000000 --- a/taglib/taglib/flac/flacpicture.cpp +++ /dev/null @@ -1,217 +0,0 @@ -/************************************************************************** - copyright : (C) 2010 by Lukáš Lalinský - email : lalinsky@gmail.com - **************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <taglib.h> -#include <tdebug.h> -#include "flacpicture.h" - -using namespace TagLib; - -class FLAC::Picture::PicturePrivate -{ -public: - PicturePrivate() : - type(FLAC::Picture::Other), - width(0), - height(0), - colorDepth(0), - numColors(0) - {} - - Type type; - String mimeType; - String description; - int width; - int height; - int colorDepth; - int numColors; - ByteVector data; -}; - -FLAC::Picture::Picture() -{ - d = new PicturePrivate; -} - -FLAC::Picture::Picture(const ByteVector &data) -{ - d = new PicturePrivate; - parse(data); -} - -FLAC::Picture::~Picture() -{ - delete d; -} - -int FLAC::Picture::code() const -{ - return FLAC::MetadataBlock::Picture; -} - -bool FLAC::Picture::parse(const ByteVector &data) -{ - if(data.size() < 32) { - debug("A picture block must contain at least 5 bytes."); - return false; - } - - uint pos = 0; - d->type = FLAC::Picture::Type(data.toUInt(pos)); - pos += 4; - uint mimeTypeLength = data.toUInt(pos); - pos += 4; - if(pos + mimeTypeLength + 24 > data.size()) { - debug("Invalid picture block."); - return false; - } - d->mimeType = String(data.mid(pos, mimeTypeLength), String::UTF8); - pos += mimeTypeLength; - uint descriptionLength = data.toUInt(pos); - pos += 4; - if(pos + descriptionLength + 20 > data.size()) { - debug("Invalid picture block."); - return false; - } - d->description = String(data.mid(pos, descriptionLength), String::UTF8); - pos += descriptionLength; - d->width = data.toUInt(pos); - pos += 4; - d->height = data.toUInt(pos); - pos += 4; - d->colorDepth = data.toUInt(pos); - pos += 4; - d->numColors = data.toUInt(pos); - pos += 4; - uint dataLength = data.toUInt(pos); - pos += 4; - if(pos + dataLength > data.size()) { - debug("Invalid picture block."); - return false; - } - d->data = data.mid(pos, dataLength); - - return true; -} - -ByteVector FLAC::Picture::render() const -{ - ByteVector result; - result.append(ByteVector::fromUInt(d->type)); - ByteVector mimeTypeData = d->mimeType.data(String::UTF8); - result.append(ByteVector::fromUInt(mimeTypeData.size())); - result.append(mimeTypeData); - ByteVector descriptionData = d->description.data(String::UTF8); - result.append(ByteVector::fromUInt(descriptionData.size())); - result.append(descriptionData); - result.append(ByteVector::fromUInt(d->width)); - result.append(ByteVector::fromUInt(d->height)); - result.append(ByteVector::fromUInt(d->colorDepth)); - result.append(ByteVector::fromUInt(d->numColors)); - result.append(ByteVector::fromUInt(d->data.size())); - result.append(d->data); - return result; -} - -FLAC::Picture::Type FLAC::Picture::type() const -{ - return d->type; -} - -void FLAC::Picture::setType(FLAC::Picture::Type type) -{ - d->type = type; -} - -String FLAC::Picture::mimeType() const -{ - return d->mimeType; -} - -void FLAC::Picture::setMimeType(const String &mimeType) -{ - d->mimeType = mimeType; -} - -String FLAC::Picture::description() const -{ - return d->description; -} - -void FLAC::Picture::setDescription(const String &description) -{ - d->description = description; -} - -int FLAC::Picture::width() const -{ - return d->width; -} - -void FLAC::Picture::setWidth(int width) -{ - d->width = width; -} - -int FLAC::Picture::height() const -{ - return d->height; -} - -void FLAC::Picture::setHeight(int height) -{ - d->height = height; -} - -int FLAC::Picture::colorDepth() const -{ - return d->colorDepth; -} - -void FLAC::Picture::setColorDepth(int colorDepth) -{ - d->colorDepth = colorDepth; -} - -int FLAC::Picture::numColors() const -{ - return d->numColors; -} - -void FLAC::Picture::setNumColors(int numColors) -{ - d->numColors = numColors; -} - -ByteVector FLAC::Picture::data() const -{ - return d->data; -} - -void FLAC::Picture::setData(const ByteVector &data) -{ - d->data = data; -} - diff --git a/taglib/taglib/flac/flacpicture.h b/taglib/taglib/flac/flacpicture.h deleted file mode 100644 index b6def57..0000000 --- a/taglib/taglib/flac/flacpicture.h +++ /dev/null @@ -1,208 +0,0 @@ -/************************************************************************** - copyright : (C) 2010 by Lukáš Lalinský - email : lalinsky@gmail.com - **************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_FLACPICTURE_H -#define TAGLIB_FLACPICTURE_H - -#include "tlist.h" -#include "tstring.h" -#include "tbytevector.h" -#include "taglib_export.h" -#include "flacmetadatablock.h" - -namespace TagLib { - - namespace FLAC { - - class TAGLIB_EXPORT Picture : public MetadataBlock - { - public: - - /*! - * This describes the function or content of the picture. - */ - enum Type { - //! A type not enumerated below - Other = 0x00, - //! 32x32 PNG image that should be used as the file icon - FileIcon = 0x01, - //! File icon of a different size or format - OtherFileIcon = 0x02, - //! Front cover image of the album - FrontCover = 0x03, - //! Back cover image of the album - BackCover = 0x04, - //! Inside leaflet page of the album - LeafletPage = 0x05, - //! Image from the album itself - Media = 0x06, - //! Picture of the lead artist or soloist - LeadArtist = 0x07, - //! Picture of the artist or performer - Artist = 0x08, - //! Picture of the conductor - Conductor = 0x09, - //! Picture of the band or orchestra - Band = 0x0A, - //! Picture of the composer - Composer = 0x0B, - //! Picture of the lyricist or text writer - Lyricist = 0x0C, - //! Picture of the recording location or studio - RecordingLocation = 0x0D, - //! Picture of the artists during recording - DuringRecording = 0x0E, - //! Picture of the artists during performance - DuringPerformance = 0x0F, - //! Picture from a movie or video related to the track - MovieScreenCapture = 0x10, - //! Picture of a large, coloured fish - ColouredFish = 0x11, - //! Illustration related to the track - Illustration = 0x12, - //! Logo of the band or performer - BandLogo = 0x13, - //! Logo of the publisher (record company) - PublisherLogo = 0x14 - }; - - Picture(); - Picture(const ByteVector &data); - ~Picture(); - - /*! - * Returns the type of the image. - */ - Type type() const; - - /*! - * Sets the type of the image. - */ - void setType(Type type); - - /*! - * Returns the mime type of the image. This should in most cases be - * "image/png" or "image/jpeg". - */ - String mimeType() const; - - /*! - * Sets the mime type of the image. This should in most cases be - * "image/png" or "image/jpeg". - */ - void setMimeType(const String &m); - - /*! - * Returns a text description of the image. - */ - - String description() const; - - /*! - * Sets a textual description of the image to \a desc. - */ - - void setDescription(const String &desc); - - /*! - * Returns the width of the image. - */ - int width() const; - - /*! - * Sets the width of the image. - */ - void setWidth(int w); - - /*! - * Returns the height of the image. - */ - int height() const; - - /*! - * Sets the height of the image. - */ - void setHeight(int h); - - /*! - * Returns the color depth (in bits-per-pixel) of the image. - */ - int colorDepth() const; - - /*! - * Sets the color depth (in bits-per-pixel) of the image. - */ - void setColorDepth(int depth); - - /*! - * Returns the number of colors used on the image.. - */ - int numColors() const; - - /*! - * Sets the number of colors used on the image (for indexed images). - */ - void setNumColors(int numColors); - - /*! - * Returns the image data. - */ - ByteVector data() const; - - /*! - * Sets the image data. - */ - void setData(const ByteVector &data); - - /*! - * Returns the FLAC metadata block type. - */ - int code() const; - - /*! - * Render the content to the FLAC picture block format. - */ - ByteVector render() const; - - /*! - * Parse the picture data in the FLAC picture block format. - */ - bool parse(const ByteVector &rawData); - - private: - Picture(const Picture &item); - Picture &operator=(const Picture &item); - - class PicturePrivate; - PicturePrivate *d; - }; - - typedef List<Picture> PictureList; - - } - -} - -#endif diff --git a/taglib/taglib/flac/flacproperties.cpp b/taglib/taglib/flac/flacproperties.cpp deleted file mode 100644 index e591193..0000000 --- a/taglib/taglib/flac/flacproperties.cpp +++ /dev/null @@ -1,169 +0,0 @@ -/*************************************************************************** - copyright : (C) 2003 by Allan Sandfeld Jensen - email : kde@carewolf.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <tstring.h> -#include <tdebug.h> - -#include "flacproperties.h" -#include "flacfile.h" - -using namespace TagLib; - -class FLAC::Properties::PropertiesPrivate -{ -public: - PropertiesPrivate(ByteVector d, long st, ReadStyle s) : - data(d), - streamLength(st), - style(s), - length(0), - bitrate(0), - sampleRate(0), - sampleWidth(0), - channels(0), - sampleFrames(0) {} - - ByteVector data; - long streamLength; - ReadStyle style; - int length; - int bitrate; - int sampleRate; - int sampleWidth; - int channels; - unsigned long long sampleFrames; - ByteVector signature; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -FLAC::Properties::Properties(ByteVector data, long streamLength, ReadStyle style) : AudioProperties(style) -{ - d = new PropertiesPrivate(data, streamLength, style); - read(); -} - -FLAC::Properties::Properties(File *file, ReadStyle style) : AudioProperties(style) -{ - d = new PropertiesPrivate(file->streamInfoData(), file->streamLength(), style); - read(); -} - -FLAC::Properties::~Properties() -{ - delete d; -} - -int FLAC::Properties::length() const -{ - return d->length; -} - -int FLAC::Properties::bitrate() const -{ - return d->bitrate; -} - -int FLAC::Properties::sampleRate() const -{ - return d->sampleRate; -} - -int FLAC::Properties::sampleWidth() const -{ - return d->sampleWidth; -} - -int FLAC::Properties::channels() const -{ - return d->channels; -} - -unsigned long long FLAC::Properties::sampleFrames() const -{ - return d->sampleFrames; -} - -ByteVector FLAC::Properties::signature() const -{ - return d->signature; -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -void FLAC::Properties::read() -{ - if(d->data.size() < 18) { - debug("FLAC::Properties::read() - FLAC properties must contain at least 18 bytes."); - return; - } - - uint pos = 0; - - // Minimum block size (in samples) - pos += 2; - - // Maximum block size (in samples) - pos += 2; - - // Minimum frame size (in bytes) - pos += 3; - - // Maximum frame size (in bytes) - pos += 3; - - uint flags = d->data.toUInt(pos, true); - pos += 4; - - d->sampleRate = flags >> 12; - d->channels = ((flags >> 9) & 7) + 1; - d->sampleWidth = ((flags >> 4) & 31) + 1; - - // The last 4 bits are the most significant 4 bits for the 36 bit - // stream length in samples. (Audio files measured in days) - - unsigned long long hi = flags & 0xf; - unsigned long long lo = d->data.toUInt(pos, true); - pos += 4; - - d->sampleFrames = (hi << 32) | lo; - - if(d->sampleRate > 0) - d->length = int(d->sampleFrames / d->sampleRate); - - // Uncompressed bitrate: - - //d->bitrate = ((d->sampleRate * d->channels) / 1000) * d->sampleWidth; - - // Real bitrate: - - d->bitrate = d->length > 0 ? ((d->streamLength * 8UL) / d->length) / 1000 : 0; - - d->signature = d->data.mid(pos, 32); -} diff --git a/taglib/taglib/flac/flacproperties.h b/taglib/taglib/flac/flacproperties.h deleted file mode 100644 index c145898..0000000 --- a/taglib/taglib/flac/flacproperties.h +++ /dev/null @@ -1,103 +0,0 @@ -/*************************************************************************** - copyright : (C) 2003 by Allan Sandfeld Jensen - email : kde@carewolf.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_FLACPROPERTIES_H -#define TAGLIB_FLACPROPERTIES_H - -#include "taglib_export.h" -#include "audioproperties.h" - -namespace TagLib { - - namespace FLAC { - - class File; - - //! An implementation of audio property reading for FLAC - - /*! - * This reads the data from an FLAC stream found in the AudioProperties - * API. - */ - - class TAGLIB_EXPORT Properties : public AudioProperties - { - public: - /*! - * Create an instance of FLAC::Properties with the data read from the - * ByteVector \a data. - */ - // BIC: switch to const reference - Properties(ByteVector data, long streamLength, ReadStyle style = Average); - - /*! - * Create an instance of FLAC::Properties with the data read from the - * FLAC::File \a file. - */ - // BIC: remove - Properties(File *file, ReadStyle style = Average); - - /*! - * Destroys this FLAC::Properties instance. - */ - virtual ~Properties(); - - // Reimplementations. - - virtual int length() const; - virtual int bitrate() const; - virtual int sampleRate() const; - virtual int channels() const; - - /*! - * Returns the sample width as read from the FLAC identification - * header. - */ - int sampleWidth() const; - - /*! - * Return the number of sample frames - */ - unsigned long long sampleFrames() const; - - /*! - * Returns the MD5 signature of the uncompressed audio stream as read - * from the stream info header header. - */ - ByteVector signature() const; - - private: - Properties(const Properties &); - Properties &operator=(const Properties &); - - void read(); - - class PropertiesPrivate; - PropertiesPrivate *d; - }; - } -} - -#endif diff --git a/taglib/taglib/flac/flacunknownmetadatablock.cpp b/taglib/taglib/flac/flacunknownmetadatablock.cpp deleted file mode 100644 index dcd5d65..0000000 --- a/taglib/taglib/flac/flacunknownmetadatablock.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/************************************************************************** - copyright : (C) 2010 by Lukáš Lalinský - email : lalinsky@gmail.com - **************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <taglib.h> -#include <tdebug.h> -#include <tstring.h> -#include "flacunknownmetadatablock.h" - -using namespace TagLib; - -class FLAC::UnknownMetadataBlock::UnknownMetadataBlockPrivate -{ -public: - UnknownMetadataBlockPrivate() : code(0) {} - - int code; - ByteVector data; -}; - -FLAC::UnknownMetadataBlock::UnknownMetadataBlock(int code, const ByteVector &data) -{ - d = new UnknownMetadataBlockPrivate; - d->code = code; - //debug(String(data.toHex())); - d->data = data; -} - -FLAC::UnknownMetadataBlock::~UnknownMetadataBlock() -{ - delete d; -} - -int FLAC::UnknownMetadataBlock::code() const -{ - return d->code; -} - -void FLAC::UnknownMetadataBlock::setCode(int code) -{ - d->code = code; -} - -ByteVector FLAC::UnknownMetadataBlock::data() const -{ - return d->data; -} - -void FLAC::UnknownMetadataBlock::setData(const ByteVector &data) -{ - d->data = data; -} - -ByteVector FLAC::UnknownMetadataBlock::render() const -{ - return d->data; -} - diff --git a/taglib/taglib/flac/flacunknownmetadatablock.h b/taglib/taglib/flac/flacunknownmetadatablock.h deleted file mode 100644 index 3030254..0000000 --- a/taglib/taglib/flac/flacunknownmetadatablock.h +++ /dev/null @@ -1,81 +0,0 @@ -/************************************************************************** - copyright : (C) 2010 by Lukáš Lalinský - email : lalinsky@gmail.com - **************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_FLACUNKNOWNMETADATABLOCK_H -#define TAGLIB_FLACUNKNOWNMETADATABLOCK_H - -#include "tlist.h" -#include "tbytevector.h" -#include "taglib_export.h" -#include "flacmetadatablock.h" - -namespace TagLib { - - namespace FLAC { - - class TAGLIB_EXPORT UnknownMetadataBlock : public MetadataBlock - { - public: - UnknownMetadataBlock(int blockType, const ByteVector &data); - ~UnknownMetadataBlock(); - - /*! - * Returns the FLAC metadata block type. - */ - int code() const; - - /*! - * Sets the FLAC metadata block type. - */ - void setCode(int code); - - /*! - * Returns the FLAC metadata block type. - */ - ByteVector data() const; - - /*! - * Sets the FLAC metadata block type. - */ - void setData(const ByteVector &data); - - /*! - * Render the content of the block. - */ - ByteVector render() const; - - private: - UnknownMetadataBlock(const MetadataBlock &item); - UnknownMetadataBlock &operator=(const MetadataBlock &item); - - class UnknownMetadataBlockPrivate; - UnknownMetadataBlockPrivate *d; - }; - - } - -} - -#endif diff --git a/taglib/taglib/it/itfile.cpp b/taglib/taglib/it/itfile.cpp deleted file mode 100644 index ad5cf0b..0000000 --- a/taglib/taglib/it/itfile.cpp +++ /dev/null @@ -1,330 +0,0 @@ -/*************************************************************************** - copyright : (C) 2011 by Mathias Panzenböck - email : grosser.meister.morti@gmx.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * - ***************************************************************************/ - -#include "tstringlist.h" -#include "itfile.h" -#include "tdebug.h" -#include "modfileprivate.h" -#include "tpropertymap.h" - -using namespace TagLib; -using namespace IT; - -class IT::File::FilePrivate -{ -public: - FilePrivate(AudioProperties::ReadStyle propertiesStyle) - : tag(), properties(propertiesStyle) - { - } - - Mod::Tag tag; - IT::Properties properties; -}; - -IT::File::File(FileName file, bool readProperties, - AudioProperties::ReadStyle propertiesStyle) : - Mod::FileBase(file), - d(new FilePrivate(propertiesStyle)) -{ - if(isOpen()) - read(readProperties); -} - -IT::File::File(IOStream *stream, bool readProperties, - AudioProperties::ReadStyle propertiesStyle) : - Mod::FileBase(stream), - d(new FilePrivate(propertiesStyle)) -{ - if(isOpen()) - read(readProperties); -} - -IT::File::~File() -{ - delete d; -} - -Mod::Tag *IT::File::tag() const -{ - return &d->tag; -} - -PropertyMap IT::File::properties() const -{ - return d->tag.properties(); -} - -PropertyMap IT::File::setProperties(const PropertyMap &properties) -{ - return d->tag.setProperties(properties); -} - -IT::Properties *IT::File::audioProperties() const -{ - return &d->properties; -} - -bool IT::File::save() -{ - if(readOnly()) - { - debug("IT::File::save() - Cannot save to a read only file."); - return false; - } - seek(4); - writeString(d->tag.title(), 25); - writeByte(0); - - seek(2, Current); - - ushort length = 0; - ushort instrumentCount = 0; - ushort sampleCount = 0; - - if(!readU16L(length) || !readU16L(instrumentCount) || !readU16L(sampleCount)) - return false; - - seek(15, Current); - - // write comment as instrument and sample names: - StringList lines = d->tag.comment().split("\n"); - for(ushort i = 0; i < instrumentCount; ++ i) { - seek(192L + length + ((long)i << 2)); - ulong instrumentOffset = 0; - if(!readU32L(instrumentOffset)) - return false; - - seek(instrumentOffset + 32); - - if(i < lines.size()) - writeString(lines[i], 25); - else - writeString(String::null, 25); - writeByte(0); - } - - for(ushort i = 0; i < sampleCount; ++ i) { - seek(192L + length + ((long)instrumentCount << 2) + ((long)i << 2)); - ulong sampleOffset = 0; - if(!readU32L(sampleOffset)) - return false; - - seek(sampleOffset + 20); - - if((TagLib::uint)(i + instrumentCount) < lines.size()) - writeString(lines[i + instrumentCount], 25); - else - writeString(String::null, 25); - writeByte(0); - } - - // write rest as message: - StringList messageLines; - for(uint i = instrumentCount + sampleCount; i < lines.size(); ++ i) - messageLines.append(lines[i]); - ByteVector message = messageLines.toString("\r").data(String::Latin1); - - // it's actually not really stated if the message needs a - // terminating NUL but it does not hurt to add one: - if(message.size() > 7999) - message.resize(7999); - message.append((char)0); - - ushort special = 0; - ushort messageLength = 0; - ulong messageOffset = 0; - - seek(46); - if(!readU16L(special)) - return false; - - ulong fileSize = File::length(); - if(special & Properties::MessageAttached) { - seek(54); - if(!readU16L(messageLength) || !readU32L(messageOffset)) - return false; - - if(messageLength == 0) - messageOffset = fileSize; - } - else - { - messageOffset = fileSize; - seek(46); - writeU16L(special | 0x1); - } - - if(messageOffset + messageLength >= fileSize) { - // append new message - seek(54); - writeU16L(message.size()); - writeU32L(messageOffset); - seek(messageOffset); - writeBlock(message); - truncate(messageOffset + message.size()); - } - else { - // Only overwrite existing message. - // I'd need to parse (understand!) the whole file for more. - // Although I could just move the message to the end of file - // and let the existing one be, but that would waste space. - message.resize(messageLength, 0); - seek(messageOffset); - writeBlock(message); - } - return true; -} - -void IT::File::read(bool) -{ - if(!isOpen()) - return; - - seek(0); - READ_ASSERT(readBlock(4) == "IMPM"); - READ_STRING(d->tag.setTitle, 26); - - seek(2, Current); - - READ_U16L_AS(length); - READ_U16L_AS(instrumentCount); - READ_U16L_AS(sampleCount); - - d->properties.setInstrumentCount(instrumentCount); - d->properties.setSampleCount(sampleCount); - READ_U16L(d->properties.setPatternCount); - READ_U16L(d->properties.setVersion); - READ_U16L(d->properties.setCompatibleVersion); - READ_U16L(d->properties.setFlags); - READ_U16L_AS(special); - d->properties.setSpecial(special); - READ_BYTE(d->properties.setGlobalVolume); - READ_BYTE(d->properties.setMixVolume); - READ_BYTE(d->properties.setBpmSpeed); - READ_BYTE(d->properties.setTempo); - READ_BYTE(d->properties.setPanningSeparation); - READ_BYTE(d->properties.setPitchWheelDepth); - - // IT supports some kind of comment tag. Still, the - // sample/instrument names are abused as comments so - // I just add all together. - String message; - if(special & Properties::MessageAttached) { - READ_U16L_AS(messageLength); - READ_U32L_AS(messageOffset); - seek(messageOffset); - ByteVector messageBytes = readBlock(messageLength); - READ_ASSERT(messageBytes.size() == messageLength); - int index = messageBytes.find((char) 0); - if(index > -1) - messageBytes.resize(index, 0); - messageBytes.replace('\r', '\n'); - message = messageBytes; - } - - seek(64); - - ByteVector pannings = readBlock(64); - ByteVector volumes = readBlock(64); - READ_ASSERT(pannings.size() == 64 && volumes.size() == 64); - int channels = 0; - for(int i = 0; i < 64; ++ i) { - // Strictly speaking an IT file has always 64 channels, but - // I don't count disabled and muted channels. - // But this always gives 64 channels for all my files anyway. - // Strangely VLC does report other values. I wonder how VLC - // gets it's values. - if((unsigned char) pannings[i] < 128 && volumes[i] > 0) - ++channels; - } - d->properties.setChannels(channels); - - // real length might be shorter because of skips and terminator - ushort realLength = 0; - for(ushort i = 0; i < length; ++ i) { - READ_BYTE_AS(order); - if(order == 255) break; - if(order != 254) ++ realLength; - } - d->properties.setLengthInPatterns(realLength); - - StringList comment; - // Note: I found files that have nil characters somewhere - // in the instrument/sample names and more characters - // afterwards. The spec does not mention such a case. - // Currently I just discard anything after a nil, but - // e.g. VLC seems to interprete a nil as a space. I - // don't know what is the proper behaviour. - for(ushort i = 0; i < instrumentCount; ++ i) { - seek(192L + length + ((long)i << 2)); - READ_U32L_AS(instrumentOffset); - seek(instrumentOffset); - - ByteVector instrumentMagic = readBlock(4); - READ_ASSERT(instrumentMagic == "IMPI"); - - READ_STRING_AS(dosFileName, 13); - - seek(15, Current); - - READ_STRING_AS(instrumentName, 26); - comment.append(instrumentName); - } - - for(ushort i = 0; i < sampleCount; ++ i) { - seek(192L + length + ((long)instrumentCount << 2) + ((long)i << 2)); - READ_U32L_AS(sampleOffset); - - seek(sampleOffset); - - ByteVector sampleMagic = readBlock(4); - READ_ASSERT(sampleMagic == "IMPS"); - - READ_STRING_AS(dosFileName, 13); - READ_BYTE_AS(globalVolume); - READ_BYTE_AS(sampleFlags); - READ_BYTE_AS(sampleVolume); - READ_STRING_AS(sampleName, 26); - /* - READ_BYTE_AS(sampleCvt); - READ_BYTE_AS(samplePanning); - READ_U32L_AS(sampleLength); - READ_U32L_AS(loopStart); - READ_U32L_AS(loopStop); - READ_U32L_AS(c5speed); - READ_U32L_AS(sustainLoopStart); - READ_U32L_AS(sustainLoopEnd); - READ_U32L_AS(sampleDataOffset); - READ_BYTE_AS(vibratoSpeed); - READ_BYTE_AS(vibratoDepth); - READ_BYTE_AS(vibratoRate); - READ_BYTE_AS(vibratoType); - */ - - comment.append(sampleName); - } - - if(message.size() > 0) - comment.append(message); - d->tag.setComment(comment.toString("\n")); - d->tag.setTrackerName("Impulse Tracker"); -} diff --git a/taglib/taglib/it/itfile.h b/taglib/taglib/it/itfile.h deleted file mode 100644 index 19327dc..0000000 --- a/taglib/taglib/it/itfile.h +++ /dev/null @@ -1,109 +0,0 @@ -/*************************************************************************** - copyright : (C) 2011 by Mathias Panzenböck - email : grosser.meister.morti@gmx.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef TAGLIB_ITFILE_H -#define TAGLIB_ITFILE_H - -#include "tfile.h" -#include "audioproperties.h" -#include "taglib_export.h" -#include "modfilebase.h" -#include "modtag.h" -#include "itproperties.h" - -namespace TagLib { - - namespace IT { - - class TAGLIB_EXPORT File : public Mod::FileBase { - public: - /*! - * 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); - - /*! - * 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 *stream, bool readProperties = true, - AudioProperties::ReadStyle propertiesStyle = - AudioProperties::Average); - - /*! - * Destroys this instance of the File. - */ - virtual ~File(); - - Mod::Tag *tag() const; - - /*! - * Forwards to Mod::Tag::properties(). - * BIC: will be removed once File::toDict() is made virtual - */ - PropertyMap properties() const; - - /*! - * Forwards to Mod::Tag::setProperties(). - * BIC: will be removed once File::setProperties() is made virtual - */ - PropertyMap setProperties(const PropertyMap &); - - /*! - * Returns the IT::Properties for this file. If no audio properties - * were read then this will return a null pointer. - */ - IT::Properties *audioProperties() const; - - /*! - * Save the file. - * This is the same as calling save(AllTags); - * - * \note Saving Impulse Tracker tags is not supported. - */ - bool save(); - - - private: - File(const File &); - File &operator=(const File &); - - void read(bool readProperties); - - class FilePrivate; - FilePrivate *d; - }; - } -} - -#endif diff --git a/taglib/taglib/it/itproperties.cpp b/taglib/taglib/it/itproperties.cpp deleted file mode 100644 index 7a328fb..0000000 --- a/taglib/taglib/it/itproperties.cpp +++ /dev/null @@ -1,245 +0,0 @@ -/*************************************************************************** - copyright :(C) 2011 by Mathias Panzenböck - email : grosser.meister.morti@gmx.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * - ***************************************************************************/ - -#include "itproperties.h" - -using namespace TagLib; -using namespace IT; - -class IT::Properties::PropertiesPrivate -{ -public: - PropertiesPrivate() : - channels(0), - lengthInPatterns(0), - instrumentCount(0), - sampleCount(0), - patternCount(0), - version(0), - compatibleVersion(0), - flags(0), - special(0), - globalVolume(0), - mixVolume(0), - tempo(0), - bpmSpeed(0), - panningSeparation(0), - pitchWheelDepth(0) - { - } - - int channels; - ushort lengthInPatterns; - ushort instrumentCount; - ushort sampleCount; - ushort patternCount; - ushort version; - ushort compatibleVersion; - ushort flags; - ushort special; - uchar globalVolume; - uchar mixVolume; - uchar tempo; - uchar bpmSpeed; - uchar panningSeparation; - uchar pitchWheelDepth; -}; - -IT::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) : - AudioProperties(propertiesStyle), - d(new PropertiesPrivate) -{ -} - -IT::Properties::~Properties() -{ - delete d; -} - -int IT::Properties::length() const -{ - return 0; -} - -int IT::Properties::bitrate() const -{ - return 0; -} - -int IT::Properties::sampleRate() const -{ - return 0; -} - -int IT::Properties::channels() const -{ - return d->channels; -} - -TagLib::ushort IT::Properties::lengthInPatterns() const -{ - return d->lengthInPatterns; -} - -bool IT::Properties::stereo() const -{ - return d->flags & Stereo; -} - -TagLib::ushort IT::Properties::instrumentCount() const -{ - return d->instrumentCount; -} - -TagLib::ushort IT::Properties::sampleCount() const -{ - return d->sampleCount; -} - -TagLib::ushort IT::Properties::patternCount() const -{ - return d->patternCount; -} - -TagLib::ushort IT::Properties::version() const -{ - return d->version; -} - -TagLib::ushort IT::Properties::compatibleVersion() const -{ - return d->compatibleVersion; -} - -TagLib::ushort IT::Properties::flags() const -{ - return d->flags; -} - -TagLib::ushort IT::Properties::special() const -{ - return d->special; -} - -uchar IT::Properties::globalVolume() const -{ - return d->globalVolume; -} - -uchar IT::Properties::mixVolume() const -{ - return d->mixVolume; -} - -uchar IT::Properties::tempo() const -{ - return d->tempo; -} - -uchar IT::Properties::bpmSpeed() const -{ - return d->bpmSpeed; -} - -uchar IT::Properties::panningSeparation() const -{ - return d->panningSeparation; -} - -uchar IT::Properties::pitchWheelDepth() const -{ - return d->pitchWheelDepth; -} - -void IT::Properties::setChannels(int channels) -{ - d->channels = channels; -} - -void IT::Properties::setLengthInPatterns(ushort lengthInPatterns) -{ - d->lengthInPatterns = lengthInPatterns; -} - -void IT::Properties::setInstrumentCount(ushort instrumentCount) -{ - d->instrumentCount = instrumentCount; -} - -void IT::Properties::setSampleCount(ushort sampleCount) -{ - d->sampleCount = sampleCount; -} - -void IT::Properties::setPatternCount(ushort patternCount) -{ - d->patternCount = patternCount; -} - -void IT::Properties::setFlags(ushort flags) -{ - d->flags = flags; -} - -void IT::Properties::setSpecial(ushort special) -{ - d->special = special; -} - -void IT::Properties::setCompatibleVersion(ushort compatibleVersion) -{ - d->compatibleVersion = compatibleVersion; -} - -void IT::Properties::setVersion(ushort version) -{ - d->version = version; -} - -void IT::Properties::setGlobalVolume(uchar globalVolume) -{ - d->globalVolume = globalVolume; -} - -void IT::Properties::setMixVolume(uchar mixVolume) -{ - d->mixVolume = mixVolume; -} - -void IT::Properties::setTempo(uchar tempo) -{ - d->tempo = tempo; -} - -void IT::Properties::setBpmSpeed(uchar bpmSpeed) -{ - d->bpmSpeed = bpmSpeed; -} - -void IT::Properties::setPanningSeparation(uchar panningSeparation) -{ - d->panningSeparation = panningSeparation; -} - -void IT::Properties::setPitchWheelDepth(uchar pitchWheelDepth) -{ - d->pitchWheelDepth = pitchWheelDepth; -} diff --git a/taglib/taglib/it/itproperties.h b/taglib/taglib/it/itproperties.h deleted file mode 100644 index da2a7c4..0000000 --- a/taglib/taglib/it/itproperties.h +++ /dev/null @@ -1,101 +0,0 @@ -/*************************************************************************** - copyright : (C) 2011 by Mathias Panzenböck - email : grosser.meister.morti@gmx.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef TAGLIB_ITPROPERTIES_H -#define TAGLIB_ITPROPERTIES_H - -#include "taglib.h" -#include "audioproperties.h" - -namespace TagLib { - namespace IT { - class TAGLIB_EXPORT Properties : public AudioProperties { - friend class File; - public: - /*! Flag bits. */ - enum { - Stereo = 1, - Vol0MixOptimizations = 2, - UseInstruments = 4, - LinearSlides = 8, - OldEffects = 16, - LinkEffects = 32, - UseMidiPitchController = 64, - RequestEmbeddedMidiConf = 128 - }; - - /*! Special bits. */ - enum { - MessageAttached = 1, - MidiConfEmbedded = 8 - }; - - Properties(AudioProperties::ReadStyle propertiesStyle); - virtual ~Properties(); - - int length() const; - int bitrate() const; - int sampleRate() const; - int channels() const; - - ushort lengthInPatterns() const; - bool stereo() const; - ushort instrumentCount() const; - ushort sampleCount() const; - ushort patternCount() const; - ushort version() const; - ushort compatibleVersion() const; - ushort flags() const; - ushort special() const; - uchar globalVolume() const; - uchar mixVolume() const; - uchar tempo() const; - uchar bpmSpeed() const; - uchar panningSeparation() const; - uchar pitchWheelDepth() const; - - void setChannels(int channels); - void setLengthInPatterns(ushort lengthInPatterns); - void setInstrumentCount(ushort instrumentCount); - void setSampleCount (ushort sampleCount); - void setPatternCount(ushort patternCount); - void setVersion (ushort version); - void setCompatibleVersion(ushort compatibleVersion); - void setFlags (ushort flags); - void setSpecial (ushort special); - void setGlobalVolume(uchar globalVolume); - void setMixVolume (uchar mixVolume); - void setTempo (uchar tempo); - void setBpmSpeed (uchar bpmSpeed); - void setPanningSeparation(uchar panningSeparation); - void setPitchWheelDepth (uchar pitchWheelDepth); - - private: - Properties(const Properties&); - Properties &operator=(const Properties&); - - class PropertiesPrivate; - PropertiesPrivate *d; - }; - } -} - -#endif diff --git a/taglib/taglib/mod/modfile.cpp b/taglib/taglib/mod/modfile.cpp deleted file mode 100644 index ce974c1..0000000 --- a/taglib/taglib/mod/modfile.cpp +++ /dev/null @@ -1,187 +0,0 @@ -/*************************************************************************** - copyright : (C) 2011 by Mathias Panzenböck - email : grosser.meister.morti@gmx.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * - ***************************************************************************/ - -#include "modfile.h" -#include "tstringlist.h" -#include "tdebug.h" -#include "modfileprivate.h" -#include "tpropertymap.h" - -using namespace TagLib; -using namespace Mod; - -class Mod::File::FilePrivate -{ -public: - FilePrivate(AudioProperties::ReadStyle propertiesStyle) - : properties(propertiesStyle) - { - } - - Mod::Tag tag; - Mod::Properties properties; -}; - -Mod::File::File(FileName file, bool readProperties, - AudioProperties::ReadStyle propertiesStyle) : - Mod::FileBase(file), - d(new FilePrivate(propertiesStyle)) -{ - if(isOpen()) - read(readProperties); -} - -Mod::File::File(IOStream *stream, bool readProperties, - AudioProperties::ReadStyle propertiesStyle) : - Mod::FileBase(stream), - d(new FilePrivate(propertiesStyle)) -{ - if(isOpen()) - read(readProperties); -} - -Mod::File::~File() -{ - delete d; -} - -Mod::Tag *Mod::File::tag() const -{ - return &d->tag; -} - -Mod::Properties *Mod::File::audioProperties() const -{ - return &d->properties; -} - -PropertyMap Mod::File::properties() const -{ - return d->tag.properties(); -} - -PropertyMap Mod::File::setProperties(const PropertyMap &properties) -{ - return d->tag.setProperties(properties); -} - -bool Mod::File::save() -{ - if(readOnly()) { - debug("Mod::File::save() - Cannot save to a read only file."); - return false; - } - seek(0); - writeString(d->tag.title(), 20); - StringList lines = d->tag.comment().split("\n"); - uint n = std::min(lines.size(), d->properties.instrumentCount()); - for(uint i = 0; i < n; ++ i) { - writeString(lines[i], 22); - seek(8, Current); - } - - for(uint i = n; i < d->properties.instrumentCount(); ++ i) { - writeString(String::null, 22); - seek(8, Current); - } - return true; -} - -void Mod::File::read(bool) -{ - if(!isOpen()) - return; - - seek(1080); - ByteVector modId = readBlock(4); - READ_ASSERT(modId.size() == 4); - - int channels = 4; - uint instruments = 31; - if(modId == "M.K." || modId == "M!K!" || modId == "M&K!" || modId == "N.T.") { - d->tag.setTrackerName("ProTracker"); - channels = 4; - } - else if(modId.startsWith("FLT") || modId.startsWith("TDZ")) { - d->tag.setTrackerName("StarTrekker"); - char digit = modId[3]; - READ_ASSERT(digit >= '0' && digit <= '9'); - channels = digit - '0'; - } - else if(modId.endsWith("CHN")) { - d->tag.setTrackerName("StarTrekker"); - char digit = modId[0]; - READ_ASSERT(digit >= '0' && digit <= '9'); - channels = digit - '0'; - } - else if(modId == "CD81" || modId == "OKTA") { - d->tag.setTrackerName("Atari Oktalyzer"); - channels = 8; - } - else if(modId.endsWith("CH") || modId.endsWith("CN")) { - d->tag.setTrackerName("TakeTracker"); - char digit = modId[0]; - READ_ASSERT(digit >= '0' && digit <= '9'); - channels = (digit - '0') * 10; - digit = modId[1]; - READ_ASSERT(digit >= '0' && digit <= '9'); - channels += digit - '0'; - } - else { - // Not sure if this is correct. I'd need a file - // created with NoiseTracker to check this. - d->tag.setTrackerName("NoiseTracker"); // probably - channels = 4; - instruments = 15; - } - d->properties.setChannels(channels); - d->properties.setInstrumentCount(instruments); - - seek(0); - READ_STRING(d->tag.setTitle, 20); - - StringList comment; - for(uint i = 0; i < instruments; ++ i) { - READ_STRING_AS(instrumentName, 22); - // value in words, * 2 (<< 1) for bytes: - READ_U16B_AS(sampleLength); - - READ_BYTE_AS(fineTuneByte); - int fineTune = fineTuneByte & 0xF; - // > 7 means negative value - if(fineTune > 7) fineTune -= 16; - - READ_BYTE_AS(volume); - if(volume > 64) volume = 64; - // volume in decibels: 20 * log10(volume / 64) - - // value in words, * 2 (<< 1) for bytes: - READ_U16B_AS(repeatStart); - // value in words, * 2 (<< 1) for bytes: - READ_U16B_AS(repatLength); - - comment.append(instrumentName); - } - - READ_BYTE(d->properties.setLengthInPatterns); - - d->tag.setComment(comment.toString("\n")); -} diff --git a/taglib/taglib/mod/modfile.h b/taglib/taglib/mod/modfile.h deleted file mode 100644 index c45ede2..0000000 --- a/taglib/taglib/mod/modfile.h +++ /dev/null @@ -1,110 +0,0 @@ -/*************************************************************************** - copyright : (C) 2011 by Mathias Panzenböck - email : grosser.meister.morti@gmx.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef TAGLIB_MODFILE_H -#define TAGLIB_MODFILE_H - -#include "tfile.h" -#include "audioproperties.h" -#include "taglib_export.h" -#include "modfilebase.h" -#include "modtag.h" -#include "modproperties.h" - -namespace TagLib { - - namespace Mod { - - class TAGLIB_EXPORT File : public TagLib::Mod::FileBase - { - public: - /*! - * Constructs a Protracker file from \a file. - * - * \note In the current implementation, both \a readProperties and - * \a propertiesStyle are ignored. The audio properties are always - * read. - */ - File(FileName file, bool readProperties = true, - AudioProperties::ReadStyle propertiesStyle = - AudioProperties::Average); - - /*! - * Constructs a Protracker file from \a stream. - * - * \note In the current implementation, both \a readProperties and - * \a propertiesStyle are ignored. The audio properties are always - * read. - * - * \note TagLib will *not* take ownership of the stream, the caller is - * responsible for deleting it after the File object. - */ - File(IOStream *stream, bool readProperties = true, - AudioProperties::ReadStyle propertiesStyle = - AudioProperties::Average); - - /*! - * Destroys this instance of the File. - */ - virtual ~File(); - - Mod::Tag *tag() const; - - /*! - * Implements the unified property interface -- export function. - * Forwards to Mod::Tag::properties(). - */ - PropertyMap properties() const; - - /*! - * Implements the unified property interface -- import function. - * Forwards to Mod::Tag::setProperties(). - */ - PropertyMap setProperties(const PropertyMap &); - /*! - * Returns the Mod::Properties for this file. If no audio properties - * were read then this will return a null pointer. - */ - Mod::Properties *audioProperties() const; - - /*! - * Save the file. - * This is the same as calling save(AllTags); - * - * \note Saving Protracker tags is not supported. - */ - bool save(); - - private: - File(const File &); - File &operator=(const File &); - - void read(bool readProperties); - - class FilePrivate; - FilePrivate *d; - }; - - } - -} - -#endif diff --git a/taglib/taglib/mod/modfilebase.cpp b/taglib/taglib/mod/modfilebase.cpp deleted file mode 100644 index e074dac..0000000 --- a/taglib/taglib/mod/modfilebase.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/*************************************************************************** - copyright : (C) 2011 by Mathias Panzenböck - email : grosser.meister.morti@gmx.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * - ***************************************************************************/ - -#include "tdebug.h" -#include "modfilebase.h" - -using namespace TagLib; -using namespace Mod; - -Mod::FileBase::FileBase(FileName file) : TagLib::File(file) -{ -} - -Mod::FileBase::FileBase(IOStream *stream) : TagLib::File(stream) -{ -} - -void Mod::FileBase::writeString(const String &s, ulong size, char padding) -{ - ByteVector data(s.data(String::Latin1)); - data.resize(size, padding); - writeBlock(data); -} - -bool Mod::FileBase::readString(String &s, ulong size) -{ - ByteVector data(readBlock(size)); - if(data.size() < size) return false; - int index = data.find((char) 0); - if(index > -1) - { - data.resize(index); - } - data.replace((char) 0xff, ' '); - - s = data; - return true; -} - -void Mod::FileBase::writeByte(uchar byte) -{ - ByteVector data(1, byte); - writeBlock(data); -} - -void Mod::FileBase::writeU16L(ushort number) -{ - writeBlock(ByteVector::fromShort(number, false)); -} - -void Mod::FileBase::writeU32L(ulong number) -{ - writeBlock(ByteVector::fromUInt(number, false)); -} - -void Mod::FileBase::writeU16B(ushort number) -{ - writeBlock(ByteVector::fromShort(number, true)); -} - -void Mod::FileBase::writeU32B(ulong number) -{ - writeBlock(ByteVector::fromUInt(number, true)); -} - -bool Mod::FileBase::readByte(uchar &byte) -{ - ByteVector data(readBlock(1)); - if(data.size() < 1) return false; - byte = data[0]; - return true; -} - -bool Mod::FileBase::readU16L(ushort &number) -{ - ByteVector data(readBlock(2)); - if(data.size() < 2) return false; - number = data.toUShort(false); - return true; -} - -bool Mod::FileBase::readU32L(ulong &number) { - ByteVector data(readBlock(4)); - if(data.size() < 4) return false; - number = data.toUInt(false); - return true; -} - -bool Mod::FileBase::readU16B(ushort &number) -{ - ByteVector data(readBlock(2)); - if(data.size() < 2) return false; - number = data.toUShort(true); - return true; -} - -bool Mod::FileBase::readU32B(ulong &number) { - ByteVector data(readBlock(4)); - if(data.size() < 4) return false; - number = data.toUInt(true); - return true; -} diff --git a/taglib/taglib/mod/modfilebase.h b/taglib/taglib/mod/modfilebase.h deleted file mode 100644 index 383bde1..0000000 --- a/taglib/taglib/mod/modfilebase.h +++ /dev/null @@ -1,62 +0,0 @@ -/*************************************************************************** - copyright : (C) 2011 by Mathias Panzenböck - email : grosser.meister.morti@gmx.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef TAGLIB_MODFILEBASE_H -#define TAGLIB_MODFILEBASE_H - -#include "taglib.h" -#include "tfile.h" -#include "tstring.h" -#include "tlist.h" -#include "taglib_export.h" - -#include <algorithm> - -namespace TagLib { - - namespace Mod { - - class TAGLIB_EXPORT FileBase : public TagLib::File - { - protected: - FileBase(FileName file); - FileBase(IOStream *stream); - - void writeString(const String &s, ulong size, char padding = 0); - void writeByte(uchar byte); - void writeU16L(ushort number); - void writeU32L(ulong number); - void writeU16B(ushort number); - void writeU32B(ulong number); - - bool readString(String &s, ulong size); - bool readByte(uchar &byte); - bool readU16L(ushort &number); - bool readU32L(ulong &number); - bool readU16B(ushort &number); - bool readU32B(ulong &number); - }; - - } - -} - -#endif diff --git a/taglib/taglib/mod/modfileprivate.h b/taglib/taglib/mod/modfileprivate.h deleted file mode 100644 index 19a3001..0000000 --- a/taglib/taglib/mod/modfileprivate.h +++ /dev/null @@ -1,67 +0,0 @@ -/*************************************************************************** - copyright : (C) 2011 by Mathias Panzenböck - email : grosser.meister.morti@gmx.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef TAGLIB_MODFILEPRIVATE_H -#define TAGLIB_MODFILEPRIVATE_H - -// some helper-macros only used internally by (s3m|it|xm)file.cpp -#define READ_ASSERT(cond) \ - if(!(cond)) \ - { \ - setValid(false); \ - return; \ - } - -#define READ(setter,type,read) \ - { \ - type number; \ - READ_ASSERT(read(number)); \ - setter(number); \ - } - -#define READ_BYTE(setter) READ(setter,uchar,readByte) -#define READ_U16L(setter) READ(setter,ushort,readU16L) -#define READ_U32L(setter) READ(setter,ulong,readU32L) -#define READ_U16B(setter) READ(setter,ushort,readU16B) -#define READ_U32B(setter) READ(setter,ulong,readU32B) - -#define READ_STRING(setter,size) \ - { \ - String s; \ - READ_ASSERT(readString(s, size)); \ - setter(s); \ - } - -#define READ_AS(type,name,read) \ - type name = 0; \ - READ_ASSERT(read(name)); - -#define READ_BYTE_AS(name) READ_AS(uchar,name,readByte) -#define READ_U16L_AS(name) READ_AS(ushort,name,readU16L) -#define READ_U32L_AS(name) READ_AS(ulong,name,readU32L) -#define READ_U16B_AS(name) READ_AS(ushort,name,readU16B) -#define READ_U32B_AS(name) READ_AS(ulong,name,readU32B) - -#define READ_STRING_AS(name,size) \ - String name; \ - READ_ASSERT(readString(name, size)); - -#endif diff --git a/taglib/taglib/mod/modproperties.cpp b/taglib/taglib/mod/modproperties.cpp deleted file mode 100644 index 4d3c354..0000000 --- a/taglib/taglib/mod/modproperties.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/*************************************************************************** - copyright : (C) 2011 by Mathias Panzenböck - email : grosser.meister.morti@gmx.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * - ***************************************************************************/ - -#include "modproperties.h" - -using namespace TagLib; -using namespace Mod; - -class Mod::Properties::PropertiesPrivate -{ -public: - PropertiesPrivate() : - channels(0), - instrumentCount(0), - lengthInPatterns(0) - { - } - - int channels; - uint instrumentCount; - uchar lengthInPatterns; -}; - -Mod::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) : - AudioProperties(propertiesStyle), - d(new PropertiesPrivate) -{ -} - -Mod::Properties::~Properties() -{ - delete d; -} - -int Mod::Properties::length() const -{ - return 0; -} - -int Mod::Properties::bitrate() const -{ - return 0; -} - -int Mod::Properties::sampleRate() const -{ - return 0; -} - -int Mod::Properties::channels() const -{ - return d->channels; -} - -TagLib::uint Mod::Properties::instrumentCount() const -{ - return d->instrumentCount; -} - -uchar Mod::Properties::lengthInPatterns() const -{ - return d->lengthInPatterns; -} - -void Mod::Properties::setChannels(int channels) -{ - d->channels = channels; -} - -void Mod::Properties::setInstrumentCount(uint instrumentCount) -{ - d->instrumentCount = instrumentCount; -} - -void Mod::Properties::setLengthInPatterns(uchar lengthInPatterns) -{ - d->lengthInPatterns = lengthInPatterns; -} diff --git a/taglib/taglib/mod/modproperties.h b/taglib/taglib/mod/modproperties.h deleted file mode 100644 index d50353a..0000000 --- a/taglib/taglib/mod/modproperties.h +++ /dev/null @@ -1,65 +0,0 @@ -/*************************************************************************** - copyright : (C) 2011 by Mathias Panzenböck - email : grosser.meister.morti@gmx.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef TAGLIB_MODPROPERTIES_H -#define TAGLIB_MODPROPERTIES_H - -#include "taglib.h" -#include "audioproperties.h" - -namespace TagLib { - - namespace Mod { - - class TAGLIB_EXPORT Properties : public AudioProperties - { - public: - Properties(AudioProperties::ReadStyle propertiesStyle); - virtual ~Properties(); - - int length() const; - int bitrate() const; - int sampleRate() const; - int channels() const; - - uint instrumentCount() const; - uchar lengthInPatterns() const; - - void setChannels(int channels); - - void setInstrumentCount(uint sampleCount); - void setLengthInPatterns(uchar lengthInPatterns); - - private: - friend class File; - - Properties(const Properties&); - Properties &operator=(const Properties&); - - class PropertiesPrivate; - PropertiesPrivate *d; - }; - - } - -} - -#endif diff --git a/taglib/taglib/mod/modtag.cpp b/taglib/taglib/mod/modtag.cpp deleted file mode 100644 index 14c4c74..0000000 --- a/taglib/taglib/mod/modtag.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/*************************************************************************** - copyright : (C) 2011 by Mathias Panzenböck - email : grosser.meister.morti@gmx.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * - ***************************************************************************/ - -#include "modtag.h" -#include "tstringlist.h" -#include "tpropertymap.h" - -using namespace TagLib; -using namespace Mod; - -class Mod::Tag::TagPrivate -{ -public: - TagPrivate() - { - } - - String title; - String comment; - String trackerName; -}; - -Mod::Tag::Tag() : TagLib::Tag() -{ - d = new TagPrivate; -} - -Mod::Tag::~Tag() -{ - delete d; -} - -String Mod::Tag::title() const -{ - return d->title; -} - -String Mod::Tag::artist() const -{ - return String::null; -} - -String Mod::Tag::album() const -{ - return String::null; -} - -String Mod::Tag::comment() const -{ - return d->comment; -} - -String Mod::Tag::genre() const -{ - return String::null; -} - -TagLib::uint Mod::Tag::year() const -{ - return 0; -} - -TagLib::uint Mod::Tag::track() const -{ - return 0; -} - -String Mod::Tag::trackerName() const -{ - return d->trackerName; -} - -void Mod::Tag::setTitle(const String &title) -{ - d->title = title; -} - -void Mod::Tag::setArtist(const String &) -{ -} - -void Mod::Tag::setAlbum(const String &) -{ -} - -void Mod::Tag::setComment(const String &comment) -{ - d->comment = comment; -} - -void Mod::Tag::setGenre(const String &) -{ -} - -void Mod::Tag::setYear(uint) -{ -} - -void Mod::Tag::setTrack(uint) -{ -} - -void Mod::Tag::setTrackerName(const String &trackerName) -{ - d->trackerName = trackerName; -} - -PropertyMap Mod::Tag::properties() const -{ - PropertyMap properties; - properties["TITLE"] = d->title; - properties["COMMENT"] = d->comment; - if(!(d->trackerName.isNull())) - properties["TRACKERNAME"] = d->trackerName; - return properties; -} - -PropertyMap Mod::Tag::setProperties(const PropertyMap &origProps) -{ - PropertyMap properties(origProps); - properties.removeEmpty(); - StringList oneValueSet; - if(properties.contains("TITLE")) { - d->title = properties["TITLE"].front(); - oneValueSet.append("TITLE"); - } else - d->title = String::null; - - if(properties.contains("COMMENT")) { - d->comment = properties["COMMENT"].front(); - oneValueSet.append("COMMENT"); - } else - d->comment = String::null; - - if(properties.contains("TRACKERNAME")) { - d->trackerName = properties["TRACKERNAME"].front(); - oneValueSet.append("TRACKERNAME"); - } else - d->trackerName = String::null; - - // for each tag that has been set above, remove the first entry in the corresponding - // value list. The others will be returned as unsupported by this format. - for(StringList::Iterator it = oneValueSet.begin(); it != oneValueSet.end(); ++it) { - if(properties[*it].size() == 1) - properties.erase(*it); - else - properties[*it].erase( properties[*it].begin() ); - } - return properties; -} diff --git a/taglib/taglib/mod/modtag.h b/taglib/taglib/mod/modtag.h deleted file mode 100644 index f33e33f..0000000 --- a/taglib/taglib/mod/modtag.h +++ /dev/null @@ -1,190 +0,0 @@ -/*************************************************************************** - copyright : (C) 2011 by Mathias Panzenböck - email : grosser.meister.morti@gmx.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef TAGLIB_MODTAG_H -#define TAGLIB_MODTAG_H - -#include "tag.h" - -namespace TagLib { - - namespace Mod { - - /*! - * Tags for module files (Mod, S3M, IT, XM). - * - * Note that only the \a title is supported as such by most - * module file formats. Except for XM files the \a trackerName - * is derived from the file format or the flavour of the file - * format. For XM files it is stored in the file. - * - * The \a comment tag is not strictly supported by module files, - * but it is common practice to abuse instrument/sample/pattern - * names as multiline comments. TagLib does so as well. - */ - class TAGLIB_EXPORT Tag : public TagLib::Tag - { - public: - Tag(); - virtual ~Tag(); - - /*! - * Returns the track name; if no track name is present in the tag - * String::null will be returned. - */ - String title() const; - - /*! - * Not supported by module files. Therefore always returns String::null. - */ - String artist() const; - - /*! - * Not supported by module files. Therefore always returns String::null. - */ - String album() const; - - /*! - * Returns the track comment derived from the instrument/sample/pattern - * names; if no comment is present in the tag String::null will be - * returned. - */ - String comment() const; - - /*! - * Not supported by module files. Therefore always returns String::null. - */ - String genre() const; - - /*! - * Not supported by module files. Therefore always returns 0. - */ - uint year() const; - - /*! - * Not supported by module files. Therefore always returns 0. - */ - uint track() const; - - /*! - * Returns the name of the tracker used to create/edit the module file. - * Only XM files store this tag to the file as such, for other formats - * (Mod, S3M, IT) this is derived from the file type or the flavour of - * the file type. Therefore only XM files might have an empty - * (String::null) tracker name. - */ - String trackerName() const; - - /*! - * Sets the title to \a title. If \a title is String::null then this - * value will be cleared. - * - * The length limits per file type are (1 characetr = 1 byte): - * Mod 20 characters, S3M 27 characters, IT 25 characters and XM 20 - * characters. - */ - void setTitle(const String &title); - - /*! - * Not supported by module files and therefore ignored. - */ - void setArtist(const String &artist); - - /*! - * Not supported by module files and therefore ignored. - */ - void setAlbum(const String &album); - - /*! - * Sets the comment to \a comment. If \a comment is String::null then - * this value will be cleared. - * - * Note that module file formats don't actually support a comment tag. - * Instead the names of instruments/patterns/samples are abused as - * a multiline comment. Because of this the number of lines in a - * module file is fixed to the number of instruments/patterns/samples. - * - * Also note that the instrument/pattern/sample name length is limited - * an thus the line length in comments are limited. Too big comments - * will be truncated. - * - * The line length limits per file type are (1 characetr = 1 byte): - * Mod 22 characters, S3M 27 characters, IT 25 characters and XM 22 - * characters. - */ - void setComment(const String &comment); - - /*! - * Not supported by module files and therefore ignored. - */ - void setGenre(const String &genre); - - /*! - * Not supported by module files and therefore ignored. - */ - void setYear(uint year); - - /*! - * Not supported by module files and therefore ignored. - */ - void setTrack(uint track); - - /*! - * Sets the tracker name to \a trackerName. If \a trackerName is - * String::null then this value will be cleared. - * - * Note that only XM files support this tag. Setting the - * tracker name for other module file formats will be ignored. - * - * The length of this tag is limited to 20 characters (1 character - * = 1 byte). - */ - void setTrackerName(const String &trackerName); - - /*! - * Implements the unified property interface -- export function. - * Since the module tag is very limited, the exported map is as well. - */ - PropertyMap properties() const; - - /*! - * Implements the unified property interface -- import function. - * Because of the limitations of the module file tag, any tags besides - * COMMENT, TITLE and, if it is an XM file, TRACKERNAME, will be - * returened. Additionally, if the map contains tags with multiple values, - * all but the first will be contained in the returned map of unsupported - * properties. - */ - PropertyMap setProperties(const PropertyMap &); - - private: - Tag(const Tag &); - Tag &operator=(const Tag &); - - class TagPrivate; - TagPrivate *d; - }; - - } - -} - -#endif diff --git a/taglib/taglib/mp4/mp4atom.cpp b/taglib/taglib/mp4/mp4atom.cpp deleted file mode 100644 index 7b87a47..0000000 --- a/taglib/taglib/mp4/mp4atom.cpp +++ /dev/null @@ -1,194 +0,0 @@ -/************************************************************************** - copyright : (C) 2007 by Lukáš Lalinský - email : lalinsky@gmail.com - **************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <tdebug.h> -#include <tstring.h> -#include "mp4atom.h" - -using namespace TagLib; - -const char *MP4::Atom::containers[11] = { - "moov", "udta", "mdia", "meta", "ilst", - "stbl", "minf", "moof", "traf", "trak", - "stsd" -}; - -MP4::Atom::Atom(File *file) -{ - offset = file->tell(); - ByteVector header = file->readBlock(8); - if (header.size() != 8) { - // The atom header must be 8 bytes long, otherwise there is either - // trailing garbage or the file is truncated - debug("MP4: Couldn't read 8 bytes of data for atom header"); - length = 0; - file->seek(0, File::End); - return; - } - - length = header.toUInt(); - - if (length == 1) { - 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; - } - else { - debug("MP4: 64-bit atoms are not supported"); - length = 0; - file->seek(0, File::End); - return; - } - } - if (length < 8) { - debug("MP4: Invalid atom size"); - length = 0; - file->seek(0, File::End); - return; - } - - name = header.mid(4, 4); - - for(int i = 0; i < numContainers; i++) { - if(name == containers[i]) { - if(name == "meta") { - file->seek(4, File::Current); - } - else if(name == "stsd") { - file->seek(8, File::Current); - } - while(file->tell() < offset + length) { - MP4::Atom *child = new MP4::Atom(file); - children.append(child); - if (child->length == 0) - return; - } - return; - } - } - - file->seek(offset + length); -} - -MP4::Atom::~Atom() -{ - for(unsigned int i = 0; i < children.size(); i++) { - delete children[i]; - } - children.clear(); -} - -MP4::Atom * -MP4::Atom::find(const char *name1, const char *name2, const char *name3, const char *name4) -{ - if(name1 == 0) { - return this; - } - for(unsigned int i = 0; i < children.size(); i++) { - if(children[i]->name == name1) { - return children[i]->find(name2, name3, name4); - } - } - return 0; -} - -MP4::AtomList -MP4::Atom::findall(const char *name, bool recursive) -{ - MP4::AtomList result; - for(unsigned int i = 0; i < children.size(); i++) { - if(children[i]->name == name) { - result.append(children[i]); - } - if(recursive) { - result.append(children[i]->findall(name, recursive)); - } - } - return result; -} - -bool -MP4::Atom::path(MP4::AtomList &path, const char *name1, const char *name2, const char *name3) -{ - path.append(this); - if(name1 == 0) { - return true; - } - for(unsigned int i = 0; i < children.size(); i++) { - if(children[i]->name == name1) { - return children[i]->path(path, name2, name3); - } - } - return false; -} - -MP4::Atoms::Atoms(File *file) -{ - file->seek(0, File::End); - long end = file->tell(); - file->seek(0); - while(file->tell() + 8 <= end) { - MP4::Atom *atom = new MP4::Atom(file); - atoms.append(atom); - if (atom->length == 0) - break; - } -} - -MP4::Atoms::~Atoms() -{ - for(unsigned int i = 0; i < atoms.size(); i++) { - delete atoms[i]; - } - atoms.clear(); -} - -MP4::Atom * -MP4::Atoms::find(const char *name1, const char *name2, const char *name3, const char *name4) -{ - for(unsigned int i = 0; i < atoms.size(); i++) { - if(atoms[i]->name == name1) { - return atoms[i]->find(name2, name3, name4); - } - } - return 0; -} - -MP4::AtomList -MP4::Atoms::path(const char *name1, const char *name2, const char *name3, const char *name4) -{ - MP4::AtomList path; - for(unsigned int i = 0; i < atoms.size(); i++) { - if(atoms[i]->name == name1) { - if(!atoms[i]->path(path, name2, name3, name4)) { - path.clear(); - } - return path; - } - } - return path; -} - diff --git a/taglib/taglib/mp4/mp4atom.h b/taglib/taglib/mp4/mp4atom.h deleted file mode 100644 index ea5091a..0000000 --- a/taglib/taglib/mp4/mp4atom.h +++ /dev/null @@ -1,111 +0,0 @@ -/************************************************************************** - copyright : (C) 2007,2011 by Lukáš Lalinský - email : lalinsky@gmail.com - **************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -// This file is not part of the public API! - -#ifndef DO_NOT_DOCUMENT - -#ifndef TAGLIB_MP4ATOM_H -#define TAGLIB_MP4ATOM_H - -#include "tfile.h" -#include "tlist.h" - -namespace TagLib { - - namespace MP4 { - - class Atom; - typedef TagLib::List<Atom *> AtomList; - - enum AtomDataType - { - TypeImplicit = 0, // for use with tags for which no type needs to be indicated because only one type is allowed - TypeUTF8 = 1, // without any count or null terminator - TypeUTF16 = 2, // also known as UTF-16BE - TypeSJIS = 3, // deprecated unless it is needed for special Japanese characters - TypeHTML = 6, // the HTML file header specifies which HTML version - TypeXML = 7, // the XML header must identify the DTD or schemas - TypeUUID = 8, // also known as GUID; stored as 16 bytes in binary (valid as an ID) - TypeISRC = 9, // stored as UTF-8 text (valid as an ID) - TypeMI3P = 10, // stored as UTF-8 text (valid as an ID) - TypeGIF = 12, // (deprecated) a GIF image - TypeJPEG = 13, // a JPEG image - TypePNG = 14, // a PNG image - TypeURL = 15, // absolute, in UTF-8 characters - TypeDuration = 16, // in milliseconds, 32-bit integer - TypeDateTime = 17, // in UTC, counting seconds since midnight, January 1, 1904; 32 or 64-bits - TypeGenred = 18, // a list of enumerated values - TypeInteger = 21, // a signed big-endian integer with length one of { 1,2,3,4,8 } bytes - TypeRIAAPA = 24, // RIAA parental advisory; { -1=no, 1=yes, 0=unspecified }, 8-bit ingteger - TypeUPC = 25, // Universal Product Code, in text UTF-8 format (valid as an ID) - TypeBMP = 27, // Windows bitmap image - TypeUndefined = 255 // undefined - }; - - struct AtomData { - AtomData(AtomDataType type, ByteVector data) : type(type), locale(0), data(data) {} - AtomDataType type; - int locale; - ByteVector data; - }; - - typedef TagLib::List<AtomData> AtomDataList; - - class Atom - { - public: - Atom(File *file); - ~Atom(); - Atom *find(const char *name1, const char *name2 = 0, const char *name3 = 0, const char *name4 = 0); - bool path(AtomList &path, const char *name1, const char *name2 = 0, const char *name3 = 0); - AtomList findall(const char *name, bool recursive = false); - long offset; - long length; - TagLib::ByteVector name; - AtomList children; - private: - static const int numContainers = 11; - static const char *containers[11]; - }; - - //! Root-level atoms - class Atoms - { - public: - Atoms(File *file); - ~Atoms(); - Atom *find(const char *name1, const char *name2 = 0, const char *name3 = 0, const char *name4 = 0); - AtomList path(const char *name1, const char *name2 = 0, const char *name3 = 0, const char *name4 = 0); - AtomList atoms; - }; - - } - -} - -#endif - -#endif diff --git a/taglib/taglib/mp4/mp4coverart.cpp b/taglib/taglib/mp4/mp4coverart.cpp deleted file mode 100644 index 2746469..0000000 --- a/taglib/taglib/mp4/mp4coverart.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/************************************************************************** - copyright : (C) 2009 by Lukáš Lalinský - email : lalinsky@gmail.com - **************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <taglib.h> -#include <tdebug.h> -#include "trefcounter.h" -#include "mp4coverart.h" - -using namespace TagLib; - -class MP4::CoverArt::CoverArtPrivate : public RefCounter -{ -public: - CoverArtPrivate() : RefCounter(), format(MP4::CoverArt::JPEG) {} - - Format format; - ByteVector data; -}; - -MP4::CoverArt::CoverArt(Format format, const ByteVector &data) -{ - d = new CoverArtPrivate; - d->format = format; - d->data = data; -} - -MP4::CoverArt::CoverArt(const CoverArt &item) : d(item.d) -{ - d->ref(); -} - -MP4::CoverArt & -MP4::CoverArt::operator=(const CoverArt &item) -{ - if(d->deref()) { - delete d; - } - d = item.d; - d->ref(); - return *this; -} - -MP4::CoverArt::~CoverArt() -{ - if(d->deref()) { - delete d; - } -} - -MP4::CoverArt::Format -MP4::CoverArt::format() const -{ - return d->format; -} - -ByteVector -MP4::CoverArt::data() const -{ - return d->data; -} - diff --git a/taglib/taglib/mp4/mp4coverart.h b/taglib/taglib/mp4/mp4coverart.h deleted file mode 100644 index 64115b4..0000000 --- a/taglib/taglib/mp4/mp4coverart.h +++ /dev/null @@ -1,75 +0,0 @@ -/************************************************************************** - copyright : (C) 2009 by Lukáš Lalinský - email : lalinsky@gmail.com - **************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_MP4COVERART_H -#define TAGLIB_MP4COVERART_H - -#include "tlist.h" -#include "tbytevector.h" -#include "taglib_export.h" -#include "mp4atom.h" - -namespace TagLib { - - namespace MP4 { - - class TAGLIB_EXPORT CoverArt - { - public: - /*! - * This describes the image type. - */ - enum Format { - JPEG = TypeJPEG, - PNG = TypePNG, - BMP = TypeBMP, - GIF = TypeGIF, - Unknown = TypeImplicit, - }; - - CoverArt(Format format, const ByteVector &data); - ~CoverArt(); - - CoverArt(const CoverArt &item); - CoverArt &operator=(const CoverArt &item); - - //! Format of the image - Format format() const; - - //! The image data - ByteVector data() const; - - private: - class CoverArtPrivate; - CoverArtPrivate *d; - }; - - typedef List<CoverArt> CoverArtList; - - } - -} - -#endif diff --git a/taglib/taglib/mp4/mp4file.cpp b/taglib/taglib/mp4/mp4file.cpp deleted file mode 100644 index aab1a2b..0000000 --- a/taglib/taglib/mp4/mp4file.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/************************************************************************** - copyright : (C) 2007 by Lukáš Lalinský - email : lalinsky@gmail.com - **************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <tdebug.h> -#include <tstring.h> -#include <tpropertymap.h> -#include "mp4atom.h" -#include "mp4tag.h" -#include "mp4file.h" - -using namespace TagLib; - -class MP4::File::FilePrivate -{ -public: - FilePrivate() : tag(0), atoms(0), properties(0) - { - } - - ~FilePrivate() - { - if(atoms) { - delete atoms; - atoms = 0; - } - if(tag) { - delete tag; - tag = 0; - } - if(properties) { - delete properties; - properties = 0; - } - } - - MP4::Tag *tag; - MP4::Atoms *atoms; - MP4::Properties *properties; -}; - -MP4::File::File(FileName file, bool readProperties, AudioProperties::ReadStyle audioPropertiesStyle) - : TagLib::File(file) -{ - d = new FilePrivate; - if(isOpen()) - read(readProperties, audioPropertiesStyle); -} - -MP4::File::File(IOStream *stream, bool readProperties, AudioProperties::ReadStyle audioPropertiesStyle) - : TagLib::File(stream) -{ - d = new FilePrivate; - if(isOpen()) - read(readProperties, audioPropertiesStyle); -} - -MP4::File::~File() -{ - delete d; -} - -MP4::Tag * -MP4::File::tag() const -{ - return d->tag; -} - -PropertyMap MP4::File::properties() const -{ - return d->tag->properties(); -} - -void MP4::File::removeUnsupportedProperties(const StringList &properties) -{ - d->tag->removeUnsupportedProperties(properties); -} - -PropertyMap MP4::File::setProperties(const PropertyMap &properties) -{ - return d->tag->setProperties(properties); -} - -MP4::Properties * -MP4::File::audioProperties() const -{ - return d->properties; -} - -bool -MP4::File::checkValid(const MP4::AtomList &list) -{ - for(uint i = 0; i < list.size(); i++) { - if(list[i]->length == 0) - return false; - if(!checkValid(list[i]->children)) - return false; - } - return true; -} - -void -MP4::File::read(bool readProperties, Properties::ReadStyle audioPropertiesStyle) -{ - if(!isValid()) - return; - - d->atoms = new Atoms(this); - if (!checkValid(d->atoms->atoms)) { - setValid(false); - return; - } - - // must have a moov atom, otherwise consider it invalid - MP4::Atom *moov = d->atoms->find("moov"); - if(!moov) { - setValid(false); - return; - } - - d->tag = new Tag(this, d->atoms); - if(readProperties) { - d->properties = new Properties(this, d->atoms, audioPropertiesStyle); - } -} - -bool -MP4::File::save() -{ - if(readOnly()) { - debug("MP4::File::save() -- File is read only."); - return false; - } - - if(!isValid()) { - debug("MP4::File::save() -- Trying to save invalid file."); - return false; - } - - return d->tag->save(); -} - diff --git a/taglib/taglib/mp4/mp4file.h b/taglib/taglib/mp4/mp4file.h deleted file mode 100644 index 39693d3..0000000 --- a/taglib/taglib/mp4/mp4file.h +++ /dev/null @@ -1,130 +0,0 @@ -/************************************************************************** - copyright : (C) 2007 by Lukáš Lalinský - email : lalinsky@gmail.com - **************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_MP4FILE_H -#define TAGLIB_MP4FILE_H - -#include "tag.h" -#include "tfile.h" -#include "taglib_export.h" -#include "mp4properties.h" -#include "mp4tag.h" - -namespace TagLib { - - //! An implementation of MP4 (AAC, ALAC, ...) metadata - namespace MP4 { - - class Atoms; - - /*! - * This implements and provides an interface for MP4 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 MP4 files. - */ - class TAGLIB_EXPORT File : public TagLib::File - { - public: - /*! - * Constructs an MP4 file from \a file. If \a readProperties is true the - * file's audio properties will also be read. - * - * \note In the current implementation, \a propertiesStyle is ignored. - */ - File(FileName file, bool readProperties = true, - Properties::ReadStyle audioPropertiesStyle = Properties::Average); - - /*! - * Constructs an MP4 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 audioPropertiesStyle = Properties::Average); - - /*! - * Destroys this instance of the File. - */ - virtual ~File(); - - /*! - * Returns a pointer to the MP4 tag of the file. - * - * MP4::Tag implements the tag interface, so this serves as the - * reimplementation of TagLib::File::tag(). - * - * \note The Tag <b>is still</b> owned by the MP4::File and should not be - * deleted by the user. It will be deleted when the file (object) is - * destroyed. - */ - Tag *tag() const; - - /*! - * Implements the unified property interface -- export function. - */ - PropertyMap properties() const; - - /*! - * Removes unsupported properties. Forwards to the actual Tag's - * removeUnsupportedProperties() function. - */ - void removeUnsupportedProperties(const StringList &properties); - - /*! - * Implements the unified property interface -- import function. - */ - PropertyMap setProperties(const PropertyMap &); - - /*! - * Returns the MP4 audio properties for this file. - */ - Properties *audioProperties() const; - - /*! - * Save the file. - * - * This returns true if the save was successful. - */ - bool save(); - - private: - - void read(bool readProperties, Properties::ReadStyle audioPropertiesStyle); - bool checkValid(const MP4::AtomList &list); - - class FilePrivate; - FilePrivate *d; - }; - - } - -} - -#endif diff --git a/taglib/taglib/mp4/mp4item.cpp b/taglib/taglib/mp4/mp4item.cpp deleted file mode 100644 index 671f26b..0000000 --- a/taglib/taglib/mp4/mp4item.cpp +++ /dev/null @@ -1,206 +0,0 @@ -/************************************************************************** - copyright : (C) 2007 by Lukáš Lalinský - email : lalinsky@gmail.com - **************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <taglib.h> -#include <tdebug.h> -#include "trefcounter.h" -#include "mp4item.h" - -using namespace TagLib; - -class MP4::Item::ItemPrivate : public RefCounter -{ -public: - ItemPrivate() : RefCounter(), valid(true), atomDataType(TypeUndefined) {} - - bool valid; - AtomDataType atomDataType; - union { - bool m_bool; - int m_int; - IntPair m_intPair; - uchar m_byte; - uint m_uint; - long long m_longlong; - }; - StringList m_stringList; - ByteVectorList m_byteVectorList; - MP4::CoverArtList m_coverArtList; -}; - -MP4::Item::Item() -{ - d = new ItemPrivate; - d->valid = false; -} - -MP4::Item::Item(const Item &item) : d(item.d) -{ - d->ref(); -} - -MP4::Item & -MP4::Item::operator=(const Item &item) -{ - if(d->deref()) { - delete d; - } - d = item.d; - d->ref(); - return *this; -} - -MP4::Item::~Item() -{ - if(d->deref()) { - delete d; - } -} - -MP4::Item::Item(bool value) -{ - d = new ItemPrivate; - d->m_bool = value; -} - -MP4::Item::Item(int value) -{ - d = new ItemPrivate; - d->m_int = value; -} - -MP4::Item::Item(uchar value) -{ - d = new ItemPrivate; - d->m_byte = value; -} - -MP4::Item::Item(uint value) -{ - d = new ItemPrivate; - d->m_uint = value; -} - -MP4::Item::Item(long long value) -{ - d = new ItemPrivate; - d->m_longlong = value; -} - -MP4::Item::Item(int value1, int value2) -{ - d = new ItemPrivate; - d->m_intPair.first = value1; - d->m_intPair.second = value2; -} - -MP4::Item::Item(const ByteVectorList &value) -{ - d = new ItemPrivate; - d->m_byteVectorList = value; -} - -MP4::Item::Item(const StringList &value) -{ - d = new ItemPrivate; - d->m_stringList = value; -} - -MP4::Item::Item(const MP4::CoverArtList &value) -{ - d = new ItemPrivate; - d->m_coverArtList = value; -} - -void MP4::Item::setAtomDataType(MP4::AtomDataType type) -{ - d->atomDataType = type; -} - -MP4::AtomDataType MP4::Item::atomDataType() const -{ - return d->atomDataType; -} - -bool -MP4::Item::toBool() const -{ - return d->m_bool; -} - -int -MP4::Item::toInt() const -{ - return d->m_int; -} - -uchar -MP4::Item::toByte() const -{ - return d->m_byte; -} - -TagLib::uint -MP4::Item::toUInt() const -{ - return d->m_uint; -} - -long long -MP4::Item::toLongLong() const -{ - return d->m_longlong; -} - -MP4::Item::IntPair -MP4::Item::toIntPair() const -{ - return d->m_intPair; -} - -StringList -MP4::Item::toStringList() const -{ - return d->m_stringList; -} - -ByteVectorList -MP4::Item::toByteVectorList() const -{ - return d->m_byteVectorList; -} - -MP4::CoverArtList -MP4::Item::toCoverArtList() const -{ - return d->m_coverArtList; -} - -bool -MP4::Item::isValid() const -{ - return d->valid; -} - diff --git a/taglib/taglib/mp4/mp4item.h b/taglib/taglib/mp4/mp4item.h deleted file mode 100644 index be7aa1a..0000000 --- a/taglib/taglib/mp4/mp4item.h +++ /dev/null @@ -1,83 +0,0 @@ -/************************************************************************** - copyright : (C) 2007 by Lukáš Lalinský - email : lalinsky@gmail.com - **************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_MP4ITEM_H -#define TAGLIB_MP4ITEM_H - -#include "tstringlist.h" -#include "mp4coverart.h" -#include "taglib_export.h" - -namespace TagLib { - - namespace MP4 { - - class TAGLIB_EXPORT Item - { - public: - struct IntPair { - int first, second; - }; - - Item(); - Item(const Item &item); - Item &operator=(const Item &item); - ~Item(); - - Item(int value); - Item(uchar value); - Item(uint value); - Item(long long value); - Item(bool value); - Item(int first, int second); - Item(const StringList &value); - Item(const ByteVectorList &value); - Item(const CoverArtList &value); - - void setAtomDataType(AtomDataType type); - AtomDataType atomDataType() const; - - int toInt() const; - uchar toByte() const; - uint toUInt() const; - long long toLongLong() const; - bool toBool() const; - IntPair toIntPair() const; - StringList toStringList() const; - ByteVectorList toByteVectorList() const; - CoverArtList toCoverArtList() const; - - bool isValid() const; - - private: - class ItemPrivate; - ItemPrivate *d; - }; - - } - -} - -#endif diff --git a/taglib/taglib/mp4/mp4properties.cpp b/taglib/taglib/mp4/mp4properties.cpp deleted file mode 100644 index 5a41c08..0000000 --- a/taglib/taglib/mp4/mp4properties.cpp +++ /dev/null @@ -1,199 +0,0 @@ -/************************************************************************** - copyright : (C) 2007 by Lukáš Lalinský - email : lalinsky@gmail.com - **************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <tdebug.h> -#include <tstring.h> -#include "mp4file.h" -#include "mp4atom.h" -#include "mp4properties.h" - -using namespace TagLib; - -class MP4::Properties::PropertiesPrivate -{ -public: - PropertiesPrivate() : length(0), bitrate(0), sampleRate(0), channels(0), bitsPerSample(0), encrypted(false), codec(MP4::Properties::Unknown) {} - - int length; - int bitrate; - int sampleRate; - int channels; - int bitsPerSample; - bool encrypted; - Codec codec; -}; - -MP4::Properties::Properties(File *file, MP4::Atoms *atoms, ReadStyle style) - : AudioProperties(style) -{ - d = new PropertiesPrivate; - - MP4::Atom *moov = atoms->find("moov"); - if(!moov) { - debug("MP4: Atom 'moov' not found"); - return; - } - - MP4::Atom *trak = 0; - ByteVector data; - - MP4::AtomList trakList = moov->findall("trak"); - for (unsigned int i = 0; i < trakList.size(); i++) { - trak = trakList[i]; - MP4::Atom *hdlr = trak->find("mdia", "hdlr"); - if(!hdlr) { - debug("MP4: Atom 'trak.mdia.hdlr' not found"); - return; - } - file->seek(hdlr->offset); - data = file->readBlock(hdlr->length); - if(data.mid(16, 4) == "soun") { - break; - } - trak = 0; - } - if (!trak) { - debug("MP4: No audio tracks"); - return; - } - - MP4::Atom *mdhd = trak->find("mdia", "mdhd"); - if(!mdhd) { - debug("MP4: Atom 'trak.mdia.mdhd' not found"); - return; - } - - file->seek(mdhd->offset); - data = file->readBlock(mdhd->length); - uint version = data[8]; - if(version == 1) { - if (data.size() < 36 + 8) { - debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected"); - return; - } - const long long unit = data.toLongLong(28U); - const long long length = data.toLongLong(36U); - d->length = unit ? int(length / unit) : 0; - } - else { - if (data.size() < 24 + 4) { - debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected"); - return; - } - const unsigned int unit = data.toUInt(20U); - const unsigned int length = data.toUInt(24U); - d->length = unit ? length / unit : 0; - } - - MP4::Atom *atom = trak->find("mdia", "minf", "stbl", "stsd"); - if(!atom) { - return; - } - - file->seek(atom->offset); - data = file->readBlock(atom->length); - if(data.mid(20, 4) == "mp4a") { - d->codec = AAC; - d->channels = data.toShort(40U); - d->bitsPerSample = data.toShort(42U); - d->sampleRate = data.toUInt(46U); - if(data.mid(56, 4) == "esds" && data[64] == 0x03) { - uint pos = 65; - if(data.mid(pos, 3) == "\x80\x80\x80") { - pos += 3; - } - pos += 4; - if(data[pos] == 0x04) { - pos += 1; - if(data.mid(pos, 3) == "\x80\x80\x80") { - pos += 3; - } - pos += 10; - d->bitrate = (data.toUInt(pos) + 500) / 1000; - } - } - } - else if (data.mid(20, 4) == "alac") { - if (atom->length == 88 && data.mid(56, 4) == "alac") { - d->codec = ALAC; - d->bitsPerSample = data.at(69); - d->channels = data.at(73); - d->bitrate = data.toUInt(80U) / 1000; - d->sampleRate = data.toUInt(84U); - } - } - - MP4::Atom *drms = atom->find("drms"); - if(drms) { - d->encrypted = true; - } -} - -MP4::Properties::~Properties() -{ - delete d; -} - -int -MP4::Properties::channels() const -{ - return d->channels; -} - -int -MP4::Properties::sampleRate() const -{ - return d->sampleRate; -} - -int -MP4::Properties::length() const -{ - return d->length; -} - -int -MP4::Properties::bitrate() const -{ - return d->bitrate; -} - -int -MP4::Properties::bitsPerSample() const -{ - return d->bitsPerSample; -} - -bool -MP4::Properties::isEncrypted() const -{ - return d->encrypted; -} - -MP4::Properties::Codec MP4::Properties::codec() const -{ - return d->codec; -} - diff --git a/taglib/taglib/mp4/mp4properties.h b/taglib/taglib/mp4/mp4properties.h deleted file mode 100644 index 2607c36..0000000 --- a/taglib/taglib/mp4/mp4properties.h +++ /dev/null @@ -1,71 +0,0 @@ -/************************************************************************** - copyright : (C) 2007 by Lukáš Lalinský - email : lalinsky@gmail.com - **************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_MP4PROPERTIES_H -#define TAGLIB_MP4PROPERTIES_H - -#include "taglib_export.h" -#include "audioproperties.h" - -namespace TagLib { - - namespace MP4 { - - class Atoms; - class File; - - //! An implementation of MP4 audio properties - class TAGLIB_EXPORT Properties : public AudioProperties - { - public: - enum Codec { - Unknown = 0, - AAC, - ALAC - }; - - Properties(File *file, Atoms *atoms, ReadStyle style = Average); - virtual ~Properties(); - - virtual int length() const; - virtual int bitrate() const; - virtual int sampleRate() const; - virtual int channels() const; - virtual int bitsPerSample() const; - bool isEncrypted() const; - - //! Audio codec used in the MP4 file - Codec codec() const; - - private: - class PropertiesPrivate; - PropertiesPrivate *d; - }; - - } - -} - -#endif diff --git a/taglib/taglib/mp4/mp4tag.cpp b/taglib/taglib/mp4/mp4tag.cpp deleted file mode 100644 index bbe3301..0000000 --- a/taglib/taglib/mp4/mp4tag.cpp +++ /dev/null @@ -1,917 +0,0 @@ -/************************************************************************** - copyright : (C) 2007,2011 by Lukáš Lalinský - email : lalinsky@gmail.com - **************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <tdebug.h> -#include <tstring.h> -#include <tpropertymap.h> -#include "mp4atom.h" -#include "mp4tag.h" -#include "id3v1genres.h" - -using namespace TagLib; - -class MP4::Tag::TagPrivate -{ -public: - TagPrivate() : file(0), atoms(0) {} - ~TagPrivate() {} - TagLib::File *file; - Atoms *atoms; - ItemListMap items; -}; - -MP4::Tag::Tag() -{ - d = new TagPrivate; -} - -MP4::Tag::Tag(TagLib::File *file, MP4::Atoms *atoms) -{ - d = new TagPrivate; - d->file = file; - d->atoms = atoms; - - MP4::Atom *ilst = atoms->find("moov", "udta", "meta", "ilst"); - if(!ilst) { - //debug("Atom moov.udta.meta.ilst not found."); - return; - } - - for(unsigned int i = 0; i < ilst->children.size(); i++) { - MP4::Atom *atom = ilst->children[i]; - file->seek(atom->offset + 8); - if(atom->name == "----") { - parseFreeForm(atom, file); - } - else if(atom->name == "trkn" || atom->name == "disk") { - parseIntPair(atom, file); - } - else if(atom->name == "cpil" || atom->name == "pgap" || atom->name == "pcst" || - atom->name == "hdvd") { - parseBool(atom, file); - } - else if(atom->name == "tmpo") { - parseInt(atom, file); - } - else if(atom->name == "tvsn" || atom->name == "tves" || atom->name == "cnID" || - atom->name == "sfID" || atom->name == "atID" || atom->name == "geID") { - parseUInt(atom, file); - } - else if(atom->name == "plID") { - parseLongLong(atom, file); - } - else if(atom->name == "stik" || atom->name == "rtng" || atom->name == "akID") { - parseByte(atom, file); - } - else if(atom->name == "gnre") { - parseGnre(atom, file); - } - else if(atom->name == "covr") { - parseCovr(atom, file); - } - else { - parseText(atom, file); - } - } -} - -MP4::Tag::~Tag() -{ - delete d; -} - -MP4::AtomDataList -MP4::Tag::parseData2(MP4::Atom *atom, TagLib::File *file, int expectedFlags, bool freeForm) -{ - AtomDataList result; - ByteVector data = file->readBlock(atom->length - 8); - int i = 0; - unsigned int pos = 0; - while(pos < data.size()) { - const int length = static_cast<int>(data.toUInt(pos)); - ByteVector name = data.mid(pos + 4, 4); - const int flags = static_cast<int>(data.toUInt(pos + 8)); - if(freeForm && i < 2) { - if(i == 0 && name != "mean") { - debug("MP4: Unexpected atom \"" + name + "\", expecting \"mean\""); - return result; - } - else if(i == 1 && name != "name") { - debug("MP4: Unexpected atom \"" + name + "\", expecting \"name\""); - return result; - } - result.append(AtomData(AtomDataType(flags), data.mid(pos + 12, length - 12))); - } - else { - if(name != "data") { - debug("MP4: Unexpected atom \"" + name + "\", expecting \"data\""); - return result; - } - if(expectedFlags == -1 || flags == expectedFlags) { - result.append(AtomData(AtomDataType(flags), data.mid(pos + 16, length - 16))); - } - } - pos += length; - i++; - } - return result; -} - -ByteVectorList -MP4::Tag::parseData(MP4::Atom *atom, TagLib::File *file, int expectedFlags, bool freeForm) -{ - AtomDataList data = parseData2(atom, file, expectedFlags, freeForm); - ByteVectorList result; - for(uint i = 0; i < data.size(); i++) { - result.append(data[i].data); - } - return result; -} - -void -MP4::Tag::parseInt(MP4::Atom *atom, TagLib::File *file) -{ - ByteVectorList data = parseData(atom, file); - if(data.size()) { - addItem(atom->name, (int)data[0].toShort()); - } -} - -void -MP4::Tag::parseUInt(MP4::Atom *atom, TagLib::File *file) -{ - ByteVectorList data = parseData(atom, file); - if(data.size()) { - addItem(atom->name, data[0].toUInt()); - } -} - -void -MP4::Tag::parseLongLong(MP4::Atom *atom, TagLib::File *file) -{ - ByteVectorList data = parseData(atom, file); - if(data.size()) { - addItem(atom->name, data[0].toLongLong()); - } -} - -void -MP4::Tag::parseByte(MP4::Atom *atom, TagLib::File *file) -{ - ByteVectorList data = parseData(atom, file); - if(data.size()) { - addItem(atom->name, (uchar)data[0].at(0)); - } -} - -void -MP4::Tag::parseGnre(MP4::Atom *atom, TagLib::File *file) -{ - ByteVectorList data = parseData(atom, file); - if(data.size()) { - int idx = (int)data[0].toShort(); - if(idx > 0) { - addItem("\251gen", StringList(ID3v1::genre(idx - 1))); - } - } -} - -void -MP4::Tag::parseIntPair(MP4::Atom *atom, TagLib::File *file) -{ - ByteVectorList data = parseData(atom, file); - if(data.size()) { - const int a = data[0].toShort(2U); - const int b = data[0].toShort(4U); - addItem(atom->name, MP4::Item(a, b)); - } -} - -void -MP4::Tag::parseBool(MP4::Atom *atom, TagLib::File *file) -{ - ByteVectorList data = parseData(atom, file); - if(data.size()) { - bool value = data[0].size() ? data[0][0] != '\0' : false; - addItem(atom->name, value); - } -} - -void -MP4::Tag::parseText(MP4::Atom *atom, TagLib::File *file, int expectedFlags) -{ - ByteVectorList data = parseData(atom, file, expectedFlags); - if(data.size()) { - StringList value; - for(unsigned int i = 0; i < data.size(); i++) { - value.append(String(data[i], String::UTF8)); - } - addItem(atom->name, value); - } -} - -void -MP4::Tag::parseFreeForm(MP4::Atom *atom, TagLib::File *file) -{ - AtomDataList data = parseData2(atom, file, -1, true); - if(data.size() > 2) { - String name = "----:" + String(data[0].data, String::UTF8) + ':' + String(data[1].data, String::UTF8); - AtomDataType type = data[2].type; - for(uint i = 2; i < data.size(); i++) { - if(data[i].type != type) { - debug("MP4: We currently don't support values with multiple types"); - break; - } - } - if(type == TypeUTF8) { - StringList value; - for(uint i = 2; i < data.size(); i++) { - value.append(String(data[i].data, String::UTF8)); - } - Item item(value); - item.setAtomDataType(type); - addItem(name, item); - } - else { - ByteVectorList value; - for(uint i = 2; i < data.size(); i++) { - value.append(data[i].data); - } - Item item(value); - item.setAtomDataType(type); - addItem(name, item); - } - } -} - -void -MP4::Tag::parseCovr(MP4::Atom *atom, TagLib::File *file) -{ - MP4::CoverArtList value; - ByteVector data = file->readBlock(atom->length - 8); - unsigned int pos = 0; - while(pos < data.size()) { - const int length = static_cast<int>(data.toUInt(pos)); - ByteVector name = data.mid(pos + 4, 4); - const int flags = static_cast<int>(data.toUInt(pos + 8)); - if(name != "data") { - debug("MP4: Unexpected atom \"" + name + "\", expecting \"data\""); - break; - } - if(flags == TypeJPEG || flags == TypePNG || flags == TypeBMP || flags == TypeGIF || 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) - addItem(atom->name, value); -} - -ByteVector -MP4::Tag::padIlst(const ByteVector &data, int length) -{ - if (length == -1) { - length = ((data.size() + 1023) & ~1023) - data.size(); - } - return renderAtom("free", ByteVector(length, '\1')); -} - -ByteVector -MP4::Tag::renderAtom(const ByteVector &name, const ByteVector &data) -{ - return ByteVector::fromUInt(data.size() + 8) + name + data; -} - -ByteVector -MP4::Tag::renderData(const ByteVector &name, int flags, const ByteVectorList &data) -{ - ByteVector result; - for(unsigned int i = 0; i < data.size(); i++) { - result.append(renderAtom("data", ByteVector::fromUInt(flags) + ByteVector(4, '\0') + data[i])); - } - return renderAtom(name, result); -} - -ByteVector -MP4::Tag::renderBool(const ByteVector &name, MP4::Item &item) -{ - ByteVectorList data; - data.append(ByteVector(1, item.toBool() ? '\1' : '\0')); - return renderData(name, TypeInteger, data); -} - -ByteVector -MP4::Tag::renderInt(const ByteVector &name, MP4::Item &item) -{ - ByteVectorList data; - data.append(ByteVector::fromShort(item.toInt())); - return renderData(name, TypeInteger, data); -} - -ByteVector -MP4::Tag::renderUInt(const ByteVector &name, MP4::Item &item) -{ - ByteVectorList data; - data.append(ByteVector::fromUInt(item.toUInt())); - return renderData(name, TypeInteger, data); -} - -ByteVector -MP4::Tag::renderLongLong(const ByteVector &name, MP4::Item &item) -{ - ByteVectorList data; - data.append(ByteVector::fromLongLong(item.toLongLong())); - return renderData(name, TypeInteger, data); -} - -ByteVector -MP4::Tag::renderByte(const ByteVector &name, MP4::Item &item) -{ - ByteVectorList data; - data.append(ByteVector(1, item.toByte())); - return renderData(name, TypeInteger, data); -} - -ByteVector -MP4::Tag::renderIntPair(const ByteVector &name, MP4::Item &item) -{ - ByteVectorList data; - data.append(ByteVector(2, '\0') + - ByteVector::fromShort(item.toIntPair().first) + - ByteVector::fromShort(item.toIntPair().second) + - ByteVector(2, '\0')); - return renderData(name, TypeImplicit, data); -} - -ByteVector -MP4::Tag::renderIntPairNoTrailing(const ByteVector &name, MP4::Item &item) -{ - ByteVectorList data; - data.append(ByteVector(2, '\0') + - ByteVector::fromShort(item.toIntPair().first) + - ByteVector::fromShort(item.toIntPair().second)); - return renderData(name, TypeImplicit, data); -} - -ByteVector -MP4::Tag::renderText(const ByteVector &name, MP4::Item &item, int flags) -{ - ByteVectorList data; - StringList value = item.toStringList(); - for(unsigned int i = 0; i < value.size(); i++) { - data.append(value[i].data(String::UTF8)); - } - return renderData(name, flags, data); -} - -ByteVector -MP4::Tag::renderCovr(const ByteVector &name, MP4::Item &item) -{ - ByteVector data; - MP4::CoverArtList value = item.toCoverArtList(); - for(unsigned int i = 0; i < value.size(); i++) { - data.append(renderAtom("data", ByteVector::fromUInt(value[i].format()) + - ByteVector(4, '\0') + value[i].data())); - } - return renderAtom(name, data); -} - -ByteVector -MP4::Tag::renderFreeForm(const String &name, MP4::Item &item) -{ - StringList header = StringList::split(name, ":"); - if (header.size() != 3) { - debug("MP4: Invalid free-form item name \"" + name + "\""); - return ByteVector::null; - } - ByteVector data; - data.append(renderAtom("mean", ByteVector::fromUInt(0) + header[1].data(String::UTF8))); - data.append(renderAtom("name", ByteVector::fromUInt(0) + header[2].data(String::UTF8))); - AtomDataType type = item.atomDataType(); - if(type == TypeUndefined) { - if(!item.toStringList().isEmpty()) { - type = TypeUTF8; - } - else { - type = TypeImplicit; - } - } - if(type == TypeUTF8) { - StringList value = item.toStringList(); - for(unsigned int i = 0; i < value.size(); i++) { - data.append(renderAtom("data", ByteVector::fromUInt(type) + ByteVector(4, '\0') + value[i].data(String::UTF8))); - } - } - else { - ByteVectorList value = item.toByteVectorList(); - for(unsigned int i = 0; i < value.size(); i++) { - data.append(renderAtom("data", ByteVector::fromUInt(type) + ByteVector(4, '\0') + value[i])); - } - } - return renderAtom("----", data); -} - -bool -MP4::Tag::save() -{ - ByteVector data; - for(MP4::ItemListMap::Iterator i = d->items.begin(); i != d->items.end(); i++) { - const String name = i->first; - if(name.startsWith("----")) { - data.append(renderFreeForm(name, i->second)); - } - else if(name == "trkn") { - data.append(renderIntPair(name.data(String::Latin1), i->second)); - } - else if(name == "disk") { - data.append(renderIntPairNoTrailing(name.data(String::Latin1), i->second)); - } - else if(name == "cpil" || name == "pgap" || name == "pcst" || name == "hdvd") { - data.append(renderBool(name.data(String::Latin1), i->second)); - } - else if(name == "tmpo") { - data.append(renderInt(name.data(String::Latin1), i->second)); - } - else if(name == "tvsn" || name == "tves" || name == "cnID" || - name == "sfID" || name == "atID" || name == "geID") { - data.append(renderUInt(name.data(String::Latin1), i->second)); - } - else if(name == "plID") { - data.append(renderLongLong(name.data(String::Latin1), i->second)); - } - else if(name == "stik" || name == "rtng" || name == "akID") { - data.append(renderByte(name.data(String::Latin1), i->second)); - } - else if(name == "covr") { - data.append(renderCovr(name.data(String::Latin1), i->second)); - } - else if(name.size() == 4){ - data.append(renderText(name.data(String::Latin1), i->second)); - } - else { - debug("MP4: Unknown item name \"" + name + "\""); - } - } - data = renderAtom("ilst", data); - - AtomList path = d->atoms->path("moov", "udta", "meta", "ilst"); - if(path.size() == 4) { - saveExisting(data, path); - } - else { - saveNew(data); - } - - return true; -} - -void -MP4::Tag::updateParents(AtomList &path, long delta, int ignore) -{ - for(unsigned int i = 0; i < path.size() - ignore; i++) { - d->file->seek(path[i]->offset); - long size = d->file->readBlock(4).toUInt(); - // 64-bit - if (size == 1) { - d->file->seek(4, File::Current); // Skip name - long long longSize = d->file->readBlock(8).toLongLong(); - // Seek the offset of the 64-bit size - d->file->seek(path[i]->offset + 8); - d->file->writeBlock(ByteVector::fromLongLong(longSize + delta)); - } - // 32-bit - else { - d->file->seek(path[i]->offset); - d->file->writeBlock(ByteVector::fromUInt(size + delta)); - } - } -} - -void -MP4::Tag::updateOffsets(long delta, long offset) -{ - MP4::Atom *moov = d->atoms->find("moov"); - if(moov) { - MP4::AtomList stco = moov->findall("stco", true); - for(unsigned int i = 0; i < stco.size(); i++) { - MP4::Atom *atom = stco[i]; - if(atom->offset > offset) { - atom->offset += delta; - } - d->file->seek(atom->offset + 12); - ByteVector data = d->file->readBlock(atom->length - 12); - unsigned int count = data.toUInt(); - d->file->seek(atom->offset + 16); - uint pos = 4; - while(count--) { - long o = static_cast<long>(data.toUInt(pos)); - if(o > offset) { - o += delta; - } - d->file->writeBlock(ByteVector::fromUInt(o)); - pos += 4; - } - } - - MP4::AtomList co64 = moov->findall("co64", true); - for(unsigned int i = 0; i < co64.size(); i++) { - MP4::Atom *atom = co64[i]; - if(atom->offset > offset) { - atom->offset += delta; - } - d->file->seek(atom->offset + 12); - ByteVector data = d->file->readBlock(atom->length - 12); - unsigned int count = data.toUInt(); - d->file->seek(atom->offset + 16); - uint pos = 4; - while(count--) { - long long o = data.toLongLong(pos); - if(o > offset) { - o += delta; - } - d->file->writeBlock(ByteVector::fromLongLong(o)); - pos += 8; - } - } - } - - MP4::Atom *moof = d->atoms->find("moof"); - if(moof) { - MP4::AtomList tfhd = moof->findall("tfhd", true); - for(unsigned int i = 0; i < tfhd.size(); i++) { - MP4::Atom *atom = tfhd[i]; - if(atom->offset > offset) { - atom->offset += delta; - } - d->file->seek(atom->offset + 9); - ByteVector data = d->file->readBlock(atom->length - 9); - const unsigned int flags = data.toUInt(0, 3, true); - if(flags & 1) { - long long o = data.toLongLong(7U); - if(o > offset) { - o += delta; - } - d->file->seek(atom->offset + 16); - d->file->writeBlock(ByteVector::fromLongLong(o)); - } - } - } -} - -void -MP4::Tag::saveNew(ByteVector &data) -{ - data = renderAtom("meta", TagLib::ByteVector(4, '\0') + - renderAtom("hdlr", TagLib::ByteVector(8, '\0') + TagLib::ByteVector("mdirappl") + TagLib::ByteVector(9, '\0')) + - data + padIlst(data)); - - AtomList path = d->atoms->path("moov", "udta"); - if(path.size() != 2) { - path = d->atoms->path("moov"); - data = renderAtom("udta", data); - } - - long offset = path[path.size() - 1]->offset + 8; - d->file->insert(data, offset, 0); - - updateParents(path, data.size()); - updateOffsets(data.size(), offset); -} - -void -MP4::Tag::saveExisting(ByteVector &data, AtomList &path) -{ - MP4::Atom *ilst = path[path.size() - 1]; - long offset = ilst->offset; - long length = ilst->length; - - MP4::Atom *meta = path[path.size() - 2]; - AtomList::Iterator index = meta->children.find(ilst); - - // check if there is an atom before 'ilst', and possibly use it as padding - if(index != meta->children.begin()) { - AtomList::Iterator prevIndex = index; - prevIndex--; - MP4::Atom *prev = *prevIndex; - if(prev->name == "free") { - offset = prev->offset; - length += prev->length; - } - } - // check if there is an atom after 'ilst', and possibly use it as padding - AtomList::Iterator nextIndex = index; - nextIndex++; - if(nextIndex != meta->children.end()) { - MP4::Atom *next = *nextIndex; - if(next->name == "free") { - length += next->length; - } - } - - long delta = data.size() - length; - if(delta > 0 || (delta < 0 && delta > -8)) { - data.append(padIlst(data)); - delta = data.size() - length; - } - else if(delta < 0) { - data.append(padIlst(data, -delta - 8)); - delta = 0; - } - - d->file->insert(data, offset, length); - - if(delta) { - updateParents(path, delta, 1); - updateOffsets(delta, offset); - } -} - -String -MP4::Tag::title() const -{ - if(d->items.contains("\251nam")) - return d->items["\251nam"].toStringList().toString(", "); - return String::null; -} - -String -MP4::Tag::artist() const -{ - if(d->items.contains("\251ART")) - return d->items["\251ART"].toStringList().toString(", "); - return String::null; -} - -String -MP4::Tag::album() const -{ - if(d->items.contains("\251alb")) - return d->items["\251alb"].toStringList().toString(", "); - return String::null; -} - -String -MP4::Tag::comment() const -{ - if(d->items.contains("\251cmt")) - return d->items["\251cmt"].toStringList().toString(", "); - return String::null; -} - -String -MP4::Tag::genre() const -{ - if(d->items.contains("\251gen")) - return d->items["\251gen"].toStringList().toString(", "); - return String::null; -} - -unsigned int -MP4::Tag::year() const -{ - if(d->items.contains("\251day")) - return d->items["\251day"].toStringList().toString().toInt(); - return 0; -} - -unsigned int -MP4::Tag::track() const -{ - if(d->items.contains("trkn")) - return d->items["trkn"].toIntPair().first; - return 0; -} - -void -MP4::Tag::setTitle(const String &value) -{ - d->items["\251nam"] = StringList(value); -} - -void -MP4::Tag::setArtist(const String &value) -{ - d->items["\251ART"] = StringList(value); -} - -void -MP4::Tag::setAlbum(const String &value) -{ - d->items["\251alb"] = StringList(value); -} - -void -MP4::Tag::setComment(const String &value) -{ - d->items["\251cmt"] = StringList(value); -} - -void -MP4::Tag::setGenre(const String &value) -{ - d->items["\251gen"] = StringList(value); -} - -void -MP4::Tag::setYear(uint value) -{ - d->items["\251day"] = StringList(String::number(value)); -} - -void -MP4::Tag::setTrack(uint value) -{ - d->items["trkn"] = MP4::Item(value, 0); -} - -MP4::ItemListMap & -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 + "\""); - } -} diff --git a/taglib/taglib/mp4/mp4tag.h b/taglib/taglib/mp4/mp4tag.h deleted file mode 100644 index 48d71fc..0000000 --- a/taglib/taglib/mp4/mp4tag.h +++ /dev/null @@ -1,118 +0,0 @@ -/************************************************************************** - copyright : (C) 2007,2011 by Lukáš Lalinský - email : lalinsky@gmail.com - **************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_MP4TAG_H -#define TAGLIB_MP4TAG_H - -#include "tag.h" -#include "tbytevectorlist.h" -#include "tfile.h" -#include "tmap.h" -#include "tstringlist.h" -#include "taglib_export.h" -#include "mp4atom.h" -#include "mp4item.h" - -namespace TagLib { - - namespace MP4 { - - typedef TagLib::Map<String, Item> ItemListMap; - - class TAGLIB_EXPORT Tag: public TagLib::Tag - { - public: - Tag(); - Tag(TagLib::File *file, Atoms *atoms); - ~Tag(); - bool save(); - - String title() const; - String artist() const; - String album() const; - String comment() const; - String genre() const; - uint year() const; - uint track() const; - - void setTitle(const String &value); - void setArtist(const String &value); - void setAlbum(const String &value); - void setComment(const String &value); - void setGenre(const String &value); - void setYear(uint value); - void setTrack(uint value); - - 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); - void parseText(Atom *atom, TagLib::File *file, int expectedFlags = 1); - void parseFreeForm(Atom *atom, TagLib::File *file); - void parseInt(Atom *atom, TagLib::File *file); - void parseByte(Atom *atom, TagLib::File *file); - void parseUInt(Atom *atom, TagLib::File *file); - void parseLongLong(Atom *atom, TagLib::File *file); - void parseGnre(Atom *atom, TagLib::File *file); - void parseIntPair(Atom *atom, TagLib::File *file); - void parseBool(Atom *atom, TagLib::File *file); - void parseCovr(Atom *atom, TagLib::File *file); - - TagLib::ByteVector padIlst(const ByteVector &data, int length = -1); - TagLib::ByteVector renderAtom(const ByteVector &name, const TagLib::ByteVector &data); - TagLib::ByteVector renderData(const ByteVector &name, int flags, const TagLib::ByteVectorList &data); - TagLib::ByteVector renderText(const ByteVector &name, Item &item, int flags = TypeUTF8); - TagLib::ByteVector renderFreeForm(const String &name, Item &item); - TagLib::ByteVector renderBool(const ByteVector &name, Item &item); - TagLib::ByteVector renderInt(const ByteVector &name, Item &item); - TagLib::ByteVector renderByte(const ByteVector &name, Item &item); - TagLib::ByteVector renderUInt(const ByteVector &name, Item &item); - TagLib::ByteVector renderLongLong(const ByteVector &name, Item &item); - TagLib::ByteVector renderIntPair(const ByteVector &name, Item &item); - TagLib::ByteVector renderIntPairNoTrailing(const ByteVector &name, Item &item); - TagLib::ByteVector renderCovr(const ByteVector &name, Item &item); - - void updateParents(AtomList &path, long delta, int ignore = 0); - void updateOffsets(long delta, long offset); - - void saveNew(TagLib::ByteVector &data); - void saveExisting(TagLib::ByteVector &data, AtomList &path); - - void addItem(const String &name, const Item &value); - - class TagPrivate; - TagPrivate *d; - }; - - } - -} - -#endif diff --git a/taglib/taglib/mpc/mpcfile.cpp b/taglib/taglib/mpc/mpcfile.cpp deleted file mode 100644 index 979c035..0000000 --- a/taglib/taglib/mpc/mpcfile.cpp +++ /dev/null @@ -1,367 +0,0 @@ -/*************************************************************************** - copyright : (C) 2004 by Allan Sandfeld Jensen - email : kde@carewolf.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <tbytevector.h> -#include <tstring.h> -#include <tagunion.h> -#include <tdebug.h> -#include <tpropertymap.h> - -#include "mpcfile.h" -#include "id3v1tag.h" -#include "id3v2header.h" -#include "apetag.h" -#include "apefooter.h" - -using namespace TagLib; - -namespace -{ - enum { MPCAPEIndex = 0, MPCID3v1Index = 1 }; -} - -class MPC::File::FilePrivate -{ -public: - FilePrivate() : - APELocation(-1), - APESize(0), - ID3v1Location(-1), - ID3v2Header(0), - ID3v2Location(-1), - ID3v2Size(0), - properties(0), - scanned(false), - hasAPE(false), - hasID3v1(false), - hasID3v2(false) {} - - ~FilePrivate() - { - delete ID3v2Header; - delete properties; - } - - long APELocation; - uint APESize; - - long ID3v1Location; - - ID3v2::Header *ID3v2Header; - long ID3v2Location; - uint ID3v2Size; - - TagUnion tag; - - Properties *properties; - bool scanned; - - // These indicate whether the file *on disk* has these tags, not if - // this data structure does. This is used in computing offsets. - - bool hasAPE; - bool hasID3v1; - bool hasID3v2; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -MPC::File::File(FileName file, bool readProperties, - Properties::ReadStyle propertiesStyle) : TagLib::File(file) -{ - d = new FilePrivate; - if(isOpen()) - read(readProperties, propertiesStyle); -} - -MPC::File::File(IOStream *stream, bool readProperties, - Properties::ReadStyle propertiesStyle) : TagLib::File(stream) -{ - d = new FilePrivate; - if(isOpen()) - read(readProperties, propertiesStyle); -} - -MPC::File::~File() -{ - delete d; -} - -TagLib::Tag *MPC::File::tag() const -{ - return &d->tag; -} - -PropertyMap MPC::File::properties() const -{ - if(d->hasAPE) - return d->tag.access<APE::Tag>(MPCAPEIndex, false)->properties(); - if(d->hasID3v1) - return d->tag.access<ID3v1::Tag>(MPCID3v1Index, false)->properties(); - return PropertyMap(); -} - -void MPC::File::removeUnsupportedProperties(const StringList &properties) -{ - if(d->hasAPE) - d->tag.access<APE::Tag>(MPCAPEIndex, false)->removeUnsupportedProperties(properties); - if(d->hasID3v1) - d->tag.access<ID3v1::Tag>(MPCID3v1Index, false)->removeUnsupportedProperties(properties); -} - -PropertyMap MPC::File::setProperties(const PropertyMap &properties) -{ - if(d->hasID3v1) - d->tag.access<APE::Tag>(MPCID3v1Index, false)->setProperties(properties); - return d->tag.access<APE::Tag>(MPCAPEIndex, true)->setProperties(properties); -} - -MPC::Properties *MPC::File::audioProperties() const -{ - return d->properties; -} - -bool MPC::File::save() -{ - if(readOnly()) { - debug("MPC::File::save() -- File is read only."); - return false; - } - - // Possibly strip ID3v2 tag - - if(d->hasID3v2 && !d->ID3v2Header) { - removeBlock(d->ID3v2Location, d->ID3v2Size); - d->hasID3v2 = false; - if(d->hasID3v1) - d->ID3v1Location -= d->ID3v2Size; - if(d->hasAPE) - d->APELocation -= d->ID3v2Size; - } - - // Update ID3v1 tag - - if(ID3v1Tag()) { - if(d->hasID3v1) { - seek(d->ID3v1Location); - writeBlock(ID3v1Tag()->render()); - } - else { - seek(0, End); - d->ID3v1Location = tell(); - writeBlock(ID3v1Tag()->render()); - d->hasID3v1 = true; - } - } else - if(d->hasID3v1) { - removeBlock(d->ID3v1Location, 128); - d->hasID3v1 = false; - if(d->hasAPE) { - if(d->APELocation > d->ID3v1Location) - d->APELocation -= 128; - } - } - - // Update APE tag - - if(APETag()) { - if(d->hasAPE) - insert(APETag()->render(), d->APELocation, d->APESize); - else { - if(d->hasID3v1) { - insert(APETag()->render(), d->ID3v1Location, 0); - d->APESize = APETag()->footer()->completeTagSize(); - d->hasAPE = true; - d->APELocation = d->ID3v1Location; - d->ID3v1Location += d->APESize; - } - else { - seek(0, End); - d->APELocation = tell(); - writeBlock(APETag()->render()); - d->APESize = APETag()->footer()->completeTagSize(); - d->hasAPE = true; - } - } - } - else - if(d->hasAPE) { - removeBlock(d->APELocation, d->APESize); - d->hasAPE = false; - if(d->hasID3v1) { - if(d->ID3v1Location > d->APELocation) - d->ID3v1Location -= d->APESize; - } - } - - return true; -} - -ID3v1::Tag *MPC::File::ID3v1Tag(bool create) -{ - return d->tag.access<ID3v1::Tag>(MPCID3v1Index, create); -} - -APE::Tag *MPC::File::APETag(bool create) -{ - return d->tag.access<APE::Tag>(MPCAPEIndex, create); -} - -void MPC::File::strip(int tags) -{ - if(tags & ID3v1) { - d->tag.set(MPCID3v1Index, 0); - APETag(true); - } - - if(tags & ID3v2) { - delete d->ID3v2Header; - d->ID3v2Header = 0; - } - - if(tags & APE) { - d->tag.set(MPCAPEIndex, 0); - - if(!ID3v1Tag()) - APETag(true); - } -} - -void MPC::File::remove(int tags) -{ - strip(tags); -} - -bool MPC::File::hasID3v1Tag() const -{ - return d->hasID3v1; -} - -bool MPC::File::hasAPETag() const -{ - return d->hasAPE; -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -void MPC::File::read(bool readProperties, Properties::ReadStyle /* propertiesStyle */) -{ - // Look for an ID3v1 tag - - d->ID3v1Location = findID3v1(); - - if(d->ID3v1Location >= 0) { - d->tag.set(MPCID3v1Index, new ID3v1::Tag(this, d->ID3v1Location)); - d->hasID3v1 = true; - } - - // Look for an APE tag - - findAPE(); - - d->APELocation = findAPE(); - - if(d->APELocation >= 0) { - d->tag.set(MPCAPEIndex, new APE::Tag(this, d->APELocation)); - - d->APESize = APETag()->footer()->completeTagSize(); - d->APELocation = d->APELocation + APETag()->footer()->size() - d->APESize; - d->hasAPE = true; - } - - if(!d->hasID3v1) - APETag(true); - - // Look for and skip an ID3v2 tag - - d->ID3v2Location = findID3v2(); - - if(d->ID3v2Location >= 0) { - seek(d->ID3v2Location); - d->ID3v2Header = new ID3v2::Header(readBlock(ID3v2::Header::size())); - d->ID3v2Size = d->ID3v2Header->completeTagSize(); - d->hasID3v2 = true; - } - - if(d->hasID3v2) - seek(d->ID3v2Location + d->ID3v2Size); - else - seek(0); - - // Look for MPC metadata - - if(readProperties) { - d->properties = new Properties(this, length() - d->ID3v2Size - d->APESize); - } -} - -long MPC::File::findAPE() -{ - if(!isValid()) - return -1; - - if(d->hasID3v1) - seek(-160, End); - else - seek(-32, End); - - long p = tell(); - - if(readBlock(8) == APE::Tag::fileIdentifier()) - return p; - - return -1; -} - -long MPC::File::findID3v1() -{ - if(!isValid()) - return -1; - - seek(-128, End); - long p = tell(); - - if(readBlock(3) == ID3v1::Tag::fileIdentifier()) - return p; - - return -1; -} - -long MPC::File::findID3v2() -{ - if(!isValid()) - return -1; - - seek(0); - - if(readBlock(3) == ID3v2::Header::fileIdentifier()) - return 0; - - return -1; -} diff --git a/taglib/taglib/mpc/mpcfile.h b/taglib/taglib/mpc/mpcfile.h deleted file mode 100644 index 1eef810..0000000 --- a/taglib/taglib/mpc/mpcfile.h +++ /dev/null @@ -1,231 +0,0 @@ -/*************************************************************************** - copyright : (C) 2004 by Allan Sandfeld Jensen - email : kde@carewolf.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_MPCFILE_H -#define TAGLIB_MPCFILE_H - -#include "taglib_export.h" -#include "tfile.h" -#include "tag.h" - -#include "mpcproperties.h" - -#include "tlist.h" - -namespace TagLib { - - class Tag; - - namespace ID3v1 { class Tag; } - namespace APE { class Tag; } - - //! An implementation of MPC metadata - - /*! - * This is implementation of MPC metadata. - * - * This supports ID3v1 and APE (v1 and v2) style comments as well as reading stream - * properties from the file. ID3v2 tags are invalid in MPC-files, but will be skipped - * and ignored. - */ - - namespace MPC { - - //! An implementation of TagLib::File with MPC specific methods - - /*! - * This implements and provides an interface for MPC 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 MPC files. - * The only invalid tag combination supported is an ID3v1 tag after an APE tag. - */ - - class TAGLIB_EXPORT File : public TagLib::File - { - public: - /*! - * This set of flags is used for various operations and is suitable for - * being OR-ed together. - */ - enum TagTypes { - //! Empty set. Matches no tag types. - NoTags = 0x0000, - //! Matches ID3v1 tags. - ID3v1 = 0x0001, - //! Matches ID3v2 tags. - ID3v2 = 0x0002, - //! Matches APE tags. - APE = 0x0004, - //! Matches all tag types. - AllTags = 0xffff - }; - - /*! - * 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); - - /*! - * 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); - - /*! - * Destroys this instance of the File. - */ - virtual ~File(); - - /*! - * Returns the Tag for this file. This will be an APE tag, an ID3v1 tag - * or a combination of the two. - */ - virtual TagLib::Tag *tag() const; - - /*! - * Implements the unified property interface -- export function. - * If the file contains both an APE and an ID3v1 tag, only the APE - * tag will be converted to the PropertyMap. - */ - PropertyMap properties() const; - - void removeUnsupportedProperties(const StringList &properties); - - /*! - * Implements the unified property interface -- import function. - * Affects only the APEv2 tag which will be created if necessary. - * If an ID3v1 tag exists, it will be updated as well. - */ - PropertyMap setProperties(const PropertyMap &); - - /*! - * Returns the MPC::Properties for this file. If no audio properties - * were read then this will return a null pointer. - */ - virtual Properties *audioProperties() const; - - /*! - * Saves the file. - */ - virtual bool save(); - - /*! - * Returns a pointer to the ID3v1 tag of the file. - * - * 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 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 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 and returns a valid pointer. If - * there already be an ID3v1 tag, the new APE tag will be placed before it. - * - * \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); - - /*! - * This will remove the tags that match the OR-ed together TagTypes from the - * file. By default it removes all tags. - * - * \warning This will also invalidate pointers to the tags - * as their memory will be freed. - * - * \note In order to make the removal permanent save() still needs to be called. - */ - void strip(int tags = AllTags); - - /*! - * \deprecated - * \see strip - */ - void remove(int tags = AllTags); - - /*! - * Returns whether or not the file on disk actually has an ID3v1 tag. - * - * \see ID3v1Tag() - */ - bool hasID3v1Tag() const; - - /*! - * Returns whether or not the file on disk actually has an APE tag. - * - * \see APETag() - */ - bool hasAPETag() const; - - private: - File(const File &); - File &operator=(const File &); - - void read(bool readProperties, Properties::ReadStyle propertiesStyle); - void scan(); - long findAPE(); - long findID3v1(); - long findID3v2(); - - class FilePrivate; - FilePrivate *d; - }; - } -} - -#endif diff --git a/taglib/taglib/mpc/mpcproperties.cpp b/taglib/taglib/mpc/mpcproperties.cpp deleted file mode 100644 index d406f8d..0000000 --- a/taglib/taglib/mpc/mpcproperties.cpp +++ /dev/null @@ -1,316 +0,0 @@ -/*************************************************************************** - copyright : (C) 2004 by Allan Sandfeld Jensen - email : kde@carewolf.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <tstring.h> -#include <tdebug.h> -#include <bitset> -#include <math.h> - -#include "mpcproperties.h" -#include "mpcfile.h" - -using namespace TagLib; - -class MPC::Properties::PropertiesPrivate -{ -public: - PropertiesPrivate(long length, ReadStyle s) : - streamLength(length), - style(s), - version(0), - length(0), - bitrate(0), - sampleRate(0), - channels(0), - totalFrames(0), - sampleFrames(0), - trackGain(0), - trackPeak(0), - albumGain(0), - albumPeak(0) {} - - long streamLength; - ReadStyle style; - int version; - int length; - int bitrate; - int sampleRate; - int channels; - uint totalFrames; - uint sampleFrames; - uint trackGain; - uint trackPeak; - uint albumGain; - uint albumPeak; - String flags; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -MPC::Properties::Properties(const ByteVector &data, long streamLength, ReadStyle style) : AudioProperties(style) -{ - d = new PropertiesPrivate(streamLength, style); - readSV7(data); -} - -MPC::Properties::Properties(File *file, long streamLength, ReadStyle style) : AudioProperties(style) -{ - d = new PropertiesPrivate(streamLength, style); - ByteVector magic = file->readBlock(4); - if(magic == "MPCK") { - // Musepack version 8 - readSV8(file); - } - else { - // Musepack version 7 or older, fixed size header - readSV7(magic + file->readBlock(MPC::HeaderSize - 4)); - } -} - -MPC::Properties::~Properties() -{ - delete d; -} - -int MPC::Properties::length() const -{ - return d->length; -} - -int MPC::Properties::bitrate() const -{ - return d->bitrate; -} - -int MPC::Properties::sampleRate() const -{ - return d->sampleRate; -} - -int MPC::Properties::channels() const -{ - return d->channels; -} - -int MPC::Properties::mpcVersion() const -{ - return d->version; -} - -TagLib::uint MPC::Properties::totalFrames() const -{ - return d->totalFrames; -} - -TagLib::uint MPC::Properties::sampleFrames() const -{ - return d->sampleFrames; -} - -int MPC::Properties::trackGain() const -{ - return d->trackGain; -} - -int MPC::Properties::trackPeak() const -{ - return d->trackPeak; -} - -int MPC::Properties::albumGain() const -{ - return d->albumGain; -} - -int MPC::Properties::albumPeak() const -{ - return d->albumPeak; -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -unsigned long readSize(File *file, TagLib::uint &sizelength) -{ - unsigned char tmp; - unsigned long size = 0; - - do { - ByteVector b = file->readBlock(1); - tmp = b[0]; - size = (size << 7) | (tmp & 0x7F); - sizelength++; - } while((tmp & 0x80)); - return size; -} - -unsigned long readSize(const ByteVector &data, TagLib::uint &sizelength) -{ - unsigned char tmp; - unsigned long size = 0; - unsigned long pos = 0; - - do { - tmp = data[pos++]; - size = (size << 7) | (tmp & 0x7F); - sizelength++; - } while((tmp & 0x80) && (pos < data.size())); - return size; -} - -static const unsigned short sftable [4] = { 44100, 48000, 37800, 32000 }; - -void MPC::Properties::readSV8(File *file) -{ - bool readSH = false, readRG = false; - - while(!readSH && !readRG) { - ByteVector packetType = file->readBlock(2); - uint packetSizeLength = 0; - unsigned long packetSize = readSize(file, packetSizeLength); - unsigned long dataSize = packetSize - 2 - packetSizeLength; - - if(packetType == "SH") { - // Stream Header - // http://trac.musepack.net/wiki/SV8Specification#StreamHeaderPacket - ByteVector data = file->readBlock(dataSize); - readSH = true; - - TagLib::uint pos = 4; - d->version = data[pos]; - pos += 1; - d->sampleFrames = readSize(data.mid(pos), pos); - ulong begSilence = readSize(data.mid(pos), pos); - - 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 = (int)(d->streamLength * 8.0 * d->sampleRate / (d->sampleFrames - begSilence)); - d->bitrate = d->bitrate / 1000; - - d->length = (d->sampleFrames - begSilence) / d->sampleRate; - } - - else if (packetType == "RG") { - // Replay Gain - // http://trac.musepack.net/wiki/SV8Specification#ReplaygainPacket - ByteVector data = file->readBlock(dataSize); - readRG = true; - - int replayGainVersion = data[0]; - if(replayGainVersion == 1) { - d->trackGain = data.toShort(1, true); - d->trackPeak = data.toShort(3, true); - d->albumGain = data.toShort(5, true); - d->albumPeak = data.toShort(7, true); - } - } - - else if(packetType == "SE") { - break; - } - - else { - file->seek(dataSize, File::Current); - } - } -} - -void MPC::Properties::readSV7(const ByteVector &data) -{ - if(data.startsWith("MP+")) { - d->version = data[3] & 15; - if(d->version < 7) - return; - - d->totalFrames = data.toUInt(4, 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.toUInt(5, false); - - d->trackGain = data.toShort(14, false); - d->trackPeak = data.toShort(12, false); - d->albumGain = data.toShort(18, false); - d->albumPeak = data.toShort(16, false); - - // convert gain info - if(d->trackGain != 0) { - int tmp = (int)((64.82 - (short)d->trackGain / 100.) * 256. + .5); - if(tmp >= (1 << 16) || tmp < 0) tmp = 0; - d->trackGain = tmp; - } - - if(d->albumGain != 0) { - int tmp = (int)((64.82 - d->albumGain / 100.) * 256. + .5); - if(tmp >= (1 << 16) || tmp < 0) tmp = 0; - d->albumGain = tmp; - } - - if (d->trackPeak != 0) - d->trackPeak = (int)(log10((double)d->trackPeak) * 20 * 256 + .5); - - if (d->albumPeak != 0) - d->albumPeak = (int)(log10((double)d->albumPeak) * 20 * 256 + .5); - - bool trueGapless = (gapless >> 31) & 0x0001; - if(trueGapless) { - uint lastFrameSamples = (gapless >> 20) & 0x07FF; - d->sampleFrames = d->totalFrames * 1152 - lastFrameSamples; - } - else - d->sampleFrames = d->totalFrames * 1152 - 576; - } - else { - uint headerData = data.toUInt(0, false); - - d->bitrate = (headerData >> 23) & 0x01ff; - d->version = (headerData >> 11) & 0x03ff; - d->sampleRate = 44100; - d->channels = 2; - - if(d->version >= 5) - d->totalFrames = data.toUInt(4, false); - else - d->totalFrames = data.toUShort(6, false); - - d->sampleFrames = d->totalFrames * 1152 - 576; - } - - d->length = d->sampleRate > 0 ? (d->sampleFrames + (d->sampleRate / 2)) / d->sampleRate : 0; - - if(!d->bitrate) - d->bitrate = d->length > 0 ? ((d->streamLength * 8L) / d->length) / 1000 : 0; -} - diff --git a/taglib/taglib/mpc/mpcproperties.h b/taglib/taglib/mpc/mpcproperties.h deleted file mode 100644 index adf40d8..0000000 --- a/taglib/taglib/mpc/mpcproperties.h +++ /dev/null @@ -1,122 +0,0 @@ -/*************************************************************************** - copyright : (C) 2004 by Allan Sandfeld Jensen - email : kde@carewolf.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_MPCPROPERTIES_H -#define TAGLIB_MPCPROPERTIES_H - -#include "taglib_export.h" -#include "audioproperties.h" - -namespace TagLib { - - namespace MPC { - - class File; - - static const uint HeaderSize = 8*7; - - //! An implementation of audio property reading for MPC - - /*! - * This reads the data from an MPC stream found in the AudioProperties - * API. - */ - - class TAGLIB_EXPORT Properties : public AudioProperties - { - public: - /*! - * Create an instance of MPC::Properties with the data read from the - * ByteVector \a data. - * - * This constructor is deprecated. It only works for MPC version up to 7. - */ - Properties(const ByteVector &data, long streamLength, ReadStyle style = Average); - - /*! - * Create an instance of MPC::Properties with the data read directly - * from a MPC::File. - */ - Properties(File *file, long streamLength, ReadStyle style = Average); - - /*! - * Destroys this MPC::Properties instance. - */ - virtual ~Properties(); - - // Reimplementations. - - virtual int length() const; - virtual int bitrate() const; - virtual int sampleRate() const; - virtual int channels() const; - - /*! - * Returns the version of the bitstream (SV4-SV8) - */ - int mpcVersion() const; - uint totalFrames() const; - uint sampleFrames() const; - - /*! - * Returns the track gain as an integer value, - * to convert to dB: trackGain in dB = 64.82 - (trackGain / 256) - */ - int trackGain() const; - - /*! - * Returns the track peak as an integer value, - * to convert to dB: trackPeak in dB = trackPeak / 256 - * to convert to floating [-1..1]: trackPeak = 10^(trackPeak / 256 / 20)/32768 - */ - int trackPeak() const; - - /*! - * Returns the album gain as an integer value, - * to convert to dB: albumGain in dB = 64.82 - (albumGain / 256) - */ - int albumGain() const; - - /*! - * Returns the album peak as an integer value, - * to convert to dB: albumPeak in dB = albumPeak / 256 - * to convert to floating [-1..1]: albumPeak = 10^(albumPeak / 256 / 20)/32768 - */ - int albumPeak() const; - - private: - Properties(const Properties &); - Properties &operator=(const Properties &); - - void readSV7(const ByteVector &data); - void readSV8(File *file); - - class PropertiesPrivate; - PropertiesPrivate *d; - }; - } -} - -#endif diff --git a/taglib/taglib/mpeg/id3v1/id3v1genres.cpp b/taglib/taglib/mpeg/id3v1/id3v1genres.cpp deleted file mode 100644 index eba4c52..0000000 --- a/taglib/taglib/mpeg/id3v1/id3v1genres.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org -***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include "id3v1genres.h" - -using namespace TagLib; - -namespace TagLib { - namespace ID3v1 { - - static const int genresSize = 148; - static const String genres[] = { - "Blues", - "Classic Rock", - "Country", - "Dance", - "Disco", - "Funk", - "Grunge", - "Hip-Hop", - "Jazz", - "Metal", - "New Age", - "Oldies", - "Other", - "Pop", - "R&B", - "Rap", - "Reggae", - "Rock", - "Techno", - "Industrial", - "Alternative", - "Ska", - "Death Metal", - "Pranks", - "Soundtrack", - "Euro-Techno", - "Ambient", - "Trip-Hop", - "Vocal", - "Jazz+Funk", - "Fusion", - "Trance", - "Classical", - "Instrumental", - "Acid", - "House", - "Game", - "Sound Clip", - "Gospel", - "Noise", - "Alternative Rock", - "Bass", - "Soul", - "Punk", - "Space", - "Meditative", - "Instrumental Pop", - "Instrumental Rock", - "Ethnic", - "Gothic", - "Darkwave", - "Techno-Industrial", - "Electronic", - "Pop-Folk", - "Eurodance", - "Dream", - "Southern Rock", - "Comedy", - "Cult", - "Gangsta", - "Top 40", - "Christian Rap", - "Pop/Funk", - "Jungle", - "Native American", - "Cabaret", - "New Wave", - "Psychedelic", - "Rave", - "Showtunes", - "Trailer", - "Lo-Fi", - "Tribal", - "Acid Punk", - "Acid Jazz", - "Polka", - "Retro", - "Musical", - "Rock & Roll", - "Hard Rock", - "Folk", - "Folk/Rock", - "National Folk", - "Swing", - "Fusion", - "Bebob", - "Latin", - "Revival", - "Celtic", - "Bluegrass", - "Avantgarde", - "Gothic Rock", - "Progressive Rock", - "Psychedelic Rock", - "Symphonic Rock", - "Slow Rock", - "Big Band", - "Chorus", - "Easy Listening", - "Acoustic", - "Humour", - "Speech", - "Chanson", - "Opera", - "Chamber Music", - "Sonata", - "Symphony", - "Booty Bass", - "Primus", - "Porn Groove", - "Satire", - "Slow Jam", - "Club", - "Tango", - "Samba", - "Folklore", - "Ballad", - "Power Ballad", - "Rhythmic Soul", - "Freestyle", - "Duet", - "Punk Rock", - "Drum Solo", - "A Cappella", - "Euro-House", - "Dance Hall", - "Goa", - "Drum & Bass", - "Club-House", - "Hardcore", - "Terror", - "Indie", - "BritPop", - "Negerpunk", - "Polsk Punk", - "Beat", - "Christian Gangsta Rap", - "Heavy Metal", - "Black Metal", - "Crossover", - "Contemporary Christian", - "Christian Rock", - "Merengue", - "Salsa", - "Thrash Metal", - "Anime", - "Jpop", - "Synthpop" - }; - } -} - -StringList ID3v1::genreList() -{ - static StringList l; - if(l.isEmpty()) { - for(int i = 0; i < genresSize; i++) - l.append(genres[i]); - } - return l; -} - -ID3v1::GenreMap ID3v1::genreMap() -{ - static GenreMap m; - if(m.isEmpty()) { - for(int i = 0; i < genresSize; i++) - m.insert(genres[i], i); - } - return m; -} - -String ID3v1::genre(int i) -{ - if(i >= 0 && i < genresSize) - return genres[i] + String::null; // always make a copy - return String::null; -} - -int ID3v1::genreIndex(const String &name) -{ - if(genreMap().contains(name)) - return genreMap()[name]; - return 255; -} diff --git a/taglib/taglib/mpeg/id3v1/id3v1genres.h b/taglib/taglib/mpeg/id3v1/id3v1genres.h deleted file mode 100644 index 271f725..0000000 --- a/taglib/taglib/mpeg/id3v1/id3v1genres.h +++ /dev/null @@ -1,66 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_ID3V1GENRE_H -#define TAGLIB_ID3V1GENRE_H - -#include "tmap.h" -#include "tstringlist.h" -#include "taglib_export.h" - -namespace TagLib { - namespace ID3v1 { - - typedef Map<String, int> GenreMap; - - /*! - * Returns the list of canonical ID3v1 genre names in the order that they - * are listed in the standard. - */ - StringList TAGLIB_EXPORT genreList(); - - /*! - * A "reverse mapping" that goes from the canonical ID3v1 genre name to the - * respective genre number. genreMap()["Rock"] == - */ - GenreMap TAGLIB_EXPORT genreMap(); - - /*! - * Returns the name of the genre at \a index in the ID3v1 genre list. If - * \a index is out of range -- less than zero or greater than 146 -- a null - * string will be returned. - */ - String TAGLIB_EXPORT genre(int index); - - /*! - * Returns the genre index for the (case sensitive) genre \a name. If the - * genre is not in the list 255 (which signifies an unknown genre in ID3v1) - * will be returned. - */ - int TAGLIB_EXPORT genreIndex(const String &name); - } -} - -#endif diff --git a/taglib/taglib/mpeg/id3v1/id3v1tag.cpp b/taglib/taglib/mpeg/id3v1/id3v1tag.cpp deleted file mode 100644 index 9fc8cfd..0000000 --- a/taglib/taglib/mpeg/id3v1/id3v1tag.cpp +++ /dev/null @@ -1,265 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <tdebug.h> -#include <tfile.h> - -#include "id3v1tag.h" -#include "id3v1genres.h" - -using namespace TagLib; -using namespace ID3v1; - -class ID3v1::Tag::TagPrivate -{ -public: - TagPrivate() : file(0), tagOffset(-1), track(0), genre(255) {} - - File *file; - long tagOffset; - - String title; - String artist; - String album; - String year; - String comment; - uchar track; - uchar genre; - - static const StringHandler *stringHandler; -}; - -static const StringHandler defaultStringHandler; -const ID3v1::StringHandler *ID3v1::Tag::TagPrivate::stringHandler = &defaultStringHandler; - -//////////////////////////////////////////////////////////////////////////////// -// StringHandler implementation -//////////////////////////////////////////////////////////////////////////////// - -StringHandler::StringHandler() -{ -} - -String ID3v1::StringHandler::parse(const ByteVector &data) const -{ - return String(data, String::Latin1).stripWhiteSpace(); -} - -ByteVector ID3v1::StringHandler::render(const String &s) const -{ - if(!s.isLatin1()) - { - return ByteVector(); - } - - return s.data(String::Latin1); -} - -//////////////////////////////////////////////////////////////////////////////// -// public methods -//////////////////////////////////////////////////////////////////////////////// - -ID3v1::Tag::Tag() : TagLib::Tag() -{ - d = new TagPrivate; -} - -ID3v1::Tag::Tag(File *file, long tagOffset) : TagLib::Tag() -{ - d = new TagPrivate; - d->file = file; - d->tagOffset = tagOffset; - - read(); -} - -ID3v1::Tag::~Tag() -{ - delete d; -} - -ByteVector ID3v1::Tag::render() const -{ - ByteVector data; - - data.append(fileIdentifier()); - data.append(TagPrivate::stringHandler->render(d->title).resize(30)); - data.append(TagPrivate::stringHandler->render(d->artist).resize(30)); - data.append(TagPrivate::stringHandler->render(d->album).resize(30)); - data.append(TagPrivate::stringHandler->render(d->year).resize(4)); - data.append(TagPrivate::stringHandler->render(d->comment).resize(28)); - data.append(char(0)); - data.append(char(d->track)); - data.append(char(d->genre)); - - return data; -} - -ByteVector ID3v1::Tag::fileIdentifier() -{ - return ByteVector::fromCString("TAG"); -} - -String ID3v1::Tag::title() const -{ - return d->title; -} - -String ID3v1::Tag::artist() const -{ - return d->artist; -} - -String ID3v1::Tag::album() const -{ - return d->album; -} - -String ID3v1::Tag::comment() const -{ - return d->comment; -} - -String ID3v1::Tag::genre() const -{ - return ID3v1::genre(d->genre); -} - -TagLib::uint ID3v1::Tag::year() const -{ - return d->year.toInt(); -} - -TagLib::uint ID3v1::Tag::track() const -{ - return d->track; -} - -void ID3v1::Tag::setTitle(const String &s) -{ - d->title = s; -} - -void ID3v1::Tag::setArtist(const String &s) -{ - d->artist = s; -} - -void ID3v1::Tag::setAlbum(const String &s) -{ - d->album = s; -} - -void ID3v1::Tag::setComment(const String &s) -{ - d->comment = s; -} - -void ID3v1::Tag::setGenre(const String &s) -{ - d->genre = ID3v1::genreIndex(s); -} - -void ID3v1::Tag::setYear(TagLib::uint i) -{ - d->year = i > 0 ? String::number(i) : String::null; -} - -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 (handler) - TagPrivate::stringHandler = handler; - else - TagPrivate::stringHandler = &defaultStringHandler; -} - -//////////////////////////////////////////////////////////////////////////////// -// protected methods -//////////////////////////////////////////////////////////////////////////////// - -void ID3v1::Tag::read() -{ - if(d->file && d->file->isValid()) { - d->file->seek(d->tagOffset); - // read the tag -- always 128 bytes - ByteVector data = d->file->readBlock(128); - - // some initial sanity checking - if(data.size() == 128 && data.startsWith("TAG")) - parse(data); - else - debug("ID3v1 tag is not valid or could not be read at the specified offset."); - } -} - -void ID3v1::Tag::parse(const ByteVector &data) -{ - int offset = 3; - - d->title = TagPrivate::stringHandler->parse(data.mid(offset, 30)); - offset += 30; - - d->artist = TagPrivate::stringHandler->parse(data.mid(offset, 30)); - offset += 30; - - d->album = TagPrivate::stringHandler->parse(data.mid(offset, 30)); - offset += 30; - - d->year = TagPrivate::stringHandler->parse(data.mid(offset, 4)); - offset += 4; - - // Check for ID3v1.1 -- Note that ID3v1 *does not* support "track zero" -- this - // is not a bug in TagLib. Since a zeroed byte is what we would expect to - // indicate the end of a C-String, specifically the comment string, a value of - // zero must be assumed to be just that. - - if(data[offset + 28] == 0 && data[offset + 29] != 0) { - // ID3v1.1 detected - - d->comment = TagPrivate::stringHandler->parse(data.mid(offset, 28)); - d->track = uchar(data[offset + 29]); - } - else - d->comment = data.mid(offset, 30); - - offset += 30; - - d->genre = uchar(data[offset]); -} diff --git a/taglib/taglib/mpeg/id3v1/id3v1tag.h b/taglib/taglib/mpeg/id3v1/id3v1tag.h deleted file mode 100644 index 7b26d02..0000000 --- a/taglib/taglib/mpeg/id3v1/id3v1tag.h +++ /dev/null @@ -1,202 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_ID3V1TAG_H -#define TAGLIB_ID3V1TAG_H - -#include "tag.h" -#include "tbytevector.h" -#include "taglib_export.h" - -namespace TagLib { - - class File; - - //! An ID3v1 implementation - - namespace ID3v1 { - - //! A abstraction for the string to data encoding in ID3v1 tags. - - /*! - * ID3v1 should in theory always contain ISO-8859-1 (Latin1) data. In - * practice it does not. TagLib by default only supports ISO-8859-1 data - * in ID3v1 tags. - * - * However by subclassing this class and reimplementing parse() and render() - * and setting your reimplementation as the default with - * ID3v1::Tag::setStringHandler() you can define how you would like these - * transformations to be done. - * - * \warning It is advisable <b>not</b> to write non-ISO-8859-1 data to ID3v1 - * tags. Please consider disabling the writing of ID3v1 tags in the case - * that the data is not ISO-8859-1. - * - * \see ID3v1::Tag::setStringHandler() - */ - - class TAGLIB_EXPORT StringHandler - { - TAGLIB_IGNORE_MISSING_DESTRUCTOR - public: - // BIC: Add virtual destructor. - StringHandler(); - - /*! - * 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; - - /*! - * Encode a ByteVector with the data from \a s. The default implementation - * assumes that \a s is an ISO-8859-1 (Latin1) string. If the string is - * does not conform to ISO-8859-1, no value is written. - * - * \warning It is recommended that you <b>not</b> override this method, but - * instead do not write an ID3v1 tag in the case that the data is not - * ISO-8859-1. - */ - virtual ByteVector render(const String &s) const; - }; - - //! The main class in the ID3v1 implementation - - /*! - * This is an implementation of the ID3v1 format. ID3v1 is both the simplist - * and most common of tag formats but is rather limited. Because of its - * pervasiveness and the way that applications have been written around the - * fields that it provides, the generic TagLib::Tag API is a mirror of what is - * provided by ID3v1. - * - * ID3v1 tags should generally only contain Latin1 information. However because - * many applications do not follow this rule there is now support for overriding - * the ID3v1 string handling using the ID3v1::StringHandler class. Please see - * the documentation for that class for more information. - * - * \see StringHandler - * - * \note Most fields are truncated to a maximum of 28-30 bytes. The - * truncation happens automatically when the tag is rendered. - */ - - class TAGLIB_EXPORT Tag : public TagLib::Tag - { - public: - /*! - * Create an ID3v1 tag with default values. - */ - Tag(); - - /*! - * Create an ID3v1 tag and parse the data in \a file starting at - * \a tagOffset. - */ - Tag(File *file, long tagOffset); - - /*! - * Destroys this Tag instance. - */ - virtual ~Tag(); - - /*! - * Renders the in memory values to a ByteVector suitable for writing to - * the file. - */ - ByteVector render() const; - - /*! - * Returns the string "TAG" suitable for usage in locating the tag in a - * file. - */ - static ByteVector fileIdentifier(); - - // Reimplementations. - - virtual String title() const; - virtual String artist() const; - virtual String album() const; - virtual String comment() const; - virtual String genre() 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(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 - */ - static void setStringHandler(const StringHandler *handler); - - protected: - /*! - * Reads from the file specified in the constructor. - */ - void read(); - /*! - * Pareses the body of the tag in \a data. - */ - void parse(const ByteVector &data); - - private: - Tag(const Tag &); - Tag &operator=(const Tag &); - - class TagPrivate; - TagPrivate *d; - }; - } -} - -#endif diff --git a/taglib/taglib/mpeg/id3v2/frames/attachedpictureframe.cpp b/taglib/taglib/mpeg/id3v2/frames/attachedpictureframe.cpp deleted file mode 100644 index 86f8e35..0000000 --- a/taglib/taglib/mpeg/id3v2/frames/attachedpictureframe.cpp +++ /dev/null @@ -1,222 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include "attachedpictureframe.h" - -#include <tstringlist.h> -#include <tdebug.h> - -using namespace TagLib; -using namespace ID3v2; - -class AttachedPictureFrame::AttachedPictureFramePrivate -{ -public: - AttachedPictureFramePrivate() : textEncoding(String::Latin1), - type(AttachedPictureFrame::Other) {} - - String::Type textEncoding; - String mimeType; - AttachedPictureFrame::Type type; - String description; - ByteVector data; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -AttachedPictureFrame::AttachedPictureFrame() : Frame("APIC") -{ - d = new AttachedPictureFramePrivate; -} - -AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data) : Frame(data) -{ - d = new AttachedPictureFramePrivate; - setData(data); -} - -AttachedPictureFrame::~AttachedPictureFrame() -{ - delete d; -} - -String AttachedPictureFrame::toString() const -{ - String s = "[" + d->mimeType + "]"; - return d->description.isEmpty() ? s : d->description + " " + s; -} - -String::Type AttachedPictureFrame::textEncoding() const -{ - return d->textEncoding; -} - -void AttachedPictureFrame::setTextEncoding(String::Type t) -{ - d->textEncoding = t; -} - -String AttachedPictureFrame::mimeType() const -{ - return d->mimeType; -} - -void AttachedPictureFrame::setMimeType(const String &m) -{ - d->mimeType = m; -} - -AttachedPictureFrame::Type AttachedPictureFrame::type() const -{ - return d->type; -} - -void AttachedPictureFrame::setType(Type t) -{ - d->type = t; -} - -String AttachedPictureFrame::description() const -{ - return d->description; -} - -void AttachedPictureFrame::setDescription(const String &desc) -{ - d->description = desc; -} - -ByteVector AttachedPictureFrame::picture() const -{ - return d->data; -} - -void AttachedPictureFrame::setPicture(const ByteVector &p) -{ - d->data = p; -} - -//////////////////////////////////////////////////////////////////////////////// -// protected members -//////////////////////////////////////////////////////////////////////////////// - -void AttachedPictureFrame::parseFields(const ByteVector &data) -{ - if(data.size() < 5) { - debug("A picture frame must contain at least 5 bytes."); - return; - } - - d->textEncoding = String::Type(data[0]); - - int pos = 1; - - d->mimeType = readStringField(data, String::Latin1, &pos); - /* Now we need at least two more bytes available */ - if (uint(pos) + 1 >= data.size()) { - debug("Truncated picture frame."); - return; - } - - d->type = (TagLib::ID3v2::AttachedPictureFrame::Type)data[pos++]; - d->description = readStringField(data, d->textEncoding, &pos); - - d->data = data.mid(pos); -} - -ByteVector AttachedPictureFrame::renderFields() const -{ - ByteVector data; - - String::Type encoding = checkTextEncoding(d->description, d->textEncoding); - - data.append(char(encoding)); - data.append(d->mimeType.data(String::Latin1)); - data.append(textDelimiter(String::Latin1)); - data.append(char(d->type)); - data.append(d->description.data(encoding)); - data.append(textDelimiter(encoding)); - data.append(d->data); - - return data; -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data, Header *h) : Frame(h) -{ - d = new AttachedPictureFramePrivate; - parseFields(fieldData(data)); -} - -//////////////////////////////////////////////////////////////////////////////// -// support for ID3v2.2 PIC frames -//////////////////////////////////////////////////////////////////////////////// - -void AttachedPictureFrameV22::parseFields(const ByteVector &data) -{ - if(data.size() < 5) { - debug("A picture frame must contain at least 5 bytes."); - return; - } - - d->textEncoding = String::Type(data[0]); - - int pos = 1; - - String fixedString = String(data.mid(pos, 3), String::Latin1); - pos += 3; - // convert fixed string image type to mime string - if (fixedString.upper() == "JPG") { - d->mimeType = "image/jpeg"; - } else if (fixedString.upper() == "PNG") { - d->mimeType = "image/png"; - } else { - debug("probably unsupported image type"); - d->mimeType = "image/" + fixedString; - } - - d->type = (TagLib::ID3v2::AttachedPictureFrame::Type)data[pos++]; - d->description = readStringField(data, d->textEncoding, &pos); - - d->data = data.mid(pos); -} - -AttachedPictureFrameV22::AttachedPictureFrameV22(const ByteVector &data, Header *h) -{ - // set v2.2 header to make fieldData work correctly - setHeader(h, true); - - parseFields(fieldData(data)); - - // now set the v2.4 header - Frame::Header *newHeader = new Frame::Header("APIC"); - newHeader->setFrameSize(h->frameSize()); - setHeader(newHeader, true); -} diff --git a/taglib/taglib/mpeg/id3v2/frames/attachedpictureframe.h b/taglib/taglib/mpeg/id3v2/frames/attachedpictureframe.h deleted file mode 100644 index 55067bd..0000000 --- a/taglib/taglib/mpeg/id3v2/frames/attachedpictureframe.h +++ /dev/null @@ -1,230 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_ATTACHEDPICTUREFRAME_H -#define TAGLIB_ATTACHEDPICTUREFRAME_H - -#include "id3v2frame.h" -#include "id3v2header.h" -#include "taglib_export.h" - -namespace TagLib { - - namespace ID3v2 { - - //! An ID3v2 attached picture frame implementation - - /*! - * This is an implementation of ID3v2 attached pictures. Pictures may be - * included in tags, one per APIC frame (but there may be multiple APIC - * frames in a single tag). These pictures are usually in either JPEG or - * PNG format. - */ - - class TAGLIB_EXPORT AttachedPictureFrame : public Frame - { - friend class FrameFactory; - - public: - - /*! - * This describes the function or content of the picture. - */ - enum Type { - //! A type not enumerated below - Other = 0x00, - //! 32x32 PNG image that should be used as the file icon - FileIcon = 0x01, - //! File icon of a different size or format - OtherFileIcon = 0x02, - //! Front cover image of the album - FrontCover = 0x03, - //! Back cover image of the album - BackCover = 0x04, - //! Inside leaflet page of the album - LeafletPage = 0x05, - //! Image from the album itself - Media = 0x06, - //! Picture of the lead artist or soloist - LeadArtist = 0x07, - //! Picture of the artist or performer - Artist = 0x08, - //! Picture of the conductor - Conductor = 0x09, - //! Picture of the band or orchestra - Band = 0x0A, - //! Picture of the composer - Composer = 0x0B, - //! Picture of the lyricist or text writer - Lyricist = 0x0C, - //! Picture of the recording location or studio - RecordingLocation = 0x0D, - //! Picture of the artists during recording - DuringRecording = 0x0E, - //! Picture of the artists during performance - DuringPerformance = 0x0F, - //! Picture from a movie or video related to the track - MovieScreenCapture = 0x10, - //! Picture of a large, coloured fish - ColouredFish = 0x11, - //! Illustration related to the track - Illustration = 0x12, - //! Logo of the band or performer - BandLogo = 0x13, - //! Logo of the publisher (record company) - PublisherLogo = 0x14 - }; - - /*! - * Constructs an empty picture frame. The description, content and text - * encoding should be set manually. - */ - AttachedPictureFrame(); - - /*! - * Constructs an AttachedPicture frame based on \a data. - */ - explicit AttachedPictureFrame(const ByteVector &data); - - /*! - * Destroys the AttahcedPictureFrame instance. - */ - virtual ~AttachedPictureFrame(); - - /*! - * Returns a string containing the description and mime-type - */ - virtual String toString() const; - - /*! - * Returns the text encoding used for the description. - * - * \see setTextEncoding() - * \see description() - */ - String::Type textEncoding() const; - - /*! - * Set the text encoding used for the description. - * - * \see description() - */ - void setTextEncoding(String::Type t); - - /*! - * Returns the mime type of the image. This should in most cases be - * "image/png" or "image/jpeg". - */ - String mimeType() const; - - /*! - * Sets the mime type of the image. This should in most cases be - * "image/png" or "image/jpeg". - */ - void setMimeType(const String &m); - - /*! - * Returns the type of the image. - * - * \see Type - * \see setType() - */ - Type type() const; - - /*! - * Sets the type for the image. - * - * \see Type - * \see type() - */ - void setType(Type t); - - /*! - * Returns a text description of the image. - * - * \see setDescription() - * \see textEncoding() - * \see setTextEncoding() - */ - - String description() const; - - /*! - * Sets a textual description of the image to \a desc. - * - * \see description() - * \see textEncoding() - * \see setTextEncoding() - */ - - void setDescription(const String &desc); - - /*! - * Returns the image data as a ByteVector. - * - * \note ByteVector has a data() method that returns a const char * which - * should make it easy to export this data to external programs. - * - * \see setPicture() - * \see mimeType() - */ - ByteVector picture() const; - - /*! - * Sets the image data to \a p. \a p should be of the type specified in - * this frame's mime-type specification. - * - * \see picture() - * \see mimeType() - * \see setMimeType() - */ - void setPicture(const ByteVector &p); - - protected: - virtual void parseFields(const ByteVector &data); - virtual ByteVector renderFields() const; - class AttachedPictureFramePrivate; - AttachedPictureFramePrivate *d; - - private: - AttachedPictureFrame(const AttachedPictureFrame &); - AttachedPictureFrame &operator=(const AttachedPictureFrame &); - AttachedPictureFrame(const ByteVector &data, Header *h); - - }; - - //! support for ID3v2.2 PIC frames - class TAGLIB_EXPORT AttachedPictureFrameV22 : public AttachedPictureFrame - { - protected: - virtual void parseFields(const ByteVector &data); - private: - AttachedPictureFrameV22(const ByteVector &data, Header *h); - friend class FrameFactory; - }; - } -} - -#endif diff --git a/taglib/taglib/mpeg/id3v2/frames/commentsframe.cpp b/taglib/taglib/mpeg/id3v2/frames/commentsframe.cpp deleted file mode 100644 index deaa9d9..0000000 --- a/taglib/taglib/mpeg/id3v2/frames/commentsframe.cpp +++ /dev/null @@ -1,197 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <tbytevectorlist.h> -#include <id3v2tag.h> -#include <tdebug.h> -#include <tstringlist.h> - -#include "commentsframe.h" -#include "tpropertymap.h" - -using namespace TagLib; -using namespace ID3v2; - -class CommentsFrame::CommentsFramePrivate -{ -public: - CommentsFramePrivate() : textEncoding(String::Latin1) {} - String::Type textEncoding; - ByteVector language; - String description; - String text; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -CommentsFrame::CommentsFrame(String::Type encoding) : Frame("COMM") -{ - d = new CommentsFramePrivate; - d->textEncoding = encoding; -} - -CommentsFrame::CommentsFrame(const ByteVector &data) : Frame(data) -{ - d = new CommentsFramePrivate; - setData(data); -} - -CommentsFrame::~CommentsFrame() -{ - delete d; -} - -String CommentsFrame::toString() const -{ - return d->text; -} - -ByteVector CommentsFrame::language() const -{ - return d->language; -} - -String CommentsFrame::description() const -{ - return d->description; -} - -String CommentsFrame::text() const -{ - return d->text; -} - -void CommentsFrame::setLanguage(const ByteVector &languageEncoding) -{ - d->language = languageEncoding.mid(0, 3); -} - -void CommentsFrame::setDescription(const String &s) -{ - d->description = s; -} - -void CommentsFrame::setText(const String &s) -{ - d->text = s; -} - -String::Type CommentsFrame::textEncoding() const -{ - return d->textEncoding; -} - -void CommentsFrame::setTextEncoding(String::Type encoding) -{ - d->textEncoding = encoding; -} - -PropertyMap CommentsFrame::asProperties() const -{ - String key = description().upper(); - PropertyMap map; - if(key.isEmpty() || key == "COMMENT") - map.insert("COMMENT", text()); - else if(key.isNull()) - map.unsupportedData().append(L"COMM/" + description()); - else - map.insert("COMMENT:" + key, text()); - return map; -} - -CommentsFrame *CommentsFrame::findByDescription(const ID3v2::Tag *tag, const String &d) // static -{ - ID3v2::FrameList comments = tag->frameList("COMM"); - - for(ID3v2::FrameList::ConstIterator it = comments.begin(); - it != comments.end(); - ++it) - { - CommentsFrame *frame = dynamic_cast<CommentsFrame *>(*it); - if(frame && frame->description() == d) - return frame; - } - - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// -// protected members -//////////////////////////////////////////////////////////////////////////////// - -void CommentsFrame::parseFields(const ByteVector &data) -{ - if(data.size() < 5) { - debug("A comment frame must contain at least 5 bytes."); - return; - } - - d->textEncoding = String::Type(data[0]); - d->language = data.mid(1, 3); - - int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2; - - ByteVectorList l = ByteVectorList::split(data.mid(4), textDelimiter(d->textEncoding), byteAlign, 2); - - if(l.size() == 2) { - 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); - } - } -} - -ByteVector CommentsFrame::renderFields() const -{ - ByteVector v; - - String::Type encoding = d->textEncoding; - - encoding = checkTextEncoding(d->description, encoding); - encoding = checkTextEncoding(d->text, encoding); - - v.append(char(encoding)); - v.append(d->language.size() == 3 ? d->language : "XXX"); - v.append(d->description.data(encoding)); - v.append(textDelimiter(encoding)); - v.append(d->text.data(encoding)); - - return v; -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -CommentsFrame::CommentsFrame(const ByteVector &data, Header *h) : Frame(h) -{ - d = new CommentsFramePrivate(); - parseFields(fieldData(data)); -} diff --git a/taglib/taglib/mpeg/id3v2/frames/commentsframe.h b/taglib/taglib/mpeg/id3v2/frames/commentsframe.h deleted file mode 100644 index f65f6f0..0000000 --- a/taglib/taglib/mpeg/id3v2/frames/commentsframe.h +++ /dev/null @@ -1,179 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_COMMENTSFRAME_H -#define TAGLIB_COMMENTSFRAME_H - -#include "id3v2frame.h" -#include "taglib_export.h" - -namespace TagLib { - - namespace ID3v2 { - - //! An implementation of ID3v2 comments - - /*! - * This implements the ID3v2 comment format. An ID3v2 comment concists of - * a language encoding, a description and a single text field. - */ - - class TAGLIB_EXPORT CommentsFrame : public Frame - { - friend class FrameFactory; - - public: - /*! - * Construct an empty comment frame that will use the text encoding - * \a encoding. - */ - explicit CommentsFrame(String::Type encoding = String::Latin1); - - /*! - * Construct a comment based on the data in \a data. - */ - explicit CommentsFrame(const ByteVector &data); - - /*! - * Destroys this CommentFrame instance. - */ - virtual ~CommentsFrame(); - - /*! - * Returns the text of this comment. - * - * \see text() - */ - virtual String toString() const; - - /*! - * Returns the language encoding as a 3 byte encoding as specified by - * <a href="http://en.wikipedia.org/wiki/ISO_639">ISO-639-2</a>. - * - * \note Most taggers simply ignore this value. - * - * \see setLanguage() - */ - ByteVector language() const; - - /*! - * Returns the description of this comment. - * - * \note Most taggers simply ignore this value. - * - * \see setDescription() - */ - String description() const; - - /*! - * Returns the text of this comment. - * - * \see setText() - */ - String text() const; - - /*! - * Set the language using the 3 byte language code from - * <a href="http://en.wikipedia.org/wiki/ISO_639">ISO-639-2</a> to - * \a languageCode. - * - * \see language() - */ - void setLanguage(const ByteVector &languageCode); - - /*! - * Sets the description of the comment to \a s. - * - * \see decription() - */ - void setDescription(const String &s); - - /*! - * Sets the text portion of the comment to \a s. - * - * \see text() - */ - virtual void setText(const String &s); - - /*! - * 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); - - /*! - * Parses this frame as PropertyMap with a single key. - * - if description() is empty or "COMMENT", the key will be "COMMENT" - * - if description() is not a valid PropertyMap key, the frame will be - * marked unsupported by an entry "COMM/<description>" in the unsupportedData() - * attribute of the returned map. - * - otherwise, the key will be "COMMENT:<description>" - * - The single value will be the frame's text(). - */ - PropertyMap asProperties() const; - - /*! - * Comments each have a unique description. This searches for a comment - * frame with the decription \a d and returns a pointer to it. If no - * frame is found that matches the given description null is returned. - * - * \see description() - */ - static CommentsFrame *findByDescription(const Tag *tag, const String &d); - - protected: - // Reimplementations. - - virtual void parseFields(const ByteVector &data); - virtual ByteVector renderFields() const; - - private: - /*! - * The constructor used by the FrameFactory. - */ - CommentsFrame(const ByteVector &data, Header *h); - CommentsFrame(const CommentsFrame &); - CommentsFrame &operator=(const CommentsFrame &); - - class CommentsFramePrivate; - CommentsFramePrivate *d; - }; - - } -} -#endif diff --git a/taglib/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.cpp b/taglib/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.cpp deleted file mode 100644 index fa3509b..0000000 --- a/taglib/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.cpp +++ /dev/null @@ -1,176 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - copyright : (C) 2006 by Aaron VonderHaar - email : avh4@users.sourceforge.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <tdebug.h> - -#include "generalencapsulatedobjectframe.h" - -using namespace TagLib; -using namespace ID3v2; - -class GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFramePrivate -{ -public: - GeneralEncapsulatedObjectFramePrivate() : textEncoding(String::Latin1) {} - - String::Type textEncoding; - String mimeType; - String fileName; - String description; - ByteVector data; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame() : Frame("GEOB") -{ - d = new GeneralEncapsulatedObjectFramePrivate; -} - -GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data) : Frame(data) -{ - d = new GeneralEncapsulatedObjectFramePrivate; - setData(data); -} - -GeneralEncapsulatedObjectFrame::~GeneralEncapsulatedObjectFrame() -{ - delete d; -} - -String GeneralEncapsulatedObjectFrame::toString() const -{ - String text = "[" + d->mimeType + "]"; - - if(!d->fileName.isEmpty()) - text += " " + d->fileName; - - if(!d->description.isEmpty()) - text += " \"" + d->description + "\""; - - return text; -} - -String::Type GeneralEncapsulatedObjectFrame::textEncoding() const -{ - return d->textEncoding; -} - -void GeneralEncapsulatedObjectFrame::setTextEncoding(String::Type encoding) -{ - d->textEncoding = encoding; -} - -String GeneralEncapsulatedObjectFrame::mimeType() const -{ - return d->mimeType; -} - -void GeneralEncapsulatedObjectFrame::setMimeType(const String &type) -{ - d->mimeType = type; -} - -String GeneralEncapsulatedObjectFrame::fileName() const -{ - return d->fileName; -} - -void GeneralEncapsulatedObjectFrame::setFileName(const String &name) -{ - d->fileName = name; -} - -String GeneralEncapsulatedObjectFrame::description() const -{ - return d->description; -} - -void GeneralEncapsulatedObjectFrame::setDescription(const String &desc) -{ - d->description = desc; -} - -ByteVector GeneralEncapsulatedObjectFrame::object() const -{ - return d->data; -} - -void GeneralEncapsulatedObjectFrame::setObject(const ByteVector &data) -{ - d->data = data; -} - -//////////////////////////////////////////////////////////////////////////////// -// protected members -//////////////////////////////////////////////////////////////////////////////// - -void GeneralEncapsulatedObjectFrame::parseFields(const ByteVector &data) -{ - if(data.size() < 4) { - debug("An object frame must contain at least 4 bytes."); - return; - } - - d->textEncoding = String::Type(data[0]); - - int pos = 1; - - d->mimeType = readStringField(data, String::Latin1, &pos); - d->fileName = readStringField(data, d->textEncoding, &pos); - d->description = readStringField(data, d->textEncoding, &pos); - - d->data = data.mid(pos); -} - -ByteVector GeneralEncapsulatedObjectFrame::renderFields() const -{ - ByteVector data; - - data.append(char(d->textEncoding)); - data.append(d->mimeType.data(String::Latin1)); - data.append(textDelimiter(String::Latin1)); - data.append(d->fileName.data(d->textEncoding)); - data.append(textDelimiter(d->textEncoding)); - data.append(d->description.data(d->textEncoding)); - data.append(textDelimiter(d->textEncoding)); - data.append(d->data); - - return data; -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data, Header *h) : Frame(h) -{ - d = new GeneralEncapsulatedObjectFramePrivate; - parseFields(fieldData(data)); -} diff --git a/taglib/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.h b/taglib/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.h deleted file mode 100644 index 42f854c..0000000 --- a/taglib/taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.h +++ /dev/null @@ -1,178 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - copyright : (C) 2006 by Aaron VonderHaar - email : avh4@users.sourceforge.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_GENERALENCAPSULATEDOBJECT_H -#define TAGLIB_GENERALENCAPSULATEDOBJECT_H - -#include "id3v2frame.h" -#include "id3v2header.h" -#include "taglib_export.h" - -namespace TagLib { - - namespace ID3v2 { - - //! An ID3v2 general encapsulated object frame implementation - - /*! - * This is an implementation of ID3v2 general encapsulated objects. - * Arbitrary binary data may be included in tags, stored in GEOB frames. - * There may be multiple GEOB frames in a single tag. Each GEOB it - * labelled with a content description (which may be blank), a required - * mime-type, and a file name (may be blank). The content description - * uniquely identifies the GEOB frame in the tag. - */ - - class TAGLIB_EXPORT GeneralEncapsulatedObjectFrame : public Frame - { - friend class FrameFactory; - - public: - - /*! - * Constructs an empty object frame. The description, file name and text - * encoding should be set manually. - */ - GeneralEncapsulatedObjectFrame(); - - /*! - * Constructs a GeneralEncapsulatedObjectFrame frame based on \a data. - * - * \warning This is \em not data for the encapsulated object, for that use - * setObject(). This constructor is used when reading the frame from the - * disk. - */ - explicit GeneralEncapsulatedObjectFrame(const ByteVector &data); - - /*! - * Destroys the GeneralEncapsulatedObjectFrame instance. - */ - virtual ~GeneralEncapsulatedObjectFrame(); - - /*! - * Returns a string containing the description, file name and mime-type - */ - virtual String toString() const; - - /*! - * Returns the text encoding used for the description and file name. - * - * \see setTextEncoding() - * \see description() - * \see fileName() - */ - String::Type textEncoding() const; - - /*! - * Set the text encoding used for the description and file name. - * - * \see description() - * \see fileName() - */ - void setTextEncoding(String::Type encoding); - - /*! - * Returns the mime type of the object. - */ - String mimeType() const; - - /*! - * Sets the mime type of the object. - */ - void setMimeType(const String &type); - - /*! - * Returns the file name of the object. - * - * \see setFileName() - */ - String fileName() const; - - /*! - * Sets the file name for the object. - * - * \see fileName() - */ - void setFileName(const String &name); - - /*! - * Returns the content description of the object. - * - * \see setDescription() - * \see textEncoding() - * \see setTextEncoding() - */ - - String description() const; - - /*! - * Sets the content description of the object to \a desc. - * - * \see description() - * \see textEncoding() - * \see setTextEncoding() - */ - - void setDescription(const String &desc); - - /*! - * Returns the object data as a ByteVector. - * - * \note ByteVector has a data() method that returns a const char * which - * should make it easy to export this data to external programs. - * - * \see setObject() - * \see mimeType() - */ - ByteVector object() const; - - /*! - * Sets the object data to \a data. \a data should be of the type specified in - * this frame's mime-type specification. - * - * \see object() - * \see mimeType() - * \see setMimeType() - */ - void setObject(const ByteVector &object); - - protected: - virtual void parseFields(const ByteVector &data); - virtual ByteVector renderFields() const; - - private: - GeneralEncapsulatedObjectFrame(const ByteVector &data, Header *h); - GeneralEncapsulatedObjectFrame(const GeneralEncapsulatedObjectFrame &); - GeneralEncapsulatedObjectFrame &operator=(const GeneralEncapsulatedObjectFrame &); - - class GeneralEncapsulatedObjectFramePrivate; - GeneralEncapsulatedObjectFramePrivate *d; - }; - } -} - -#endif diff --git a/taglib/taglib/mpeg/id3v2/frames/ownershipframe.cpp b/taglib/taglib/mpeg/id3v2/frames/ownershipframe.cpp deleted file mode 100644 index 9451c4c..0000000 --- a/taglib/taglib/mpeg/id3v2/frames/ownershipframe.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/*************************************************************************** - 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)); -} diff --git a/taglib/taglib/mpeg/id3v2/frames/ownershipframe.h b/taglib/taglib/mpeg/id3v2/frames/ownershipframe.h deleted file mode 100644 index 34fc912..0000000 --- a/taglib/taglib/mpeg/id3v2/frames/ownershipframe.h +++ /dev/null @@ -1,151 +0,0 @@ -/*************************************************************************** - 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 diff --git a/taglib/taglib/mpeg/id3v2/frames/popularimeterframe.cpp b/taglib/taglib/mpeg/id3v2/frames/popularimeterframe.cpp deleted file mode 100644 index 3d4429f..0000000 --- a/taglib/taglib/mpeg/id3v2/frames/popularimeterframe.cpp +++ /dev/null @@ -1,137 +0,0 @@ -/*************************************************************************** - copyright : (C) 2008 by Lukas Lalinsky - email : lalinsky@gmail.com - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <tdebug.h> - -#include "popularimeterframe.h" - -using namespace TagLib; -using namespace ID3v2; - -class PopularimeterFrame::PopularimeterFramePrivate -{ -public: - PopularimeterFramePrivate() : rating(0), counter(0) {} - String email; - int rating; - TagLib::uint counter; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -PopularimeterFrame::PopularimeterFrame() : Frame("POPM") -{ - d = new PopularimeterFramePrivate; -} - -PopularimeterFrame::PopularimeterFrame(const ByteVector &data) : Frame(data) -{ - d = new PopularimeterFramePrivate; - setData(data); -} - -PopularimeterFrame::~PopularimeterFrame() -{ - delete d; -} - -String PopularimeterFrame::toString() const -{ - return d->email + " rating=" + String::number(d->rating) + " counter=" + String::number(d->counter); -} - -String PopularimeterFrame::email() const -{ - return d->email; -} - -void PopularimeterFrame::setEmail(const String &s) -{ - d->email = s; -} - -int PopularimeterFrame::rating() const -{ - return d->rating; -} - -void PopularimeterFrame::setRating(int s) -{ - d->rating = s; -} - -TagLib::uint PopularimeterFrame::counter() const -{ - return d->counter; -} - -void PopularimeterFrame::setCounter(TagLib::uint s) -{ - d->counter = s; -} - -//////////////////////////////////////////////////////////////////////////////// -// protected members -//////////////////////////////////////////////////////////////////////////////// - -void PopularimeterFrame::parseFields(const ByteVector &data) -{ - int pos = 0, size = int(data.size()); - - d->email = readStringField(data, String::Latin1, &pos); - - d->rating = 0; - d->counter = 0; - if(pos < size) { - d->rating = (unsigned char)(data[pos++]); - if(pos < size) { - d->counter = data.toUInt(static_cast<uint>(pos)); - } - } -} - -ByteVector PopularimeterFrame::renderFields() const -{ - ByteVector data; - - data.append(d->email.data(String::Latin1)); - data.append(textDelimiter(String::Latin1)); - data.append(char(d->rating)); - data.append(ByteVector::fromUInt(d->counter)); - - return data; -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -PopularimeterFrame::PopularimeterFrame(const ByteVector &data, Header *h) : Frame(h) -{ - d = new PopularimeterFramePrivate; - parseFields(fieldData(data)); -} diff --git a/taglib/taglib/mpeg/id3v2/frames/popularimeterframe.h b/taglib/taglib/mpeg/id3v2/frames/popularimeterframe.h deleted file mode 100644 index d39f1aa..0000000 --- a/taglib/taglib/mpeg/id3v2/frames/popularimeterframe.h +++ /dev/null @@ -1,132 +0,0 @@ -/*************************************************************************** - copyright : (C) 2008 by Lukas Lalinsky - email : lalinsky@gmail.com - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_POPULARIMETERFRAME_H -#define TAGLIB_POPULARIMETERFRAME_H - -#include "id3v2frame.h" -#include "taglib_export.h" - -namespace TagLib { - - namespace ID3v2 { - - //! An implementation of ID3v2 "popularimeter" - - /*! - * This implements the ID3v2 popularimeter (POPM frame). It concists of - * an email, a rating and an optional counter. - */ - - class TAGLIB_EXPORT PopularimeterFrame : public Frame - { - friend class FrameFactory; - - public: - /*! - * Construct an empty popularimeter frame. - */ - explicit PopularimeterFrame(); - - /*! - * Construct a popularimeter based on the data in \a data. - */ - explicit PopularimeterFrame(const ByteVector &data); - - /*! - * Destroys this PopularimeterFrame instance. - */ - virtual ~PopularimeterFrame(); - - /*! - * Returns the text of this popularimeter. - * - * \see text() - */ - virtual String toString() const; - - /*! - * Returns the email. - * - * \see setEmail() - */ - String email() const; - - /*! - * Set the email. - * - * \see email() - */ - void setEmail(const String &email); - - /*! - * Returns the rating. - * - * \see setRating() - */ - int rating() const; - - /*! - * Set the rating. - * - * \see rating() - */ - void setRating(int rating); - - /*! - * Returns the counter. - * - * \see setCounter() - */ - uint counter() const; - - /*! - * Set the counter. - * - * \see counter() - */ - void setCounter(uint counter); - - protected: - // Reimplementations. - - virtual void parseFields(const ByteVector &data); - virtual ByteVector renderFields() const; - - private: - /*! - * The constructor used by the FrameFactory. - */ - PopularimeterFrame(const ByteVector &data, Header *h); - PopularimeterFrame(const PopularimeterFrame &); - PopularimeterFrame &operator=(const PopularimeterFrame &); - - class PopularimeterFramePrivate; - PopularimeterFramePrivate *d; - }; - - } -} -#endif diff --git a/taglib/taglib/mpeg/id3v2/frames/privateframe.cpp b/taglib/taglib/mpeg/id3v2/frames/privateframe.cpp deleted file mode 100644 index 24ee0f3..0000000 --- a/taglib/taglib/mpeg/id3v2/frames/privateframe.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/*************************************************************************** - copyright : (C) 2008 by Serkan Kalyoncu - copyright : (C) 2008 by Scott Wheeler - email : wheeler@kde.org -***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <tbytevectorlist.h> -#include <id3v2tag.h> -#include <tdebug.h> - -#include "privateframe.h" - -using namespace TagLib; -using namespace ID3v2; - - -class PrivateFrame::PrivateFramePrivate -{ -public: - ByteVector data; - String owner; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -PrivateFrame::PrivateFrame() : Frame("PRIV") -{ - d = new PrivateFramePrivate; -} - -PrivateFrame::PrivateFrame(const ByteVector &data) : Frame(data) -{ - d = new PrivateFramePrivate; - setData(data); -} - -PrivateFrame::~PrivateFrame() -{ - delete d; -} - -String PrivateFrame::toString() const -{ - return d->owner; -} - -String PrivateFrame::owner() const -{ - return d->owner; -} - -ByteVector PrivateFrame::data() const -{ - return d->data; -} - -void PrivateFrame::setOwner(const String &s) -{ - d->owner = s; -} - -void PrivateFrame::setData(const ByteVector & data) -{ - d->data = data; -} - -//////////////////////////////////////////////////////////////////////////////// -// protected members -//////////////////////////////////////////////////////////////////////////////// - -void PrivateFrame::parseFields(const ByteVector &data) -{ - if(data.size() < 2) { - debug("A private frame must contain at least 2 bytes."); - return; - } - - // Owner identifier is assumed to be Latin1 - - const int byteAlign = 1; - const int endOfOwner = data.find(textDelimiter(String::Latin1), 0, byteAlign); - - d->owner = String(data.mid(0, endOfOwner)); - d->data = data.mid(endOfOwner + 1); -} - -ByteVector PrivateFrame::renderFields() const -{ - ByteVector v; - - v.append(d->owner.data(String::Latin1)); - v.append(textDelimiter(String::Latin1)); - v.append(d->data); - - return v; -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -PrivateFrame::PrivateFrame(const ByteVector &data, Header *h) : Frame(h) -{ - d = new PrivateFramePrivate(); - parseFields(fieldData(data)); -} diff --git a/taglib/taglib/mpeg/id3v2/frames/privateframe.h b/taglib/taglib/mpeg/id3v2/frames/privateframe.h deleted file mode 100644 index 06f82f3..0000000 --- a/taglib/taglib/mpeg/id3v2/frames/privateframe.h +++ /dev/null @@ -1,111 +0,0 @@ -/*************************************************************************** - copyright : (C) 2008 by Serkan Kalyoncu - copyright : (C) 2008 by Scott Wheeler - email : wheeler@kde.org -***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_PRIVATEFRAME_H -#define TAGLIB_PRIVATEFRAME_H - -#include "id3v2frame.h" -#include "taglib_export.h" - -namespace TagLib { - - namespace ID3v2 { - - //! An implementation of ID3v2 privateframe - - class TAGLIB_EXPORT PrivateFrame : public Frame - { - friend class FrameFactory; - - public: - /*! - * Construct an empty private frame. - */ - PrivateFrame(); - - /*! - * Construct a private frame based on the data in \a data. - * - * \note This is the constructor used when parsing the frame from a file. - */ - explicit PrivateFrame(const ByteVector &data); - - /*! - * Destroys this private frame instance. - */ - virtual ~PrivateFrame(); - - /*! - * Returns the text of this private frame, currently just the owner. - * - * \see text() - */ - virtual String toString() const; - - /*! - * \return The owner of the private frame. - * \note This should contain an email address or link to a website. - */ - String owner() const; - - /*! - * - */ - ByteVector data() const; - - /*! - * Sets the owner of the frame to \a s. - * \note This should contain an email address or link to a website. - */ - void setOwner(const String &s); - - /*! - * - */ - void setData(const ByteVector &v); - - protected: - // Reimplementations. - - virtual void parseFields(const ByteVector &data); - virtual ByteVector renderFields() const; - - private: - /*! - * The constructor used by the FrameFactory. - */ - PrivateFrame(const ByteVector &data, Header *h); - - PrivateFrame(const PrivateFrame &); - PrivateFrame &operator=(const PrivateFrame &); - - class PrivateFramePrivate; - PrivateFramePrivate *d; - }; - - } -} -#endif diff --git a/taglib/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp b/taglib/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp deleted file mode 100644 index e3efbc3..0000000 --- a/taglib/taglib/mpeg/id3v2/frames/relativevolumeframe.cpp +++ /dev/null @@ -1,236 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <tdebug.h> -#include <tmap.h> - -#include "relativevolumeframe.h" - -using namespace TagLib; -using namespace ID3v2; - -static inline int bitsToBytes(int i) -{ - return i % 8 == 0 ? i / 8 : (i - i % 8) / 8 + 1; -} - -struct ChannelData -{ - ChannelData() : channelType(RelativeVolumeFrame::Other), volumeAdjustment(0) {} - - RelativeVolumeFrame::ChannelType channelType; - short volumeAdjustment; - RelativeVolumeFrame::PeakVolume peakVolume; -}; - -class RelativeVolumeFrame::RelativeVolumeFramePrivate -{ -public: - String identification; - Map<ChannelType, ChannelData> channels; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -RelativeVolumeFrame::RelativeVolumeFrame() : Frame("RVA2") -{ - d = new RelativeVolumeFramePrivate; -} - -RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data) : Frame(data) -{ - d = new RelativeVolumeFramePrivate; - setData(data); -} - -RelativeVolumeFrame::~RelativeVolumeFrame() -{ - delete d; -} - -String RelativeVolumeFrame::toString() const -{ - return d->identification; -} - -List<RelativeVolumeFrame::ChannelType> RelativeVolumeFrame::channels() const -{ - List<ChannelType> l; - - Map<ChannelType, ChannelData>::ConstIterator it = d->channels.begin(); - for(; it != d->channels.end(); ++it) - l.append((*it).first); - - return l; -} - -// deprecated - -RelativeVolumeFrame::ChannelType RelativeVolumeFrame::channelType() const -{ - return MasterVolume; -} - -// deprecated - -void RelativeVolumeFrame::setChannelType(ChannelType) -{ - -} - -short RelativeVolumeFrame::volumeAdjustmentIndex(ChannelType type) const -{ - return d->channels.contains(type) ? d->channels[type].volumeAdjustment : 0; -} - -short RelativeVolumeFrame::volumeAdjustmentIndex() const -{ - return volumeAdjustmentIndex(MasterVolume); -} - -void RelativeVolumeFrame::setVolumeAdjustmentIndex(short index, ChannelType type) -{ - d->channels[type].volumeAdjustment = index; -} - -void RelativeVolumeFrame::setVolumeAdjustmentIndex(short index) -{ - setVolumeAdjustmentIndex(index, MasterVolume); -} - -float RelativeVolumeFrame::volumeAdjustment(ChannelType type) const -{ - return d->channels.contains(type) ? float(d->channels[type].volumeAdjustment) / float(512) : 0; -} - -float RelativeVolumeFrame::volumeAdjustment() const -{ - return volumeAdjustment(MasterVolume); -} - -void RelativeVolumeFrame::setVolumeAdjustment(float adjustment, ChannelType type) -{ - d->channels[type].volumeAdjustment = short(adjustment * float(512)); -} - -void RelativeVolumeFrame::setVolumeAdjustment(float adjustment) -{ - setVolumeAdjustment(adjustment, MasterVolume); -} - -RelativeVolumeFrame::PeakVolume RelativeVolumeFrame::peakVolume(ChannelType type) const -{ - return d->channels.contains(type) ? d->channels[type].peakVolume : PeakVolume(); -} - -RelativeVolumeFrame::PeakVolume RelativeVolumeFrame::peakVolume() const -{ - return peakVolume(MasterVolume); -} - -void RelativeVolumeFrame::setPeakVolume(const PeakVolume &peak, ChannelType type) -{ - d->channels[type].peakVolume = peak; -} - -void RelativeVolumeFrame::setPeakVolume(const PeakVolume &peak) -{ - setPeakVolume(peak, MasterVolume); -} - -String RelativeVolumeFrame::identification() const -{ - return d->identification; -} - -void RelativeVolumeFrame::setIdentification(const String &s) -{ - d->identification = s; -} - -//////////////////////////////////////////////////////////////////////////////// -// protected members -//////////////////////////////////////////////////////////////////////////////// - -void RelativeVolumeFrame::parseFields(const ByteVector &data) -{ - int pos = 0; - d->identification = readStringField(data, String::Latin1, &pos); - - // Each channel is at least 4 bytes. - - while(pos <= (int)data.size() - 4) { - - - ChannelType type = ChannelType(data[pos]); - pos += 1; - - ChannelData &channel = d->channels[type]; - - channel.volumeAdjustment = data.toShort(static_cast<uint>(pos)); - pos += 2; - - channel.peakVolume.bitsRepresentingPeak = data[pos]; - pos += 1; - - int bytes = bitsToBytes(channel.peakVolume.bitsRepresentingPeak); - channel.peakVolume.peakVolume = data.mid(pos, bytes); - pos += bytes; - } -} - -ByteVector RelativeVolumeFrame::renderFields() const -{ - ByteVector data; - - data.append(d->identification.data(String::Latin1)); - data.append(textDelimiter(String::Latin1)); - - Map<ChannelType, ChannelData>::ConstIterator it = d->channels.begin(); - - for(; it != d->channels.end(); ++it) { - ChannelType type = (*it).first; - const ChannelData &channel = (*it).second; - - data.append(char(type)); - data.append(ByteVector::fromShort(channel.volumeAdjustment)); - data.append(char(channel.peakVolume.bitsRepresentingPeak)); - data.append(channel.peakVolume.peakVolume); - } - - return data; -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data, Header *h) : Frame(h) -{ - d = new RelativeVolumeFramePrivate; - parseFields(fieldData(data)); -} diff --git a/taglib/taglib/mpeg/id3v2/frames/relativevolumeframe.h b/taglib/taglib/mpeg/id3v2/frames/relativevolumeframe.h deleted file mode 100644 index dad4e7d..0000000 --- a/taglib/taglib/mpeg/id3v2/frames/relativevolumeframe.h +++ /dev/null @@ -1,274 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_RELATIVEVOLUMEFRAME_H -#define TAGLIB_RELATIVEVOLUMEFRAME_H - -#include "tlist.h" -#include "id3v2frame.h" -#include "taglib_export.h" - -namespace TagLib { - - namespace ID3v2 { - - //! An ID3v2 relative volume adjustment frame implementation - - /*! - * This is an implementation of ID3v2 relative volume adjustment. The - * presence of this frame makes it possible to specify an increase in volume - * for an audio file or specific audio tracks in that file. - * - * Multiple relative volume adjustment frames may be present in the tag - * each with a unique identification and describing volume adjustment for - * different channel types. - */ - - class TAGLIB_EXPORT RelativeVolumeFrame : public Frame - { - friend class FrameFactory; - - public: - - /*! - * This indicates the type of volume adjustment that should be applied. - */ - enum ChannelType { - //! A type not enumerated below - Other = 0x00, - //! The master volume for the track - MasterVolume = 0x01, - //! The front right audio channel - FrontRight = 0x02, - //! The front left audio channel - FrontLeft = 0x03, - //! The back right audio channel - BackRight = 0x04, - //! The back left audio channel - BackLeft = 0x05, - //! The front center audio channel - FrontCentre = 0x06, - //! The back center audio channel - BackCentre = 0x07, - //! The subwoofer audio channel - Subwoofer = 0x08 - }; - - //! Struct that stores the relevant values for ID3v2 peak volume - - /*! - * The peak volume is described as a series of bits that is padded to fill - * a block of bytes. These two values should always be updated in tandem. - */ - struct PeakVolume - { - /*! - * Constructs an empty peak volume description. - */ - PeakVolume() : bitsRepresentingPeak(0) {} - /*! - * The number of bits (in the range of 0 to 255) used to describe the - * peak volume. - */ - unsigned char bitsRepresentingPeak; - /*! - * The array of bits (represented as a series of bytes) used to describe - * the peak volume. - */ - ByteVector peakVolume; - }; - - /*! - * Constructs a RelativeVolumeFrame. The relevant data should be set - * manually. - */ - RelativeVolumeFrame(); - - /*! - * Constructs a RelativeVolumeFrame based on the contents of \a data. - */ - RelativeVolumeFrame(const ByteVector &data); - - /*! - * Destroys the RelativeVolumeFrame instance. - */ - virtual ~RelativeVolumeFrame(); - - /*! - * Returns the frame's identification. - * - * \see identification() - */ - virtual String toString() const; - - /*! - * Returns a list of channels with information currently in the frame. - */ - List<ChannelType> channels() const; - - /*! - * \deprecated Always returns master volume. - */ - ChannelType channelType() const; - - /*! - * \deprecated This method no longer has any effect. - */ - void setChannelType(ChannelType t); - - /* - * There was a terrible API goof here, and while this can't be changed to - * the way it appears below for binary compaibility reasons, let's at - * least pretend that it looks clean. - */ - -#ifdef DOXYGEN - - /*! - * Returns the relative volume adjustment "index". As indicated by the - * ID3v2 standard this is a 16-bit signed integer that reflects the - * decibils of adjustment when divided by 512. - * - * This defaults to returning the value for the master volume channel if - * available and returns 0 if the specified channel does not exist. - * - * \see setVolumeAdjustmentIndex() - * \see volumeAjustment() - */ - short volumeAdjustmentIndex(ChannelType type = MasterVolume) const; - - /*! - * Set the volume adjustment to \a index. As indicated by the ID3v2 - * standard this is a 16-bit signed integer that reflects the decibils of - * adjustment when divided by 512. - * - * By default this sets the value for the master volume. - * - * \see volumeAdjustmentIndex() - * \see setVolumeAjustment() - */ - void setVolumeAdjustmentIndex(short index, ChannelType type = MasterVolume); - - /*! - * Returns the relative volume adjustment in decibels. - * - * \note Because this is actually stored internally as an "index" to this - * value the value returned by this method may not be identical to the - * value set using setVolumeAdjustment(). - * - * This defaults to returning the value for the master volume channel if - * available and returns 0 if the specified channel does not exist. - * - * \see setVolumeAdjustment() - * \see volumeAdjustmentIndex() - */ - float volumeAdjustment(ChannelType type = MasterVolume) const; - - /*! - * Set the relative volume adjustment in decibels to \a adjustment. - * - * By default this sets the value for the master volume. - * - * \note Because this is actually stored internally as an "index" to this - * value the value set by this method may not be identical to the one - * returned by volumeAdjustment(). - * - * \see setVolumeAdjustment() - * \see volumeAdjustmentIndex() - */ - void setVolumeAdjustment(float adjustment, ChannelType type = MasterVolume); - - /*! - * Returns the peak volume (represented as a length and a string of bits). - * - * This defaults to returning the value for the master volume channel if - * available and returns 0 if the specified channel does not exist. - * - * \see setPeakVolume() - */ - PeakVolume peakVolume(ChannelType type = MasterVolume) const; - - /*! - * Sets the peak volume to \a peak. - * - * By default this sets the value for the master volume. - * - * \see peakVolume() - */ - void setPeakVolume(const PeakVolume &peak, ChannelType type = MasterVolume); - -#else - - // BIC: Combine each of the following pairs of functions (or maybe just - // rework this junk altogether). - - short volumeAdjustmentIndex(ChannelType type) const; - short volumeAdjustmentIndex() const; - - void setVolumeAdjustmentIndex(short index, ChannelType type); - void setVolumeAdjustmentIndex(short index); - - float volumeAdjustment(ChannelType type) const; - float volumeAdjustment() const; - - void setVolumeAdjustment(float adjustment, ChannelType type); - void setVolumeAdjustment(float adjustment); - - PeakVolume peakVolume(ChannelType type) const; - PeakVolume peakVolume() const; - - void setPeakVolume(const PeakVolume &peak, ChannelType type); - void setPeakVolume(const PeakVolume &peak); - -#endif - - /*! - * Returns the identification for this frame. - */ - String identification() const; - - /*! - * Sets the identification of the frame to \a s. The string - * is used to identify the situation and/or device where this - * adjustment should apply. - */ - void setIdentification(const String &s); - - protected: - virtual void parseFields(const ByteVector &data); - virtual ByteVector renderFields() const; - - private: - RelativeVolumeFrame(const ByteVector &data, Header *h); - RelativeVolumeFrame(const RelativeVolumeFrame &); - RelativeVolumeFrame &operator=(const RelativeVolumeFrame &); - - class RelativeVolumeFramePrivate; - RelativeVolumeFramePrivate *d; - }; - - } -} -#endif diff --git a/taglib/taglib/mpeg/id3v2/frames/textidentificationframe.cpp b/taglib/taglib/mpeg/id3v2/frames/textidentificationframe.cpp deleted file mode 100644 index 70ea50f..0000000 --- a/taglib/taglib/mpeg/id3v2/frames/textidentificationframe.cpp +++ /dev/null @@ -1,423 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <tbytevectorlist.h> -#include <id3v2tag.h> -#include "textidentificationframe.h" -#include "tpropertymap.h" -#include "id3v1genres.h" - -using namespace TagLib; -using namespace ID3v2; - -class TextIdentificationFrame::TextIdentificationFramePrivate -{ -public: - TextIdentificationFramePrivate() : textEncoding(String::Latin1) {} - String::Type textEncoding; - StringList fieldList; -}; - -//////////////////////////////////////////////////////////////////////////////// -// TextIdentificationFrame public members -//////////////////////////////////////////////////////////////////////////////// - -TextIdentificationFrame::TextIdentificationFrame(const ByteVector &type, String::Type encoding) : - Frame(type) -{ - d = new TextIdentificationFramePrivate; - d->textEncoding = encoding; -} - -TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data) : - Frame(data) -{ - d = new TextIdentificationFramePrivate; - setData(data); -} - -TextIdentificationFrame *TextIdentificationFrame::createTIPLFrame(const PropertyMap &properties) // static -{ - TextIdentificationFrame *frame = new TextIdentificationFrame("TIPL"); - StringList l; - for(PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it){ - l.append(it->first); - l.append(it->second.toString(",")); // comma-separated list of names - } - frame->setText(l); - return frame; -} - -TextIdentificationFrame *TextIdentificationFrame::createTMCLFrame(const PropertyMap &properties) // static -{ - TextIdentificationFrame *frame = new TextIdentificationFrame("TMCL"); - StringList l; - for(PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it){ - if(!it->first.startsWith(instrumentPrefix)) // should not happen - continue; - l.append(it->first.substr(instrumentPrefix.size())); - l.append(it->second.toString(",")); - } - frame->setText(l); - return frame; -} - -TextIdentificationFrame::~TextIdentificationFrame() -{ - delete d; -} - -void TextIdentificationFrame::setText(const StringList &l) -{ - d->fieldList = l; -} - -void TextIdentificationFrame::setText(const String &s) -{ - d->fieldList = s; -} - -String TextIdentificationFrame::toString() const -{ - return d->fieldList.toString(); -} - -StringList TextIdentificationFrame::fieldList() const -{ - return d->fieldList; -} - -String::Type TextIdentificationFrame::textEncoding() const -{ - return d->textEncoding; -} - -void TextIdentificationFrame::setTextEncoding(String::Type encoding) -{ - d->textEncoding = encoding; -} - -// array of allowed TIPL prefixes and their corresponding key value -static const TagLib::uint involvedPeopleSize = 5; -static const char* involvedPeople[][2] = { - {"ARRANGER", "ARRANGER"}, - {"ENGINEER", "ENGINEER"}, - {"PRODUCER", "PRODUCER"}, - {"DJ-MIX", "DJMIXER"}, - {"MIX", "MIXER"}, -}; - -const KeyConversionMap &TextIdentificationFrame::involvedPeopleMap() // static -{ - static KeyConversionMap m; - if(m.isEmpty()) - for(uint i = 0; i < involvedPeopleSize; ++i) - m.insert(involvedPeople[i][1], involvedPeople[i][0]); - return m; -} - -PropertyMap TextIdentificationFrame::asProperties() const -{ - if(frameID() == "TIPL") - return makeTIPLProperties(); - if(frameID() == "TMCL") - return makeTMCLProperties(); - PropertyMap map; - String tagName = frameIDToKey(frameID()); - if(tagName.isNull()) { - map.unsupportedData().append(frameID()); - return map; - } - StringList values = fieldList(); - if(tagName == "GENRE") { - // Special case: Support ID3v1-style genre numbers. They are not officially supported in - // ID3v2, however it seems that still a lot of programs use them. - for(StringList::Iterator it = values.begin(); it != values.end(); ++it) { - bool ok = false; - int test = it->toInt(&ok); // test if the genre value is an integer - if(ok) - *it = ID3v1::genre(test); - } - } else if(tagName == "DATE") { - for(StringList::Iterator it = values.begin(); it != values.end(); ++it) { - // ID3v2 specifies ISO8601 timestamps which contain a 'T' as separator between date and time. - // Since this is unusual in other formats, the T is removed. - int tpos = it->find("T"); - if(tpos != -1) - (*it)[tpos] = ' '; - } - } - PropertyMap ret; - ret.insert(tagName, values); - return ret; -} - -//////////////////////////////////////////////////////////////////////////////// -// TextIdentificationFrame protected members -//////////////////////////////////////////////////////////////////////////////// - -void TextIdentificationFrame::parseFields(const ByteVector &data) -{ - // Don't try to parse invalid frames - - if(data.size() < 2) - return; - - // read the string data type (the first byte of the field data) - - d->textEncoding = String::Type(data[0]); - - // split the byte array into chunks based on the string type (two byte delimiter - // for unicode encodings) - - int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2; - - // build a small counter to strip nulls off the end of the field - - int dataLength = data.size() - 1; - - while(dataLength > 0 && data[dataLength] == 0) - dataLength--; - - while(dataLength % byteAlign != 0) - dataLength++; - - ByteVectorList l = ByteVectorList::split(data.mid(1, dataLength), textDelimiter(d->textEncoding), byteAlign); - - d->fieldList.clear(); - - // append those split values to the list and make sure that the new string's - // type is the same specified for this frame - - for(ByteVectorList::Iterator it = l.begin(); it != l.end(); it++) { - if(!(*it).isEmpty()) { - if(d->textEncoding == String::Latin1) - d->fieldList.append(Tag::latin1StringHandler()->parse(*it)); - else - d->fieldList.append(String(*it, d->textEncoding)); - } - } -} - -ByteVector TextIdentificationFrame::renderFields() const -{ - String::Type encoding = checkTextEncoding(d->fieldList, d->textEncoding); - - ByteVector v; - - v.append(char(encoding)); - - for(StringList::ConstIterator it = d->fieldList.begin(); it != d->fieldList.end(); it++) { - - // Since the field list is null delimited, if this is not the first - // element in the list, append the appropriate delimiter for this - // encoding. - - if(it != d->fieldList.begin()) - v.append(textDelimiter(encoding)); - - v.append((*it).data(encoding)); - } - - return v; -} - -//////////////////////////////////////////////////////////////////////////////// -// TextIdentificationFrame private members -//////////////////////////////////////////////////////////////////////////////// - -TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data, Header *h) : Frame(h) -{ - d = new TextIdentificationFramePrivate; - parseFields(fieldData(data)); -} - -PropertyMap TextIdentificationFrame::makeTIPLProperties() const -{ - PropertyMap map; - if(fieldList().size() % 2 != 0){ - // according to the ID3 spec, TIPL must contain an even number of entries - map.unsupportedData().append(frameID()); - return map; - } - StringList l = fieldList(); - for(StringList::ConstIterator it = l.begin(); it != l.end(); ++it) { - bool found = false; - for(uint i = 0; i < involvedPeopleSize; ++i) - if(*it == involvedPeople[i][0]) { - map.insert(involvedPeople[i][1], (++it)->split(",")); - found = true; - break; - } - if(!found){ - // invalid involved role -> mark whole frame as unsupported in order to be consisten with writing - map.clear(); - map.unsupportedData().append(frameID()); - return map; - } - } - return map; -} - -PropertyMap TextIdentificationFrame::makeTMCLProperties() const -{ - PropertyMap map; - if(fieldList().size() % 2 != 0){ - // according to the ID3 spec, TMCL must contain an even number of entries - map.unsupportedData().append(frameID()); - return map; - } - StringList l = fieldList(); - for(StringList::ConstIterator it = l.begin(); it != l.end(); ++it) { - String instrument = it->upper(); - if(instrument.isNull()) { - // instrument is not a valid key -> frame unsupported - map.clear(); - map.unsupportedData().append(frameID()); - return map; - } - map.insert(L"PERFORMER:" + instrument, (++it)->split(",")); - } - return map; -} - -//////////////////////////////////////////////////////////////////////////////// -// UserTextIdentificationFrame public members -//////////////////////////////////////////////////////////////////////////////// - -UserTextIdentificationFrame::UserTextIdentificationFrame(String::Type encoding) : - TextIdentificationFrame("TXXX", encoding), - d(0) -{ - StringList l; - l.append(String::null); - l.append(String::null); - setText(l); -} - - -UserTextIdentificationFrame::UserTextIdentificationFrame(const ByteVector &data) : - TextIdentificationFrame(data) -{ - checkFields(); -} - -UserTextIdentificationFrame::UserTextIdentificationFrame(const String &description, const StringList &values, String::Type encoding) : - TextIdentificationFrame("TXXX", encoding), - d(0) -{ - setDescription(description); - setText(values); -} - -String UserTextIdentificationFrame::toString() const -{ - return "[" + description() + "] " + fieldList().toString(); -} - -String UserTextIdentificationFrame::description() const -{ - return !TextIdentificationFrame::fieldList().isEmpty() - ? TextIdentificationFrame::fieldList().front() - : String::null; -} - -StringList UserTextIdentificationFrame::fieldList() const -{ - // TODO: remove this function - - return TextIdentificationFrame::fieldList(); -} - -void UserTextIdentificationFrame::setText(const String &text) -{ - if(description().isEmpty()) - setDescription(String::null); - - TextIdentificationFrame::setText(StringList(description()).append(text)); -} - -void UserTextIdentificationFrame::setText(const StringList &fields) -{ - if(description().isEmpty()) - setDescription(String::null); - - TextIdentificationFrame::setText(StringList(description()).append(fields)); -} - -void UserTextIdentificationFrame::setDescription(const String &s) -{ - StringList l = fieldList(); - - if(l.isEmpty()) - l.append(s); - else - l[0] = s; - - TextIdentificationFrame::setText(l); -} - -PropertyMap UserTextIdentificationFrame::asProperties() const -{ - PropertyMap map; - String tagName = txxxToKey(description()); - StringList v = fieldList(); - for(StringList::ConstIterator it = v.begin(); it != v.end(); ++it) - if(it != v.begin()) - map.insert(tagName, *it); - return map; -} - -UserTextIdentificationFrame *UserTextIdentificationFrame::find( - ID3v2::Tag *tag, const String &description) // static -{ - FrameList l = tag->frameList("TXXX"); - for(FrameList::Iterator it = l.begin(); it != l.end(); ++it) { - UserTextIdentificationFrame *f = dynamic_cast<UserTextIdentificationFrame *>(*it); - if(f && f->description() == description) - return f; - } - return 0; -} - -//////////////////////////////////////////////////////////////////////////////// -// UserTextIdentificationFrame private members -//////////////////////////////////////////////////////////////////////////////// - -UserTextIdentificationFrame::UserTextIdentificationFrame(const ByteVector &data, Header *h) : - TextIdentificationFrame(data, h) -{ - checkFields(); -} - -void UserTextIdentificationFrame::checkFields() -{ - int fields = fieldList().size(); - - if(fields == 0) - setDescription(String::null); - if(fields <= 1) - setText(String::null); -} diff --git a/taglib/taglib/mpeg/id3v2/frames/textidentificationframe.h b/taglib/taglib/mpeg/id3v2/frames/textidentificationframe.h deleted file mode 100644 index 58ed63e..0000000 --- a/taglib/taglib/mpeg/id3v2/frames/textidentificationframe.h +++ /dev/null @@ -1,313 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_TEXTIDENTIFICATIONFRAME_H -#define TAGLIB_TEXTIDENTIFICATIONFRAME_H - -#include "tstringlist.h" -#include "tmap.h" -#include "taglib_export.h" - -#include "id3v2frame.h" - -namespace TagLib { - - namespace ID3v2 { - - class Tag; - typedef Map<String, String> KeyConversionMap; - - //! An ID3v2 text identification frame implementation - - /*! - * This is an implementation of the most common type of ID3v2 frame -- text - * identification frames. There are a number of variations on this. Those - * enumerated in the ID3v2.4 standard are: - * - * <ul> - * <li><b>TALB</b> Album/Movie/Show title</li> - * <li><b>TBPM</b> BPM (beats per minute)</li> - * <li><b>TCOM</b> Composer</li> - * <li><b>TCON</b> Content type</li> - * <li><b>TCOP</b> Copyright message</li> - * <li><b>TDEN</b> Encoding time</li> - * <li><b>TDLY</b> Playlist delay</li> - * <li><b>TDOR</b> Original release time</li> - * <li><b>TDRC</b> Recording time</li> - * <li><b>TDRL</b> Release time</li> - * <li><b>TDTG</b> Tagging time</li> - * <li><b>TENC</b> Encoded by</li> - * <li><b>TEXT</b> Lyricist/Text writer</li> - * <li><b>TFLT</b> File type</li> - * <li><b>TIPL</b> Involved people list</li> - * <li><b>TIT1</b> Content group description</li> - * <li><b>TIT2</b> Title/songname/content description</li> - * <li><b>TIT3</b> Subtitle/Description refinement</li> - * <li><b>TKEY</b> Initial key</li> - * <li><b>TLAN</b> Language(s)</li> - * <li><b>TLEN</b> Length</li> - * <li><b>TMCL</b> Musician credits list</li> - * <li><b>TMED</b> Media type</li> - * <li><b>TMOO</b> Mood</li> - * <li><b>TOAL</b> Original album/movie/show title</li> - * <li><b>TOFN</b> Original filename</li> - * <li><b>TOLY</b> Original lyricist(s)/text writer(s)</li> - * <li><b>TOPE</b> Original artist(s)/performer(s)</li> - * <li><b>TOWN</b> File owner/licensee</li> - * <li><b>TPE1</b> Lead performer(s)/Soloist(s)</li> - * <li><b>TPE2</b> Band/orchestra/accompaniment</li> - * <li><b>TPE3</b> Conductor/performer refinement</li> - * <li><b>TPE4</b> Interpreted, remixed, or otherwise modified by</li> - * <li><b>TPOS</b> Part of a set</li> - * <li><b>TPRO</b> Produced notice</li> - * <li><b>TPUB</b> Publisher</li> - * <li><b>TRCK</b> Track number/Position in set</li> - * <li><b>TRSN</b> Internet radio station name</li> - * <li><b>TRSO</b> Internet radio station owner</li> - * <li><b>TSOA</b> Album sort order</li> - * <li><b>TSOP</b> Performer sort order</li> - * <li><b>TSOT</b> Title sort order</li> - * <li><b>TSRC</b> ISRC (international standard recording code)</li> - * <li><b>TSSE</b> Software/Hardware and settings used for encoding</li> - * <li><b>TSST</b> Set subtitle</li> - * </ul> - * - * The ID3v2 Frames document gives a description of each of these formats - * and the expected order of strings in each. ID3v2::Header::frameID() can - * be used to determine the frame type. - * - * \note If non-Latin1 compatible strings are used with this class, even if - * the text encoding is set to Latin1, the frame will be written using UTF8 - * (with the encoding flag appropriately set in the output). - */ - - class TAGLIB_EXPORT TextIdentificationFrame : public Frame - { - friend class FrameFactory; - - public: - /*! - * Construct an empty frame of type \a type. Uses \a encoding as the - * default text encoding. - * - * \note In this case you must specify the text encoding as it - * resolves the ambiguity between constructors. - * - * \note Please see the note in the class description regarding Latin1. - */ - TextIdentificationFrame(const ByteVector &type, String::Type encoding); - - /*! - * This is a dual purpose constructor. \a data can either be binary data - * that should be parsed or (at a minimum) the frame ID. - */ - explicit TextIdentificationFrame(const ByteVector &data); - - /*! - * This is a special factory method to create a TIPL (involved people list) - * frame from the given \a properties. Will parse key=[list of values] data - * into the TIPL format as specified in the ID3 standard. - */ - static TextIdentificationFrame *createTIPLFrame(const PropertyMap &properties); - - /*! - * This is a special factory method to create a TMCL (musician credits list) - * frame from the given \a properties. Will parse key=[list of values] data - * into the TMCL format as specified in the ID3 standard, where key should be - * of the form instrumentPrefix:instrument. - */ - static TextIdentificationFrame *createTMCLFrame(const PropertyMap &properties); - /*! - * Destroys this TextIdentificationFrame instance. - */ - virtual ~TextIdentificationFrame(); - - /*! - * Text identification frames are a list of string fields. - * - * This function will accept either a StringList or a String (using the - * StringList constructor that accepts a single String). - * - * \note This will not change the text encoding of the frame even if the - * strings passed in are not of the same encoding. Please use - * setEncoding(s.type()) if you wish to change the encoding of the frame. - */ - void setText(const StringList &l); - - // Reimplementations. - - virtual void setText(const String &s); - virtual String toString() const; - - /*! - * Returns the text encoding that will be used in rendering this frame. - * This defaults to the type that was either specified in the constructor - * or read from the frame when parsed. - * - * \note Please see the note in the class description regarding Latin1. - * - * \see setTextEncoding() - * \see render() - */ - String::Type textEncoding() const; - - /*! - * Sets the text encoding to be used when rendering this frame to - * \a encoding. - * - * \note Please see the note in the class description regarding Latin1. - * - * \see textEncoding() - * \see render() - */ - void setTextEncoding(String::Type encoding); - - /*! - * Returns a list of the strings in this frame. - */ - StringList fieldList() const; - - /*! - * Returns a KeyConversionMap mapping a role as it would be used in a PropertyMap - * to the corresponding key used in a TIPL ID3 frame to describe that role. - */ - static const KeyConversionMap &involvedPeopleMap(); - - PropertyMap asProperties() const; - - protected: - // Reimplementations. - - virtual void parseFields(const ByteVector &data); - virtual ByteVector renderFields() const; - - /*! - * The constructor used by the FrameFactory. - */ - TextIdentificationFrame(const ByteVector &data, Header *h); - - private: - TextIdentificationFrame(const TextIdentificationFrame &); - TextIdentificationFrame &operator=(const TextIdentificationFrame &); - - /*! - * Parses the special structure of a TIPL frame - * Only the whitelisted roles "ARRANGER", "ENGINEER", "PRODUCER", - * "DJMIXER" (ID3: "DJ-MIX") and "MIXER" (ID3: "MIX") are allowed. - */ - PropertyMap makeTIPLProperties() const; - /*! - * Parses the special structure of a TMCL frame. - */ - PropertyMap makeTMCLProperties() const; - class TextIdentificationFramePrivate; - TextIdentificationFramePrivate *d; - }; - - /*! - * This is a specialization of text identification frames that allows for - * user defined entries. Each entry has a description in addition to the - * normal list of fields that a text identification frame has. - * - * This description identifies the frame and must be unique. - */ - - //! An ID3v2 custom text identification frame implementationx - - class TAGLIB_EXPORT UserTextIdentificationFrame : public TextIdentificationFrame - { - friend class FrameFactory; - - public: - /*! - * Constructs an empty user defined text identification frame. For this to be - * a useful frame both a description and text must be set. - */ - explicit UserTextIdentificationFrame(String::Type encoding = String::Latin1); - - /*! - * Creates a frame based on \a data. - */ - explicit UserTextIdentificationFrame(const ByteVector &data); - - /*! - * Creates a user defined text identification frame with the given \a description - * and \a values. - */ - UserTextIdentificationFrame(const String &description, const StringList &values, String::Type encoding = String::UTF8); - - virtual String toString() const; - - /*! - * Returns the description for this frame. - */ - String description() const; - - /*! - * Sets the description of the frame to \a s. \a s must be unique. You can - * check for the presence of another user defined text frame of the same type - * using find() and testing for null. - */ - void setDescription(const String &s); - - StringList fieldList() const; - void setText(const String &text); - void setText(const StringList &fields); - - /*! - * A UserTextIdentificationFrame is parsed into a PropertyMap as follows: - * - the key is the frame's description, uppercased - * - if the description contains '::', only the substring after that - * separator is considered as key (compatibility with exfalso) - * - if the above rules don't yield a valid key (e.g. containing non-ASCII - * characters), the returned map will contain an entry "TXXX/<description>" - * in its unsupportedData() list. - * - The values will be copies of the fieldList(). - * - If the description() appears as value in fieldList(), it will be omitted - * in the value list, in order to be compatible with TagLib which copies - * the description() into the fieldList(). - */ - PropertyMap asProperties() const; - - /*! - * Searches for the user defined text frame with the description \a description - * in \a tag. This returns null if no matching frames were found. - */ - static UserTextIdentificationFrame *find(Tag *tag, const String &description); - - private: - UserTextIdentificationFrame(const ByteVector &data, Header *h); - UserTextIdentificationFrame(const TextIdentificationFrame &); - UserTextIdentificationFrame &operator=(const UserTextIdentificationFrame &); - - void checkFields(); - - class UserTextIdentificationFramePrivate; - UserTextIdentificationFramePrivate *d; - }; - - } -} -#endif diff --git a/taglib/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.cpp b/taglib/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.cpp deleted file mode 100644 index a0e842e..0000000 --- a/taglib/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <tbytevectorlist.h> -#include <tpropertymap.h> -#include <tdebug.h> - -#include "id3v2tag.h" -#include "uniquefileidentifierframe.h" - -using namespace TagLib; -using namespace ID3v2; - -class UniqueFileIdentifierFrame::UniqueFileIdentifierFramePrivate -{ -public: - String owner; - ByteVector identifier; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public methods -//////////////////////////////////////////////////////////////////////////////// - -UniqueFileIdentifierFrame::UniqueFileIdentifierFrame(const ByteVector &data) : - ID3v2::Frame(data) -{ - d = new UniqueFileIdentifierFramePrivate; - setData(data); -} - -UniqueFileIdentifierFrame::UniqueFileIdentifierFrame(const String &owner, const ByteVector &id) : - ID3v2::Frame("UFID") -{ - d = new UniqueFileIdentifierFramePrivate; - d->owner = owner; - d->identifier = id; -} - -UniqueFileIdentifierFrame::~UniqueFileIdentifierFrame() -{ - delete d; -} - -String UniqueFileIdentifierFrame::owner() const -{ - return d->owner; -} - -ByteVector UniqueFileIdentifierFrame::identifier() const -{ - return d->identifier; -} - -void UniqueFileIdentifierFrame::setOwner(const String &s) -{ - d->owner = s; -} - -void UniqueFileIdentifierFrame::setIdentifier(const ByteVector &v) -{ - d->identifier = v; -} - -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) { - debug("An UFID frame must contain at least 1 byte."); - return; - } - - int pos = 0; - d->owner = readStringField(data, String::Latin1, &pos); - d->identifier = data.mid(pos); -} - -ByteVector UniqueFileIdentifierFrame::renderFields() const -{ - ByteVector data; - - data.append(d->owner.data(String::Latin1)); - data.append(char(0)); - data.append(d->identifier); - - return data; -} - -UniqueFileIdentifierFrame::UniqueFileIdentifierFrame(const ByteVector &data, Header *h) : - Frame(h) -{ - d = new UniqueFileIdentifierFramePrivate; - parseFields(fieldData(data)); -} diff --git a/taglib/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.h b/taglib/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.h deleted file mode 100644 index add5a2e..0000000 --- a/taglib/taglib/mpeg/id3v2/frames/uniquefileidentifierframe.h +++ /dev/null @@ -1,123 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_UNIQUEFILEIDENTIFIERFRAME -#define TAGLIB_UNIQUEFILEIDENTIFIERFRAME - -#include "id3v2frame.h" - -namespace TagLib { - - namespace ID3v2 { - - /*! - * This is an implementation of ID3v2 unique file identifier frames. This - * frame is used to identify the file in an arbitrary database identified - * by the owner field. - */ - - //! An implementation of ID3v2 unique identifier frames - - class TAGLIB_EXPORT UniqueFileIdentifierFrame : public ID3v2::Frame - { - friend class FrameFactory; - - public: - /*! - * Creates a uniqe file identifier frame based on \a data. - */ - UniqueFileIdentifierFrame(const ByteVector &data); - - /*! - * Creates a unique file identifier frame with the owner \a owner and - * the identification \a id. - */ - UniqueFileIdentifierFrame(const String &owner, const ByteVector &id); - - /*! - * Destroys the frame. - */ - ~UniqueFileIdentifierFrame(); - - /*! - * Returns the owner for the frame; essentially this is the key for - * determining which identification scheme this key belongs to. This - * will usually either be an email address or URL for the person or tool - * used to create the unique identifier. - * - * \see setOwner() - */ - String owner() const; - - /*! - * Returns the unique identifier. Though sometimes this is a text string - * it also may be binary data and as much should be assumed when handling - * it. - */ - ByteVector identifier() const; - - /*! - * Sets the owner of the identification scheme to \a s. - * - * \see owner() - */ - void setOwner(const String &s); - - /*! - * Sets the unique file identifier to \a v. - * - * \see identifier() - */ - void setIdentifier(const ByteVector &v); - - 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; - - private: - UniqueFileIdentifierFrame(const UniqueFileIdentifierFrame &); - UniqueFileIdentifierFrame &operator=(const UniqueFileIdentifierFrame &); - - UniqueFileIdentifierFrame(const ByteVector &data, Header *h); - - class UniqueFileIdentifierFramePrivate; - UniqueFileIdentifierFramePrivate *d; - }; - } -} - -#endif diff --git a/taglib/taglib/mpeg/id3v2/frames/unknownframe.cpp b/taglib/taglib/mpeg/id3v2/frames/unknownframe.cpp deleted file mode 100644 index 4def028..0000000 --- a/taglib/taglib/mpeg/id3v2/frames/unknownframe.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include "unknownframe.h" - -using namespace TagLib; -using namespace ID3v2; - -class UnknownFrame::UnknownFramePrivate -{ -public: - ByteVector fieldData; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -UnknownFrame::UnknownFrame(const ByteVector &data) : Frame(data) -{ - d = new UnknownFramePrivate; - setData(data); -} - -UnknownFrame::~UnknownFrame() -{ - delete d; -} - -String UnknownFrame::toString() const -{ - return String::null; -} - -ByteVector UnknownFrame::data() const -{ - return d->fieldData; -} - -//////////////////////////////////////////////////////////////////////////////// -// protected members -//////////////////////////////////////////////////////////////////////////////// - -void UnknownFrame::parseFields(const ByteVector &data) -{ - d->fieldData = data; -} - -ByteVector UnknownFrame::renderFields() const -{ - return d->fieldData; -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -UnknownFrame::UnknownFrame(const ByteVector &data, Header *h) : Frame(h) -{ - d = new UnknownFramePrivate; - parseFields(fieldData(data)); -} diff --git a/taglib/taglib/mpeg/id3v2/frames/unknownframe.h b/taglib/taglib/mpeg/id3v2/frames/unknownframe.h deleted file mode 100644 index 6559f4e..0000000 --- a/taglib/taglib/mpeg/id3v2/frames/unknownframe.h +++ /dev/null @@ -1,79 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_UNKNOWNFRAME_H -#define TAGLIB_UNKNOWNFRAME_H - -#include "id3v2frame.h" -#include "taglib_export.h" - -namespace TagLib { - - namespace ID3v2 { - - //! A frame type \e unknown to TagLib. - - /*! - * This class represents a frame type not known (or more often simply - * unimplemented) in TagLib. This is here provide a basic API for - * manipulating the binary data of unknown frames and to provide a means - * of rendering such \e unknown frames. - * - * Please note that a cleaner way of handling frame types that TagLib - * does not understand is to subclass ID3v2::Frame and ID3v2::FrameFactory - * to have your frame type supported through the standard ID3v2 mechanism. - */ - - class TAGLIB_EXPORT UnknownFrame : public Frame - { - friend class FrameFactory; - - public: - UnknownFrame(const ByteVector &data); - virtual ~UnknownFrame(); - - virtual String toString() const; - - /*! - * Returns the field data (everything but the header) for this frame. - */ - ByteVector data() const; - - protected: - virtual void parseFields(const ByteVector &data); - virtual ByteVector renderFields() const; - - private: - UnknownFrame(const ByteVector &data, Header *h); - UnknownFrame(const UnknownFrame &); - UnknownFrame &operator=(const UnknownFrame &); - - class UnknownFramePrivate; - UnknownFramePrivate *d; - }; - - } -} -#endif diff --git a/taglib/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp b/taglib/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp deleted file mode 100644 index 8f96cb8..0000000 --- a/taglib/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - copyright : (C) 2006 by Urs Fleisch - email : ufleisch@users.sourceforge.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include "unsynchronizedlyricsframe.h" -#include <tbytevectorlist.h> -#include <id3v2tag.h> -#include <tdebug.h> -#include <tpropertymap.h> - -using namespace TagLib; -using namespace ID3v2; - -class UnsynchronizedLyricsFrame::UnsynchronizedLyricsFramePrivate -{ -public: - UnsynchronizedLyricsFramePrivate() : textEncoding(String::Latin1) {} - String::Type textEncoding; - ByteVector language; - String description; - String text; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(String::Type encoding) : - Frame("USLT") -{ - d = new UnsynchronizedLyricsFramePrivate; - d->textEncoding = encoding; -} - -UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(const ByteVector &data) : - Frame(data) -{ - d = new UnsynchronizedLyricsFramePrivate; - setData(data); -} - -UnsynchronizedLyricsFrame::~UnsynchronizedLyricsFrame() -{ - delete d; -} - -String UnsynchronizedLyricsFrame::toString() const -{ - return d->text; -} - -ByteVector UnsynchronizedLyricsFrame::language() const -{ - return d->language; -} - -String UnsynchronizedLyricsFrame::description() const -{ - return d->description; -} - -String UnsynchronizedLyricsFrame::text() const -{ - return d->text; -} - -void UnsynchronizedLyricsFrame::setLanguage(const ByteVector &languageEncoding) -{ - d->language = languageEncoding.mid(0, 3); -} - -void UnsynchronizedLyricsFrame::setDescription(const String &s) -{ - d->description = s; -} - -void UnsynchronizedLyricsFrame::setText(const String &s) -{ - d->text = s; -} - - -String::Type UnsynchronizedLyricsFrame::textEncoding() const -{ - return d->textEncoding; -} - -void UnsynchronizedLyricsFrame::setTextEncoding(String::Type encoding) -{ - d->textEncoding = encoding; -} - -PropertyMap UnsynchronizedLyricsFrame::asProperties() const -{ - PropertyMap map; - String key = description().upper(); - if(key.isEmpty() || key.upper() == "LYRICS") - map.insert("LYRICS", text()); - else if(key.isNull()) - map.unsupportedData().append(L"USLT/" + description()); - else - map.insert("LYRICS:" + key, text()); - return map; -} - -UnsynchronizedLyricsFrame *UnsynchronizedLyricsFrame::findByDescription(const ID3v2::Tag *tag, const String &d) // static -{ - ID3v2::FrameList lyrics = tag->frameList("USLT"); - - for(ID3v2::FrameList::ConstIterator it = lyrics.begin(); it != lyrics.end(); ++it){ - UnsynchronizedLyricsFrame *frame = dynamic_cast<UnsynchronizedLyricsFrame *>(*it); - if(frame && frame->description() == d) - return frame; - } - return 0; -} -//////////////////////////////////////////////////////////////////////////////// -// protected members -//////////////////////////////////////////////////////////////////////////////// - -void UnsynchronizedLyricsFrame::parseFields(const ByteVector &data) -{ - if(data.size() < 5) { - debug("An unsynchronized lyrics frame must contain at least 5 bytes."); - return; - } - - d->textEncoding = String::Type(data[0]); - d->language = data.mid(1, 3); - - int byteAlign - = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2; - - ByteVectorList l = - ByteVectorList::split(data.mid(4), textDelimiter(d->textEncoding), byteAlign, 2); - - if(l.size() == 2) { - 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); - } - } -} - -ByteVector UnsynchronizedLyricsFrame::renderFields() const -{ - ByteVector v; - - v.append(char(d->textEncoding)); - v.append(d->language.size() == 3 ? d->language : "XXX"); - v.append(d->description.data(d->textEncoding)); - v.append(textDelimiter(d->textEncoding)); - v.append(d->text.data(d->textEncoding)); - - return v; -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(const ByteVector &data, Header *h) - : Frame(h) -{ - d = new UnsynchronizedLyricsFramePrivate(); - parseFields(fieldData(data)); -} diff --git a/taglib/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.h b/taglib/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.h deleted file mode 100644 index 3af354f..0000000 --- a/taglib/taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.h +++ /dev/null @@ -1,179 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - copyright : (C) 2006 by Urs Fleisch - email : ufleisch@users.sourceforge.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_UNSYNCHRONIZEDLYRICSFRAME_H -#define TAGLIB_UNSYNCHRONIZEDLYRICSFRAME_H - -#include "id3v2frame.h" - -namespace TagLib { - - namespace ID3v2 { - - //! ID3v2 unsynchronized lyrics frame - /*! - * An implementation of ID3v2 unsynchronized lyrics. - */ - class TAGLIB_EXPORT UnsynchronizedLyricsFrame : public Frame - { - friend class FrameFactory; - - public: - /*! - * Construct an empty unsynchronized lyrics frame that will use the text encoding - * \a encoding. - */ - explicit UnsynchronizedLyricsFrame(String::Type encoding = String::Latin1); - - /*! - * Construct a unsynchronized lyrics frame based on the data in \a data. - */ - explicit UnsynchronizedLyricsFrame(const ByteVector &data); - - /*! - * Destroys this UnsynchronizedLyricsFrame instance. - */ - virtual ~UnsynchronizedLyricsFrame(); - - /*! - * Returns the text of this unsynchronized lyrics frame. - * - * \see text() - */ - virtual String toString() const; - - /*! - * Returns the language encoding as a 3 byte encoding as specified by - * <a href="http://en.wikipedia.org/wiki/ISO_639">ISO-639-2</a>. - * - * \note Most taggers simply ignore this value. - * - * \see setLanguage() - */ - ByteVector language() const; - - /*! - * Returns the description of this unsynchronized lyrics frame. - * - * \note Most taggers simply ignore this value. - * - * \see setDescription() - */ - String description() const; - - /*! - * Returns the text of this unsynchronized lyrics frame. - * - * \see setText() - */ - String text() const; - - /*! - * Set the language using the 3 byte language code from - * <a href="http://en.wikipedia.org/wiki/ISO_639">ISO-639-2</a> to - * \a languageCode. - * - * \see language() - */ - void setLanguage(const ByteVector &languageCode); - - /*! - * Sets the description of the unsynchronized lyrics frame to \a s. - * - * \see decription() - */ - void setDescription(const String &s); - - /*! - * Sets the text portion of the unsynchronized lyrics frame to \a s. - * - * \see text() - */ - virtual void setText(const String &s); - - /*! - * 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); - - - /*! Parses this frame as PropertyMap with a single key. - * - if description() is empty or "LYRICS", the key will be "LYRICS" - * - if description() is not a valid PropertyMap key, the frame will be - * marked unsupported by an entry "USLT/<description>" in the unsupportedData() - * attribute of the returned map. - * - otherwise, the key will be "LYRICS:<description>" - * - The single value will be the frame's text(). - * Note that currently the language() field is not supported by the PropertyMap - * interface. - */ - PropertyMap asProperties() const; - - /*! - * LyricsFrames each have a unique description. This searches for a lyrics - * frame with the decription \a d and returns a pointer to it. If no - * frame is found that matches the given description null is returned. - * - * \see description() - */ - static UnsynchronizedLyricsFrame *findByDescription(const Tag *tag, const String &d); - - protected: - // Reimplementations. - - virtual void parseFields(const ByteVector &data); - virtual ByteVector renderFields() const; - - private: - /*! - * The constructor used by the FrameFactory. - */ - UnsynchronizedLyricsFrame(const ByteVector &data, Header *h); - UnsynchronizedLyricsFrame(const UnsynchronizedLyricsFrame &); - UnsynchronizedLyricsFrame &operator=(const UnsynchronizedLyricsFrame &); - - class UnsynchronizedLyricsFramePrivate; - UnsynchronizedLyricsFramePrivate *d; - }; - - } -} -#endif diff --git a/taglib/taglib/mpeg/id3v2/frames/urllinkframe.cpp b/taglib/taglib/mpeg/id3v2/frames/urllinkframe.cpp deleted file mode 100644 index 6bcbbda..0000000 --- a/taglib/taglib/mpeg/id3v2/frames/urllinkframe.cpp +++ /dev/null @@ -1,230 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - copyright : (C) 2006 by Urs Fleisch - email : ufleisch@users.sourceforge.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include "urllinkframe.h" -#include "id3v2tag.h" -#include <tdebug.h> -#include <tstringlist.h> -#include <tpropertymap.h> - -using namespace TagLib; -using namespace ID3v2; - -class UrlLinkFrame::UrlLinkFramePrivate -{ -public: - String url; -}; - -class UserUrlLinkFrame::UserUrlLinkFramePrivate -{ -public: - UserUrlLinkFramePrivate() : textEncoding(String::Latin1) {} - String::Type textEncoding; - String description; -}; - -UrlLinkFrame::UrlLinkFrame(const ByteVector &data) : - Frame(data) -{ - d = new UrlLinkFramePrivate; - setData(data); -} - -UrlLinkFrame::~UrlLinkFrame() -{ - delete d; -} - -void UrlLinkFrame::setUrl(const String &s) -{ - d->url = s; -} - -String UrlLinkFrame::url() const -{ - return d->url; -} - -void UrlLinkFrame::setText(const String &s) -{ - setUrl(s); -} - -String UrlLinkFrame::toString() const -{ - return url(); -} - -PropertyMap UrlLinkFrame::asProperties() const -{ - String key = frameIDToKey(frameID()); - PropertyMap map; - if(key.isNull()) - // unknown W*** frame - this normally shouldn't happen - map.unsupportedData().append(frameID()); - else - map.insert(key, url()); - return map; -} - -void UrlLinkFrame::parseFields(const ByteVector &data) -{ - d->url = String(data); -} - -ByteVector UrlLinkFrame::renderFields() const -{ - return d->url.data(String::Latin1); -} - -UrlLinkFrame::UrlLinkFrame(const ByteVector &data, Header *h) : Frame(h) -{ - d = new UrlLinkFramePrivate; - parseFields(fieldData(data)); -} - - -UserUrlLinkFrame::UserUrlLinkFrame(String::Type encoding) : - UrlLinkFrame("WXXX") -{ - d = new UserUrlLinkFramePrivate; - d->textEncoding = encoding; -} - -UserUrlLinkFrame::UserUrlLinkFrame(const ByteVector &data) : - UrlLinkFrame(data) -{ - d = new UserUrlLinkFramePrivate; - setData(data); -} - -UserUrlLinkFrame::~UserUrlLinkFrame() -{ - delete d; -} - -String UserUrlLinkFrame::toString() const -{ - return "[" + description() + "] " + url(); -} - -String::Type UserUrlLinkFrame::textEncoding() const -{ - return d->textEncoding; -} - -void UserUrlLinkFrame::setTextEncoding(String::Type encoding) -{ - d->textEncoding = encoding; -} - -String UserUrlLinkFrame::description() const -{ - return d->description; -} - -void UserUrlLinkFrame::setDescription(const String &s) -{ - d->description = s; -} - -PropertyMap UserUrlLinkFrame::asProperties() const -{ - PropertyMap map; - String key = description().upper(); - if(key.isEmpty() || key.upper() == "URL") - map.insert("URL", url()); - else if(key.isNull()) - map.unsupportedData().append(L"WXXX/" + description()); - else - map.insert("URL:" + key, url()); - return map; -} - -UserUrlLinkFrame *UserUrlLinkFrame::find(ID3v2::Tag *tag, const String &description) // static -{ - FrameList l = tag->frameList("WXXX"); - for(FrameList::Iterator it = l.begin(); it != l.end(); ++it) { - UserUrlLinkFrame *f = dynamic_cast<UserUrlLinkFrame *>(*it); - if(f && f->description() == description) - return f; - } - return 0; -} - -void UserUrlLinkFrame::parseFields(const ByteVector &data) -{ - if(data.size() < 2) { - debug("A user URL link frame must contain at least 2 bytes."); - return; - } - - int pos = 0; - - d->textEncoding = String::Type(data[0]); - pos += 1; - - if(d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8) { - int offset = data.find(textDelimiter(d->textEncoding), pos); - if(offset < pos) - return; - - d->description = String(data.mid(pos, offset - pos), d->textEncoding); - pos = offset + 1; - } - else { - int len = data.mid(pos).find(textDelimiter(d->textEncoding), 0, 2); - if(len < 0) - return; - - d->description = String(data.mid(pos, len), d->textEncoding); - pos += len + 2; - } - - setUrl(String(data.mid(pos))); -} - -ByteVector UserUrlLinkFrame::renderFields() const -{ - ByteVector v; - - String::Type encoding = checkTextEncoding(d->description, d->textEncoding); - - v.append(char(encoding)); - v.append(d->description.data(encoding)); - v.append(textDelimiter(encoding)); - v.append(url().data(String::Latin1)); - - return v; -} - -UserUrlLinkFrame::UserUrlLinkFrame(const ByteVector &data, Header *h) : UrlLinkFrame(data, h) -{ - d = new UserUrlLinkFramePrivate; - parseFields(fieldData(data)); -} diff --git a/taglib/taglib/mpeg/id3v2/frames/urllinkframe.h b/taglib/taglib/mpeg/id3v2/frames/urllinkframe.h deleted file mode 100644 index 7ac966b..0000000 --- a/taglib/taglib/mpeg/id3v2/frames/urllinkframe.h +++ /dev/null @@ -1,189 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - copyright : (C) 2006 by Urs Fleisch - email : ufleisch@users.sourceforge.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_URLLINKFRAME_H -#define TAGLIB_URLLINKFRAME_H - -#include "id3v2frame.h" - -namespace TagLib { - - namespace ID3v2 { - - //! ID3v2 URL frame - /*! - * An implementation of ID3v2 URL link frames. - */ - class TAGLIB_EXPORT UrlLinkFrame : public Frame - { - friend class FrameFactory; - - public: - /*! - * This is a dual purpose constructor. \a data can either be binary data - * that should be parsed or (at a minimum) the frame ID. - */ - explicit UrlLinkFrame(const ByteVector &data); - - /*! - * Destroys this UrlLinkFrame instance. - */ - virtual ~UrlLinkFrame(); - - /*! - * Returns the URL. - */ - virtual String url() const; - - /*! - * Sets the URL to \a s. - */ - virtual void setUrl(const String &s); - - // Reimplementations. - - virtual void setText(const String &s); - virtual String toString() const; - PropertyMap asProperties() const; - - protected: - virtual void parseFields(const ByteVector &data); - virtual ByteVector renderFields() const; - - /*! - * The constructor used by the FrameFactory. - */ - UrlLinkFrame(const ByteVector &data, Header *h); - - private: - UrlLinkFrame(const UrlLinkFrame &); - UrlLinkFrame &operator=(const UrlLinkFrame &); - - class UrlLinkFramePrivate; - UrlLinkFramePrivate *d; - }; - - //! ID3v2 User defined URL frame - - /*! - * This is a specialization of URL link frames that allows for - * user defined entries. Each entry has a description in addition to the - * normal list of fields that a URL link frame has. - * - * This description identifies the frame and must be unique. - */ - class TAGLIB_EXPORT UserUrlLinkFrame : public UrlLinkFrame - { - friend class FrameFactory; - - public: - /*! - * Constructs an empty user defined URL link frame. For this to be - * a useful frame both a description and text must be set. - */ - explicit UserUrlLinkFrame(String::Type encoding = String::Latin1); - - /*! - * This is a dual purpose constructor. \a data can either be binary data - * that should be parsed or (at a minimum) the frame ID. - */ - explicit UserUrlLinkFrame(const ByteVector &data); - - /*! - * Destroys this UserUrlLinkFrame instance. - */ - virtual ~UserUrlLinkFrame(); - - // Reimplementations. - - virtual String toString() const; - - /*! - * Returns the text encoding that will be used in rendering this frame. - * This defaults to the type that was either specified in the constructor - * or read from the frame when parsed. - * - * \see setTextEncoding() - * \see render() - */ - String::Type textEncoding() const; - - /*! - * Sets the text encoding to be used when rendering this frame to - * \a encoding. - * - * \see textEncoding() - * \see render() - */ - void setTextEncoding(String::Type encoding); - - /*! - * Returns the description for this frame. - */ - String description() const; - - /*! - * Sets the description of the frame to \a s. \a s must be unique. - */ - void setDescription(const String &s); - - /*! - * Parses the UserUrlLinkFrame as PropertyMap. The description() is taken as key, - * and the URL as single value. - * - if description() is empty, the key will be "URL". - * - otherwise, if description() is not a valid key (e.g. containing non-ASCII - * characters), the returned map will contain an entry "WXXX/<description>" - * in its unsupportedData() list. - */ - PropertyMap asProperties() const; - - /*! - * Searches for the user defined url frame with the description \a description - * in \a tag. This returns null if no matching frames were found. - */ - static UserUrlLinkFrame *find(Tag *tag, const String &description); - - protected: - virtual void parseFields(const ByteVector &data); - virtual ByteVector renderFields() const; - - /*! - * The constructor used by the FrameFactory. - */ - UserUrlLinkFrame(const ByteVector &data, Header *h); - - private: - UserUrlLinkFrame(const UserUrlLinkFrame &); - UserUrlLinkFrame &operator=(const UserUrlLinkFrame &); - - class UserUrlLinkFramePrivate; - UserUrlLinkFramePrivate *d; - }; - - } -} -#endif diff --git a/taglib/taglib/mpeg/id3v2/id3v2.2.0.txt b/taglib/taglib/mpeg/id3v2/id3v2.2.0.txt deleted file mode 100644 index a69bddd..0000000 --- a/taglib/taglib/mpeg/id3v2/id3v2.2.0.txt +++ /dev/null @@ -1,1660 +0,0 @@ - -Informal standard M. Nilsson -Document: id3v2-00.txt 26th March 1998 - - - ID3 tag version 2 - -Status of this document - - This document is an Informal standard and is released so that - implementors could have a set standard before the formal standard is - set. The formal standard will use another version number if not - identical to what is described in this document. The contents in this - document may change for clarifications but never for added or altered - functionallity. - - Distribution of this document is unlimited. - - -Abstract - - The recent gain of popularity for MPEG layer III audio files on the - internet forced a standardised way of storing information about an - audio file within itself to determinate its origin and contents. - - Today the most accepted way to do this is with the so called ID3 tag, - which is simple but very limited and in some cases very unsuitable. - The ID3 tag has very limited space in every field, very limited - numbers of fields, not expandable or upgradeable and is placed at the - end of a the file, which is unsuitable for streaming audio. This draft - is an attempt to answer these issues with a new version of the ID3 - tag. - - -1. Table of contents - - 2. Conventions in this document - 3. ID3v2 overview - 3.1. ID3v2 header - 3.2. ID3v2 frames overview - 4. Declared ID3v2 frames - 4.1. Unique file identifier - 4.2. Text information frames - 4.2.1. Text information frames - details - 4.2.2. User defined text information frame - 4.3. URL link frames - 4.3.1. URL link frames - details - 4.3.2. User defined URL link frame - 4.4. Involved people list - 4.5. Music CD Identifier - 4.6. Event timing codes - 4.7. MPEG location lookup table - 4.8. Synced tempo codes - 4.9. Unsychronised lyrics/text transcription - 4.10. Synchronised lyrics/text - 4.11. Comments - 4.12. Relative volume adjustment - 4.13. Equalisation - 4.14. Reverb - 4.15. Attached picture - 4.16. General encapsulated object - 4.17. Play counter - 4.18. Popularimeter - 4.19. Recommended buffer size - 4.20. Encrypted meta frame - 4.21. Audio encryption - 4.22. Linked information - 5. The 'unsynchronisation scheme' - 6. Copyright - 7. References - 8. Appendix - A. Appendix A - ID3-Tag Specification V1.1 - A.1. Overview - A.2. ID3v1 Implementation - A.3. Genre List - A.4. Track addition - ID3v1.1 - 9. Author's Address - - -2. Conventions in this document - - In the examples, text within "" is a text string exactly as it appears - in a file. Numbers preceded with $ are hexadecimal and numbers - preceded with % are binary. $xx is used to indicate a byte with - unknown content. %x is used to indicate a bit with unknown content. - The most significant bit (MSB) of a byte is called 'bit 7' and the - least significant bit (LSB) is called 'bit 0'. - - A tag is the whole tag described in this document. A frame is a block - of information in the tag. The tag consists of a header, frames and - optional padding. A field is a piece of information; one value, a - string etc. A numeric string is a string that consists of the - characters 0-9 only. - - -3. ID3v2 overview - - The two biggest design goals were to be able to implement ID3v2 - without disturbing old software too much and that ID3v2 should be - expandable. - - The first criterion is met by the simple fact that the MPEG [MPEG] - decoding software uses a syncsignal, embedded in the audiostream, to - 'lock on to' the audio. Since the ID3v2 tag doesn't contain a valid - syncsignal, no software will attempt to play the tag. If, for any - reason, coincidence make a syncsignal appear within the tag it will be - taken care of by the 'unsynchronisation scheme' described in section - 5. - - The second criterion has made a more noticeable impact on the design - of the ID3v2 tag. It is constructed as a container for several - information blocks, called frames, whose format need not be known to - the software that encounters them. At the start of every frame there - is an identifier that explains the frames's format and content, and a - size descriptor that allows software to skip unknown frames. - - If a total revision of the ID3v2 tag should be needed, there is a - version number and a size descriptor in the ID3v2 header. - - The ID3 tag described in this document is mainly targeted to files - encoded with MPEG-2 layer I, MPEG-2 layer II, MPEG-2 layer III and - MPEG-2.5, but may work with other types of encoded audio. - - The bitorder in ID3v2 is most significant bit first (MSB). The - byteorder in multibyte numbers is most significant byte first (e.g. - $12345678 would be encoded $12 34 56 78). - - It is permitted to include padding after all the final frame (at the - end of the ID3 tag), making the size of all the frames together - smaller than the size given in the head of the tag. A possible purpose - of this padding is to allow for adding a few additional frames or - enlarge existing frames within the tag without having to rewrite the - entire file. The value of the padding bytes must be $00. - - -3.1. ID3v2 header - - The ID3v2 tag header, which should be the first information in the - file, is 10 bytes as follows: - - ID3/file identifier "ID3" - ID3 version $02 00 - ID3 flags %xx000000 - ID3 size 4 * %0xxxxxxx - - The first three bytes of the tag are always "ID3" to indicate that - this is an ID3 tag, directly followed by the two version bytes. The - first byte of ID3 version is it's major version, while the second byte - is its revision number. All revisions are backwards compatible while - major versions are not. If software with ID3v2 and below support - should encounter version three or higher it should simply ignore the - whole tag. Version and revision will never be $FF. - - The first bit (bit 7) in the 'ID3 flags' is indicating whether or not - unsynchronisation is used (see section 5 for details); a set bit - indicates usage. - - The second bit (bit 6) is indicating whether or not compression is - used; a set bit indicates usage. Since no compression scheme has been - decided yet, the ID3 decoder (for now) should just ignore the entire - tag if the compression bit is set. - - The ID3 tag size is encoded with four bytes where the first bit (bit - 7) is set to zero in every byte, making a total of 28 bits. The zeroed - bits are ignored, so a 257 bytes long tag is represented as $00 00 02 - 01. - - The ID3 tag size is the size of the complete tag after - unsychronisation, including padding, excluding the header (total tag - size - 10). The reason to use 28 bits (representing up to 256MB) for - size description is that we don't want to run out of space here. - - A ID3v2 tag can be detected with the following pattern: - $49 44 33 yy yy xx zz zz zz zz - Where yy is less than $FF, xx is the 'flags' byte and zz is less than - $80. - - -3.2. ID3v2 frames overview - - The headers of the frames are similar in their construction. They - consist of one three character identifier (capital A-Z and 0-9) and - one three byte size field, making a total of six bytes. The header is - excluded from the size. Identifiers beginning with "X", "Y" and "Z" - are for experimental use and free for everyone to use. Have in mind - that someone else might have used the same identifier as you. All - other identifiers are either used or reserved for future use. - - The three character frame identifier is followed by a three byte size - descriptor, making a total header size of six bytes in every frame. - The size is calculated as framesize excluding frame identifier and - size descriptor (frame size - 6). - - There is no fixed order of the frames' appearance in the tag, although - it is desired that the frames are arranged in order of significance - concerning the recognition of the file. An example of such order: - UFI, MCI, TT2 ... - - A tag must contain at least one frame. A frame must be at least 1 byte - big, excluding the 6-byte header. - - If nothing else is said a string is represented as ISO-8859-1 - [ISO-8859-1] characters in the range $20 - $FF. All unicode strings - [UNICODE] use 16-bit unicode 2.0 (ISO/IEC 10646-1:1993, UCS-2). All - numeric strings are always encoded as ISO-8859-1. Terminated strings - are terminated with $00 if encoded with ISO-8859-1 and $00 00 if - encoded as unicode. If nothing else is said newline character is - forbidden. In ISO-8859-1 a new line is represented, when allowed, with - $0A only. Frames that allow different types of text encoding have a - text encoding description byte directly after the frame size. If - ISO-8859-1 is used this byte should be $00, if unicode is used it - should be $01. - - The three byte language field is used to describe the language of the - frame's content, according to ISO-639-2 [ISO-639-2]. - - All URLs [URL] may be relative, e.g. "picture.png", "../doc.txt". - - If a frame is longer than it should be, e.g. having more fields than - specified in this document, that indicates that additions to the - frame have been made in a later version of the ID3 standard. This - is reflected by the revision number in the header of the tag. - - -4. Declared ID3v2 frames - - The following frames are declared in this draft. - - 4.19 BUF Recommended buffer size - - 4.17 CNT Play counter - 4.11 COM Comments - 4.21 CRA Audio encryption - 4.20 CRM Encrypted meta frame - - 4.6 ETC Event timing codes - 4.13 EQU Equalization - - 4.16 GEO General encapsulated object - - 4.4 IPL Involved people list - - 4.22 LNK Linked information - - 4.5 MCI Music CD Identifier - 4.7 MLL MPEG location lookup table - - 4.15 PIC Attached picture - 4.18 POP Popularimeter - - 4.14 REV Reverb - 4.12 RVA Relative volume adjustment - - 4.10 SLT Synchronized lyric/text - 4.8 STC Synced tempo codes - - 4.2.1 TAL Album/Movie/Show title - 4.2.1 TBP BPM (Beats Per Minute) - 4.2.1 TCM Composer - 4.2.1 TCO Content type - 4.2.1 TCR Copyright message - 4.2.1 TDA Date - 4.2.1 TDY Playlist delay - 4.2.1 TEN Encoded by - 4.2.1 TFT File type - 4.2.1 TIM Time - 4.2.1 TKE Initial key - 4.2.1 TLA Language(s) - 4.2.1 TLE Length - 4.2.1 TMT Media type - 4.2.1 TOA Original artist(s)/performer(s) - 4.2.1 TOF Original filename - 4.2.1 TOL Original Lyricist(s)/text writer(s) - 4.2.1 TOR Original release year - 4.2.1 TOT Original album/Movie/Show title - 4.2.1 TP1 Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group - 4.2.1 TP2 Band/Orchestra/Accompaniment - 4.2.1 TP3 Conductor/Performer refinement - 4.2.1 TP4 Interpreted, remixed, or otherwise modified by - 4.2.1 TPA Part of a set - 4.2.1 TPB Publisher - 4.2.1 TRC ISRC (International Standard Recording Code) - 4.2.1 TRD Recording dates - 4.2.1 TRK Track number/Position in set - 4.2.1 TSI Size - 4.2.1 TSS Software/hardware and settings used for encoding - 4.2.1 TT1 Content group description - 4.2.1 TT2 Title/Songname/Content description - 4.2.1 TT3 Subtitle/Description refinement - 4.2.1 TXT Lyricist/text writer - 4.2.2 TXX User defined text information frame - 4.2.1 TYE Year - - 4.1 UFI Unique file identifier - 4.9 ULT Unsychronized lyric/text transcription - - 4.3.1 WAF Official audio file webpage - 4.3.1 WAR Official artist/performer webpage - 4.3.1 WAS Official audio source webpage - 4.3.1 WCM Commercial information - 4.3.1 WCP Copyright/Legal information - 4.3.1 WPB Publishers official webpage - 4.3.2 WXX User defined URL link frame - - -4.1. Unique file identifier - - This frame's purpose is to be able to identify the audio file in a - database that may contain more information relevant to the content. - Since standardisation of such a database is beyond this document, all - frames begin with a null-terminated string with a URL [URL] containing - an email address, or a link to a location where an email address can - be found, that belongs to the organisation responsible for this - specific database implementation. Questions regarding the database - should be sent to the indicated email address. The URL should not be - used for the actual database queries. If a $00 is found directly after - the 'Frame size' the whole frame should be ignored, and preferably be - removed. The 'Owner identifier' is then followed by the actual - identifier, which may be up to 64 bytes. There may be more than one - "UFI" frame in a tag, but only one with the same 'Owner identifier'. - - Unique file identifier "UFI" - Frame size $xx xx xx - Owner identifier <textstring> $00 - Identifier <up to 64 bytes binary data> - - -4.2. Text information frames - - The text information frames are the most important frames, containing - information like artist, album and more. There may only be one text - information frame of its kind in an tag. If the textstring is followed - by a termination ($00 (00)) all the following information should be - ignored and not be displayed. All the text information frames have the - following format: - - Text information identifier "T00" - "TZZ" , excluding "TXX", - described in 4.2.2. - Frame size $xx xx xx - Text encoding $xx - Information <textstring> - - -4.2.1. Text information frames - details - - TT1 - The 'Content group description' frame is used if the sound belongs to - a larger category of sounds/music. For example, classical music is - often sorted in different musical sections (e.g. "Piano Concerto", - "Weather - Hurricane"). - - TT2 - The 'Title/Songname/Content description' frame is the actual name of - the piece (e.g. "Adagio", "Hurricane Donna"). - - TT3 - The 'Subtitle/Description refinement' frame is used for information - directly related to the contents title (e.g. "Op. 16" or "Performed - live at wembley"). - - TP1 - The 'Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group' is - used for the main artist(s). They are seperated with the "/" - character. - - TP2 - The 'Band/Orchestra/Accompaniment' frame is used for additional - information about the performers in the recording. - - TP3 - The 'Conductor' frame is used for the name of the conductor. - - TP4 - The 'Interpreted, remixed, or otherwise modified by' frame contains - more information about the people behind a remix and similar - interpretations of another existing piece. - - TCM - The 'Composer(s)' frame is intended for the name of the composer(s). - They are seperated with the "/" character. - - TXT - The 'Lyricist(s)/text writer(s)' frame is intended for the writer(s) - of the text or lyrics in the recording. They are seperated with the - "/" character. - - TLA - The 'Language(s)' frame should contain the languages of the text or - lyrics in the audio file. The language is represented with three - characters according to ISO-639-2. If more than one language is used - in the text their language codes should follow according to their - usage. - - TCO - The content type, which previously (in ID3v1.1, see appendix A) was - stored as a one byte numeric value only, is now a numeric string. You - may use one or several of the types as ID3v1.1 did or, since the - category list would be impossible to maintain with accurate and up to - date categories, define your own. - References to the ID3v1 genres can be made by, as first byte, enter - "(" followed by a number from the genres list (section A.3.) and - ended with a ")" character. This is optionally followed by a - refinement, e.g. "(21)" or "(4)Eurodisco". Several references can be - made in the same frame, e.g. "(51)(39)". If the refinement should - begin with a "(" character it should be replaced with "((", e.g. "((I - can figure out any genre)" or "(55)((I think...)". The following new - content types is defined in ID3v2 and is implemented in the same way - as the numerig content types, e.g. "(RX)". - - RX Remix - CR Cover - - TAL - The 'Album/Movie/Show title' frame is intended for the title of the - recording(/source of sound) which the audio in the file is taken from. - - TPA - The 'Part of a set' frame is a numeric string that describes which - part of a set the audio came from. This frame is used if the source - described in the "TAL" frame is divided into several mediums, e.g. a - double CD. The value may be extended with a "/" character and a - numeric string containing the total number of parts in the set. E.g. - "1/2". - - TRK - The 'Track number/Position in set' frame is a numeric string - containing the order number of the audio-file on its original - recording. This may be extended with a "/" character and a numeric - string containing the total numer of tracks/elements on the original - recording. E.g. "4/9". - - TRC - The 'ISRC' frame should contian the International Standard Recording - Code [ISRC]. - - TYE - The 'Year' frame is a numeric string with a year of the recording. - This frames is always four characters long (until the year 10000). - - TDA - The 'Date' frame is a numeric string in the DDMM format containing - the date for the recording. This field is always four characters - long. - - TIM - The 'Time' frame is a numeric string in the HHMM format containing - the time for the recording. This field is always four characters - long. - - TRD - The 'Recording dates' frame is a intended to be used as complement to - the "TYE", "TDA" and "TIM" frames. E.g. "4th-7th June, 12th June" in - combination with the "TYE" frame. - - TMT - The 'Media type' frame describes from which media the sound - originated. This may be a textstring or a reference to the predefined - media types found in the list below. References are made within "(" - and ")" and are optionally followed by a text refinement, e.g. "(MC) - with four channels". If a text refinement should begin with a "(" - character it should be replaced with "((" in the same way as in the - "TCO" frame. Predefined refinements is appended after the media type, - e.g. "(CD/S)" or "(VID/PAL/VHS)". - - DIG Other digital media - /A Analog transfer from media - - ANA Other analog media - /WAC Wax cylinder - /8CA 8-track tape cassette - - CD CD - /A Analog transfer from media - /DD DDD - /AD ADD - /AA AAD - - LD Laserdisc - /A Analog transfer from media - - TT Turntable records - /33 33.33 rpm - /45 45 rpm - /71 71.29 rpm - /76 76.59 rpm - /78 78.26 rpm - /80 80 rpm - - MD MiniDisc - /A Analog transfer from media - - DAT DAT - /A Analog transfer from media - /1 standard, 48 kHz/16 bits, linear - /2 mode 2, 32 kHz/16 bits, linear - /3 mode 3, 32 kHz/12 bits, nonlinear, low speed - /4 mode 4, 32 kHz/12 bits, 4 channels - /5 mode 5, 44.1 kHz/16 bits, linear - /6 mode 6, 44.1 kHz/16 bits, 'wide track' play - - DCC DCC - /A Analog transfer from media - - DVD DVD - /A Analog transfer from media - - TV Television - /PAL PAL - /NTSC NTSC - /SECAM SECAM - - VID Video - /PAL PAL - /NTSC NTSC - /SECAM SECAM - /VHS VHS - /SVHS S-VHS - /BETA BETAMAX - - RAD Radio - /FM FM - /AM AM - /LW LW - /MW MW - - TEL Telephone - /I ISDN - - MC MC (normal cassette) - /4 4.75 cm/s (normal speed for a two sided cassette) - /9 9.5 cm/s - /I Type I cassette (ferric/normal) - /II Type II cassette (chrome) - /III Type III cassette (ferric chrome) - /IV Type IV cassette (metal) - - REE Reel - /9 9.5 cm/s - /19 19 cm/s - /38 38 cm/s - /76 76 cm/s - /I Type I cassette (ferric/normal) - /II Type II cassette (chrome) - /III Type III cassette (ferric chrome) - /IV Type IV cassette (metal) - - TFT - The 'File type' frame indicates which type of audio this tag defines. - The following type and refinements are defined: - - MPG MPEG Audio - /1 MPEG 2 layer I - /2 MPEG 2 layer II - /3 MPEG 2 layer III - /2.5 MPEG 2.5 - /AAC Advanced audio compression - - but other types may be used, not for these types though. This is used - in a similar way to the predefined types in the "TMT" frame, but - without parenthesis. If this frame is not present audio type is - assumed to be "MPG". - - TBP - BPM is short for beats per minute, and is easily computed by - dividing the number of beats in a musical piece with its length. To - get a more accurate result, do the BPM calculation on the main-part - only. To acquire best result measure the time between each beat and - calculate individual BPM for each beat and use the median value as - result. BPM is an integer and represented as a numerical string. - - TCR - The 'Copyright message' frame, which must begin with a year and a - space character (making five characters), is intended for the - copyright holder of the original sound, not the audio file itself. The - absence of this frame means only that the copyright information is - unavailable or has been removed, and must not be interpreted to mean - that the sound is public domain. Every time this field is displayed - the field must be preceded with "Copyright " (C) " ", where (C) is one - character showing a C in a circle. - - TPB - The 'Publisher' frame simply contains the name of the label or - publisher. - - TEN - The 'Encoded by' frame contains the name of the person or - organisation that encoded the audio file. This field may contain a - copyright message, if the audio file also is copyrighted by the - encoder. - - TSS - The 'Software/hardware and settings used for encoding' frame - includes the used audio encoder and its settings when the file was - encoded. Hardware refers to hardware encoders, not the computer on - which a program was run. - - TOF - The 'Original filename' frame contains the preferred filename for the - file, since some media doesn't allow the desired length of the - filename. The filename is case sensitive and includes its suffix. - - TLE - The 'Length' frame contains the length of the audiofile in - milliseconds, represented as a numeric string. - - TSI - The 'Size' frame contains the size of the audiofile in bytes - excluding the tag, represented as a numeric string. - - TDY - The 'Playlist delay' defines the numbers of milliseconds of silence - between every song in a playlist. The player should use the "ETC" - frame, if present, to skip initial silence and silence at the end of - the audio to match the 'Playlist delay' time. The time is represented - as a numeric string. - - TKE - The 'Initial key' frame contains the musical key in which the sound - starts. It is represented as a string with a maximum length of three - characters. The ground keys are represented with "A","B","C","D","E", - "F" and "G" and halfkeys represented with "b" and "#". Minor is - represented as "m". Example "Cbm". Off key is represented with an "o" - only. - - TOT - The 'Original album/Movie/Show title' frame is intended for the title - of the original recording(/source of sound), if for example the music - in the file should be a cover of a previously released song. - - TOA - The 'Original artist(s)/performer(s)' frame is intended for the - performer(s) of the original recording, if for example the music in - the file should be a cover of a previously released song. The - performers are seperated with the "/" character. - - TOL - The 'Original Lyricist(s)/text writer(s)' frame is intended for the - text writer(s) of the original recording, if for example the music in - the file should be a cover of a previously released song. The text - writers are seperated with the "/" character. - - TOR - The 'Original release year' frame is intended for the year when the - original recording, if for example the music in the file should be a - cover of a previously released song, was released. The field is - formatted as in the "TDY" frame. - - -4.2.2. User defined text information frame - - This frame is intended for one-string text information concerning the - audiofile in a similar way to the other "T"xx frames. The frame body - consists of a description of the string, represented as a terminated - string, followed by the actual string. There may be more than one - "TXX" frame in each tag, but only one with the same description. - - User defined... "TXX" - Frame size $xx xx xx - Text encoding $xx - Description <textstring> $00 (00) - Value <textstring> - - -4.3. URL link frames - - With these frames dynamic data such as webpages with touring - information, price information or plain ordinary news can be added to - the tag. There may only be one URL [URL] link frame of its kind in an - tag, except when stated otherwise in the frame description. If the - textstring is followed by a termination ($00 (00)) all the following - information should be ignored and not be displayed. All URL link - frames have the following format: - - URL link frame "W00" - "WZZ" , excluding "WXX" - (described in 4.3.2.) - Frame size $xx xx xx - URL <textstring> - - -4.3.1. URL link frames - details - - WAF - The 'Official audio file webpage' frame is a URL pointing at a file - specific webpage. - - WAR - The 'Official artist/performer webpage' frame is a URL pointing at - the artists official webpage. There may be more than one "WAR" frame - in a tag if the audio contains more than one performer. - - WAS - The 'Official audio source webpage' frame is a URL pointing at the - official webpage for the source of the audio file, e.g. a movie. - - WCM - The 'Commercial information' frame is a URL pointing at a webpage - with information such as where the album can be bought. There may be - more than one "WCM" frame in a tag. - - WCP - The 'Copyright/Legal information' frame is a URL pointing at a - webpage where the terms of use and ownership of the file is described. - - WPB - The 'Publishers official webpage' frame is a URL pointing at the - official wepage for the publisher. - - -4.3.2. User defined URL link frame - - This frame is intended for URL [URL] links concerning the audiofile in - a similar way to the other "W"xx frames. The frame body consists of a - description of the string, represented as a terminated string, - followed by the actual URL. The URL is always encoded with ISO-8859-1 - [ISO-8859-1]. There may be more than one "WXX" frame in each tag, but - only one with the same description. - - User defined... "WXX" - Frame size $xx xx xx - Text encoding $xx - Description <textstring> $00 (00) - URL <textstring> - - -4.4. Involved people list - - Since there might be a lot of people contributing to an audio file in - various ways, such as musicians and technicians, the 'Text - information frames' are often insufficient to list everyone involved - in a project. The 'Involved people list' is a frame containing the - names of those involved, and how they were involved. The body simply - contains a terminated string with the involvement directly followed by - a terminated string with the involvee followed by a new involvement - and so on. There may only be one "IPL" frame in each tag. - - Involved people list "IPL" - Frame size $xx xx xx - Text encoding $xx - People list strings <textstrings> - - -4.5. Music CD Identifier - - This frame is intended for music that comes from a CD, so that the CD - can be identified in databases such as the CDDB [CDDB]. The frame - consists of a binary dump of the Table Of Contents, TOC, from the CD, - which is a header of 4 bytes and then 8 bytes/track on the CD making a - maximum of 804 bytes. This frame requires a present and valid "TRK" - frame. There may only be one "MCI" frame in each tag. - - Music CD identifier "MCI" - Frame size $xx xx xx - CD TOC <binary data> - - -4.6. Event timing codes - - This frame allows synchronisation with key events in a song or sound. - The head is: - - Event timing codes "ETC" - Frame size $xx xx xx - Time stamp format $xx - - Where time stamp format is: - - $01 Absolute time, 32 bit sized, using MPEG [MPEG] frames as unit - $02 Absolute time, 32 bit sized, using milliseconds as unit - - Abolute time means that every stamp contains the time from the - beginning of the file. - - Followed by a list of key events in the following format: - - Type of event $xx - Time stamp $xx (xx ...) - - The 'Time stamp' is set to zero if directly at the beginning of the - sound or after the previous event. All events should be sorted in - chronological order. The type of event is as follows: - - $00 padding (has no meaning) - $01 end of initial silence - $02 intro start - $03 mainpart start - $04 outro start - $05 outro end - $06 verse begins - $07 refrain begins - $08 interlude - $09 theme start - $0A variation - $0B key change - $0C time change - $0D unwanted noise (Snap, Crackle & Pop) - - $0E-$DF reserved for future use - - $E0-$EF not predefined sync 0-F - - $F0-$FC reserved for future use - - $FD audio end (start of silence) - $FE audio file ends - $FF one more byte of events follows (all the following bytes with - the value $FF have the same function) - - The 'Not predefined sync's ($E0-EF) are for user events. You might - want to synchronise your music to something, like setting of an - explosion on-stage, turning on your screensaver etc. - - There may only be one "ETC" frame in each tag. - - -4.7. MPEG location lookup table - - To increase performance and accuracy of jumps within a MPEG [MPEG] - audio file, frames with timecodes in different locations in the file - might be useful. The ID3 frame includes references that the software - can use to calculate positions in the file. After the frame header is - a descriptor of how much the 'frame counter' should increase for every - reference. If this value is two then the first reference points out - the second frame, the 2nd reference the 4th frame, the 3rd reference - the 6th frame etc. In a similar way the 'bytes between reference' and - 'milliseconds between reference' points out bytes and milliseconds - respectively. - - Each reference consists of two parts; a certain number of bits, as - defined in 'bits for bytes deviation', that describes the difference - between what is said in 'bytes between reference' and the reality and - a certain number of bits, as defined in 'bits for milliseconds - deviation', that describes the difference between what is said in - 'milliseconds between reference' and the reality. The number of bits - in every reference, i.e. 'bits for bytes deviation'+'bits for - milliseconds deviation', must be a multiple of four. There may only be - one "MLL" frame in each tag. - - Location lookup table "MLL" - ID3 frame size $xx xx xx - MPEG frames between reference $xx xx - Bytes between reference $xx xx xx - Milliseconds between reference $xx xx xx - Bits for bytes deviation $xx - Bits for milliseconds dev. $xx - - Then for every reference the following data is included; - - Deviation in bytes %xxx.... - Deviation in milliseconds %xxx.... - - -4.8. Synced tempo codes - - For a more accurate description of the tempo of a musical piece this - frame might be used. After the header follows one byte describing - which time stamp format should be used. Then follows one or more tempo - codes. Each tempo code consists of one tempo part and one time part. - The tempo is in BPM described with one or two bytes. If the first byte - has the value $FF, one more byte follows, which is added to the first - giving a range from 2 - 510 BPM, since $00 and $01 is reserved. $00 is - used to describe a beat-free time period, which is not the same as a - music-free time period. $01 is used to indicate one single beat-stroke - followed by a beat-free period. - - The tempo descriptor is followed by a time stamp. Every time the tempo - in the music changes, a tempo descriptor may indicate this for the - player. All tempo descriptors should be sorted in chronological order. - The first beat-stroke in a time-period is at the same time as the beat - description occurs. There may only be one "STC" frame in each tag. - - Synced tempo codes "STC" - Frame size $xx xx xx - Time stamp format $xx - Tempo data <binary data> - - Where time stamp format is: - - $01 Absolute time, 32 bit sized, using MPEG [MPEG] frames as unit - $02 Absolute time, 32 bit sized, using milliseconds as unit - - Abolute time means that every stamp contains the time from the - beginning of the file. - - -4.9. Unsychronised lyrics/text transcription - - This frame contains the lyrics of the song or a text transcription of - other vocal activities. The head includes an encoding descriptor and - a content descriptor. The body consists of the actual text. The - 'Content descriptor' is a terminated string. If no descriptor is - entered, 'Content descriptor' is $00 (00) only. Newline characters - are allowed in the text. Maximum length for the descriptor is 64 - bytes. There may be more than one lyrics/text frame in each tag, but - only one with the same language and content descriptor. - - Unsynced lyrics/text "ULT" - Frame size $xx xx xx - Text encoding $xx - Language $xx xx xx - Content descriptor <textstring> $00 (00) - Lyrics/text <textstring> - - -4.10. Synchronised lyrics/text - - This is another way of incorporating the words, said or sung lyrics, - in the audio file as text, this time, however, in sync with the audio. - It might also be used to describing events e.g. occurring on a stage - or on the screen in sync with the audio. The header includes a content - descriptor, represented with as terminated textstring. If no - descriptor is entered, 'Content descriptor' is $00 (00) only. - - Synced lyrics/text "SLT" - Frame size $xx xx xx - Text encoding $xx - Language $xx xx xx - Time stamp format $xx - Content type $xx - Content descriptor <textstring> $00 (00) - - - Encoding: $00 ISO-8859-1 [ISO-8859-1] character set is used => $00 - is sync identifier. - $01 Unicode [UNICODE] character set is used => $00 00 is - sync identifier. - - Content type: $00 is other - $01 is lyrics - $02 is text transcription - $03 is movement/part name (e.g. "Adagio") - $04 is events (e.g. "Don Quijote enters the stage") - $05 is chord (e.g. "Bb F Fsus") - - Time stamp format is: - - $01 Absolute time, 32 bit sized, using MPEG [MPEG] frames as unit - $02 Absolute time, 32 bit sized, using milliseconds as unit - - Abolute time means that every stamp contains the time from the - beginning of the file. - - The text that follows the frame header differs from that of the - unsynchronised lyrics/text transcription in one major way. Each - syllable (or whatever size of text is considered to be convenient by - the encoder) is a null terminated string followed by a time stamp - denoting where in the sound file it belongs. Each sync thus has the - following structure: - - Terminated text to be synced (typically a syllable) - Sync identifier (terminator to above string) $00 (00) - Time stamp $xx (xx ...) - - The 'time stamp' is set to zero or the whole sync is omitted if - located directly at the beginning of the sound. All time stamps should - be sorted in chronological order. The sync can be considered as a - validator of the subsequent string. - - Newline characters are allowed in all "SLT" frames and should be used - after every entry (name, event etc.) in a frame with the content type - $03 - $04. - - A few considerations regarding whitespace characters: Whitespace - separating words should mark the beginning of a new word, thus - occurring in front of the first syllable of a new word. This is also - valid for new line characters. A syllable followed by a comma should - not be broken apart with a sync (both the syllable and the comma - should be before the sync). - - An example: The "ULT" passage - - "Strangers in the night" $0A "Exchanging glances" - - would be "SLT" encoded as: - - "Strang" $00 xx xx "ers" $00 xx xx " in" $00 xx xx " the" $00 xx xx - " night" $00 xx xx 0A "Ex" $00 xx xx "chang" $00 xx xx "ing" $00 xx - xx "glan" $00 xx xx "ces" $00 xx xx - - There may be more than one "SLT" frame in each tag, but only one with - the same language and content descriptor. - - -4.11. Comments - - This frame replaces the old 30-character comment field in ID3v1. It - consists of a frame head followed by encoding, language and content - descriptors and is ended with the actual comment as a text string. - Newline characters are allowed in the comment text string. There may - be more than one comment frame in each tag, but only one with the same - language and content descriptor. - - Comment "COM" - Frame size $xx xx xx - Text encoding $xx - Language $xx xx xx - Short content description <textstring> $00 (00) - The actual text <textstring> - - -4.12. Relative volume adjustment - - This is a more subjective function than the previous ones. It allows - the user to say how much he wants to increase/decrease the volume on - each channel while the file is played. The purpose is to be able to - align all files to a reference volume, so that you don't have to - change the volume constantly. This frame may also be used to balance - adjust the audio. If the volume peak levels are known then this could - be described with the 'Peak volume right' and 'Peak volume left' - field. If Peakvolume is not known these fields could be left zeroed - or completely omitted. There may only be one "RVA" frame in each - tag. - - Relative volume adjustment "RVA" - Frame size $xx xx xx - Increment/decrement %000000xx - Bits used for volume descr. $xx - Relative volume change, right $xx xx (xx ...) - Relative volume change, left $xx xx (xx ...) - Peak volume right $xx xx (xx ...) - Peak volume left $xx xx (xx ...) - - In the increment/decrement field bit 0 is used to indicate the right - channel and bit 1 is used to indicate the left channel. 1 is - increment and 0 is decrement. - - The 'bits used for volume description' field is normally $10 (16 bits) - for MPEG 2 layer I, II and III [MPEG] and MPEG 2.5. This value may not - be $00. The volume is always represented with whole bytes, padded in - the beginning (highest bits) when 'bits used for volume description' - is not a multiple of eight. - - -4.13. Equalisation - - This is another subjective, alignment frame. It allows the user to - predefine an equalisation curve within the audio file. There may only - be one "EQU" frame in each tag. - - Equalisation "EQU" - Frame size $xx xx xx - Adjustment bits $xx - - The 'adjustment bits' field defines the number of bits used for - representation of the adjustment. This is normally $10 (16 bits) for - MPEG 2 layer I, II and III [MPEG] and MPEG 2.5. This value may not be - $00. - - This is followed by 2 bytes + ('adjustment bits' rounded up to the - nearest byte) for every equalisation band in the following format, - giving a frequency range of 0 - 32767Hz: - - Increment/decrement %x (MSB of the Frequency) - Frequency (lower 15 bits) - Adjustment $xx (xx ...) - - The increment/decrement bit is 1 for increment and 0 for decrement. - The equalisation bands should be ordered increasingly with reference - to frequency. All frequencies don't have to be declared. Adjustments - with the value $00 should be omitted. A frequency should only be - described once in the frame. - - -4.14. Reverb - - Yet another subjective one. You may here adjust echoes of different - kinds. Reverb left/right is the delay between every bounce in ms. - Reverb bounces left/right is the number of bounces that should be - made. $FF equals an infinite number of bounces. Feedback is the amount - of volume that should be returned to the next echo bounce. $00 is 0%, - $FF is 100%. If this value were $7F, there would be 50% volume - reduction on the first bounce, yet 50% on the second and so on. Left - to left means the sound from the left bounce to be played in the left - speaker, while left to right means sound from the left bounce to be - played in the right speaker. - - 'Premix left to right' is the amount of left sound to be mixed in the - right before any reverb is applied, where $00 id 0% and $FF is 100%. - 'Premix right to left' does the same thing, but right to left. Setting - both premix to $FF would result in a mono output (if the reverb is - applied symmetric). There may only be one "REV" frame in each tag. - - Reverb settings "REV" - Frame size $00 00 0C - Reverb left (ms) $xx xx - Reverb right (ms) $xx xx - Reverb bounces, left $xx - Reverb bounces, right $xx - Reverb feedback, left to left $xx - Reverb feedback, left to right $xx - Reverb feedback, right to right $xx - Reverb feedback, right to left $xx - Premix left to right $xx - Premix right to left $xx - - -4.15. Attached picture - - This frame contains a picture directly related to the audio file. - Image format is preferably "PNG" [PNG] or "JPG" [JFIF]. Description - is a short description of the picture, represented as a terminated - textstring. The description has a maximum length of 64 characters, - but may be empty. There may be several pictures attached to one file, - each in their individual "PIC" frame, but only one with the same - content descriptor. There may only be one picture with the picture - type declared as picture type $01 and $02 respectively. There is a - possibility to put only a link to the image file by using the 'image - format' "-->" and having a complete URL [URL] instead of picture data. - The use of linked files should however be used restrictively since - there is the risk of separation of files. - - Attached picture "PIC" - Frame size $xx xx xx - Text encoding $xx - Image format $xx xx xx - Picture type $xx - Description <textstring> $00 (00) - Picture data <binary data> - - - Picture type: $00 Other - $01 32x32 pixels 'file icon' (PNG only) - $02 Other file icon - $03 Cover (front) - $04 Cover (back) - $05 Leaflet page - $06 Media (e.g. lable side of CD) - $07 Lead artist/lead performer/soloist - $08 Artist/performer - $09 Conductor - $0A Band/Orchestra - $0B Composer - $0C Lyricist/text writer - $0D Recording Location - $0E During recording - $0F During performance - $10 Movie/video screen capture - $11 A bright coloured fish - $12 Illustration - $13 Band/artist logotype - $14 Publisher/Studio logotype - - -4.16. General encapsulated object - - In this frame any type of file can be encapsulated. After the header, - 'Frame size' and 'Encoding' follows 'MIME type' [MIME] and 'Filename' - for the encapsulated object, both represented as terminated strings - encoded with ISO 8859-1 [ISO-8859-1]. The filename is case sensitive. - Then follows a content description as terminated string, encoded as - 'Encoding'. The last thing in the frame is the actual object. The - first two strings may be omitted, leaving only their terminations. - MIME type is always an ISO-8859-1 text string. There may be more than - one "GEO" frame in each tag, but only one with the same content - descriptor. - - General encapsulated object "GEO" - Frame size $xx xx xx - Text encoding $xx - MIME type <textstring> $00 - Filename <textstring> $00 (00) - Content description <textstring> $00 (00) - Encapsulated object <binary data> - - -4.17. Play counter - - This is simply a counter of the number of times a file has been - played. The value is increased by one every time the file begins to - play. There may only be one "CNT" frame in each tag. When the counter - reaches all one's, one byte is inserted in front of the counter thus - making the counter eight bits bigger. The counter must be at least - 32-bits long to begin with. - - Play counter "CNT" - Frame size $xx xx xx - Counter $xx xx xx xx (xx ...) - - -4.18. Popularimeter - - The purpose of this frame is to specify how good an audio file is. - Many interesting applications could be found to this frame such as a - playlist that features better audiofiles more often than others or it - could be used to profile a persons taste and find other 'good' files - by comparing people's profiles. The frame is very simple. It contains - the email address to the user, one rating byte and a four byte play - counter, intended to be increased with one for every time the file is - played. The email is a terminated string. The rating is 1-255 where - 1 is worst and 255 is best. 0 is unknown. If no personal counter is - wanted it may be omitted. When the counter reaches all one's, one - byte is inserted in front of the counter thus making the counter - eight bits bigger in the same away as the play counter ("CNT"). - There may be more than one "POP" frame in each tag, but only one with - the same email address. - - Popularimeter "POP" - Frame size $xx xx xx - Email to user <textstring> $00 - Rating $xx - Counter $xx xx xx xx (xx ...) - - -4.19. Recommended buffer size - - Sometimes the server from which a audio file is streamed is aware of - transmission or coding problems resulting in interruptions in the - audio stream. In these cases, the size of the buffer can be - recommended by the server using this frame. If the 'embedded info - flag' is true (1) then this indicates that an ID3 tag with the - maximum size described in 'Buffer size' may occur in the audiostream. - In such case the tag should reside between two MPEG [MPEG] frames, if - the audio is MPEG encoded. If the position of the next tag is known, - 'offset to next tag' may be used. The offset is calculated from the - end of tag in which this frame resides to the first byte of the header - in the next. This field may be omitted. Embedded tags is currently not - recommended since this could render unpredictable behaviour from - present software/hardware. The 'Buffer size' should be kept to a - minimum. There may only be one "BUF" frame in each tag. - - Recommended buffer size "BUF" - Frame size $xx xx xx - Buffer size $xx xx xx - Embedded info flag %0000000x - Offset to next tag $xx xx xx xx - - -4.20. Encrypted meta frame - - This frame contains one or more encrypted frames. This enables - protection of copyrighted information such as pictures and text, that - people might want to pay extra for. Since standardisation of such an - encryption scheme is beyond this document, all "CRM" frames begin with - a terminated string with a URL [URL] containing an email address, or a - link to a location where an email adress can be found, that belongs to - the organisation responsible for this specific encrypted meta frame. - - Questions regarding the encrypted frame should be sent to the - indicated email address. If a $00 is found directly after the 'Frame - size', the whole frame should be ignored, and preferably be removed. - The 'Owner identifier' is then followed by a short content description - and explanation as to why it's encrypted. After the - 'content/explanation' description, the actual encrypted block follows. - - When an ID3v2 decoder encounters a "CRM" frame, it should send the - datablock to the 'plugin' with the corresponding 'owner identifier' - and expect to receive either a datablock with one or several ID3v2 - frames after each other or an error. There may be more than one "CRM" - frames in a tag, but only one with the same 'owner identifier'. - - Encrypted meta frame "CRM" - Frame size $xx xx xx - Owner identifier <textstring> $00 (00) - Content/explanation <textstring> $00 (00) - Encrypted datablock <binary data> - - -4.21. Audio encryption - - This frame indicates if the actual audio stream is encrypted, and by - whom. Since standardisation of such encrypion scheme is beyond this - document, all "CRA" frames begin with a terminated string with a - URL containing an email address, or a link to a location where an - email address can be found, that belongs to the organisation - responsible for this specific encrypted audio file. Questions - regarding the encrypted audio should be sent to the email address - specified. If a $00 is found directly after the 'Frame size' and the - audiofile indeed is encrypted, the whole file may be considered - useless. - - After the 'Owner identifier', a pointer to an unencrypted part of the - audio can be specified. The 'Preview start' and 'Preview length' is - described in frames. If no part is unencrypted, these fields should be - left zeroed. After the 'preview length' field follows optionally a - datablock required for decryption of the audio. There may be more than - one "CRA" frames in a tag, but only one with the same 'Owner - identifier'. - - Audio encryption "CRA" - Frame size $xx xx xx - Owner identifier <textstring> $00 (00) - Preview start $xx xx - Preview length $xx xx - Encryption info <binary data> - - -4.22. Linked information - - To keep space waste as low as possible this frame may be used to link - information from another ID3v2 tag that might reside in another audio - file or alone in a binary file. It is recommended that this method is - only used when the files are stored on a CD-ROM or other circumstances - when the risk of file seperation is low. The frame contains a frame - identifier, which is the frame that should be linked into this tag, a - URL [URL] field, where a reference to the file where the frame is - given, and additional ID data, if needed. Data should be retrieved - from the first tag found in the file to which this link points. There - may be more than one "LNK" frame in a tag, but only one with the same - contents. A linked frame is to be considered as part of the tag and - has the same restrictions as if it was a physical part of the tag - (i.e. only one "REV" frame allowed, whether it's linked or not). - - Linked information "LNK" - Frame size $xx xx xx - Frame identifier $xx xx xx - URL <textstring> $00 (00) - Additional ID data <textstring(s)> - - Frames that may be linked and need no additional data are "IPL", - "MCI", "ETC", "LLT", "STC", "RVA", "EQU", "REV", "BUF", the text - information frames and the URL link frames. - - The "TXX", "PIC", "GEO", "CRM" and "CRA" frames may be linked with the - content descriptor as additional ID data. - - The "COM", "SLT" and "ULT" frames may be linked with three bytes of - language descriptor directly followed by a content descriptor as - additional ID data. - - -5. The 'unsynchronisation scheme' - - The only purpose of the 'unsychronisation scheme' is to make the ID3v2 - tag as compatible as possible with existing software. There is no use - in 'unsynchronising' tags if the file is only to be processed by new - software. Unsynchronisation may only be made with MPEG 2 layer I, II - and III and MPEG 2.5 files. - - Whenever a false synchronisation is found within the tag, one zeroed - byte is inserted after the first false synchronisation byte. The - format of a correct sync that should be altered by ID3 encoders is as - follows: - - %11111111 111xxxxx - - And should be replaced with: - - %11111111 00000000 111xxxxx - - This has the side effect that all $FF 00 combinations have to be - altered, so they won't be affected by the decoding process. Therefore - all the $FF 00 combinations have to be replaced with the $FF 00 00 - combination during the unsynchonisation. - - To indicate usage of the unsynchronisation, the first bit in 'ID3 - flags' should be set. This bit should only be set if the tag - contained a, now corrected, false synchronisation. The bit should - only be clear if the tag does not contain any false synchronisations. - - Do bear in mind, that if a compression scheme is used by the encoder, - the unsyncronisation scheme should be applied *afterwards*. When - decoding a compressed, 'unsyncronised' file, the 'unsyncronisation - scheme' should be parsed first, compression afterwards. - - -6. Copyright - - Copyright (C) Martin Nilsson 1998. All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that a reference to this document is included on all - such copies and derivative works. However, this document itself may - not be modified in any way and reissued as the original document. - - The limited permissions granted above are perpetual and will not be - revoked. - - This document and the information contained herein is provided on an - "AS IS" basis and THE AUTHORS DISCLAIMS ALL WARRANTIES, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE - INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED - WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - - -7. References - - [CDDB] Compact Disc Data Base - - <url:http://www.cddb.com> - - [ISO-639-2] ISO/FDIS 639-2. - Codes for the representation of names of languages, Part 2: Alpha-3 - code. Technical committee / subcommittee: TC 37 / SC 2 - - [ISO-8859-1] ISO/IEC DIS 8859-1. - 8-bit single-byte coded graphic character sets, Part 1: Latin - alphabet No. 1. Technical committee / subcommittee: JTC 1 / SC 2 - - [ISRC] ISO 3901:1986 - International Standard Recording Code (ISRC). - Technical committee / subcommittee: TC 46 / SC 9 - - [JFIF] JPEG File Interchange Format, version 1.02 - - <url:http://www.w3.org/Graphics/JPEG/jfif.txt> - - [MIME] Freed, N. and N. Borenstein, "Multipurpose Internet Mail - Extensions (MIME) Part One: Format of Internet Message Bodies", - RFC 2045, November 1996. - - <url:ftp://ftp.isi.edu/in-notes/rfc2045.txt> - - [MPEG] ISO/IEC 11172-3:1993. - Coding of moving pictures and associated audio for digital storage - media at up to about 1,5 Mbit/s, Part 3: Audio. - Technical committee / subcommittee: JTC 1 / SC 29 - and - ISO/IEC 13818-3:1995 - Generic coding of moving pictures and associated audio information, - Part 3: Audio. - Technical committee / subcommittee: JTC 1 / SC 29 - and - ISO/IEC DIS 13818-3 - Generic coding of moving pictures and associated audio information, - Part 3: Audio (Revision of ISO/IEC 13818-3:1995) - - - [PNG] Portable Network Graphics, version 1.0 - - <url:http://www.w3.org/TR/REC-png-multi.html> - - [UNICODE] ISO/IEC 10646-1:1993. - Universal Multiple-Octet Coded Character Set (UCS), Part 1: - Architecture and Basic Multilingual Plane. Technical committee - / subcommittee: JTC 1 / SC 2 - - <url:http://www.unicode.org> - - [URL] T. Berners-Lee, L. Masinter & M. McCahill, "Uniform Resource - Locators (URL).", RFC 1738, December 1994. - - <url:ftp://ftp.isi.edu/in-notes/rfc1738.txt> - - -8. Appendix - - -A. Appendix A - ID3-Tag Specification V1.1 - - ID3-Tag Specification V1.1 (12 dec 1997) by Michael Mutschler - <amiga2@info2.rus.uni-stuttgart.de>, edited for space and clarity - reasons. - - -A.1. Overview - - The ID3-Tag is an information field for MPEG Layer 3 audio files. - Since a standalone MP3 doesn't provide a method of storing other - information than those directly needed for replay reasons, the - ID3-tag was invented by Eric Kemp in 1996. - - A revision from ID3v1 to ID3v1.1 was made by Michael Mutschler to - support track number information is described in A.4. - - -A.2. ID3v1 Implementation - - The Information is stored in the last 128 bytes of an MP3. The Tag - has got the following fields, and the offsets given here, are from - 0-127. - - Field Length Offsets - Tag 3 0-2 - Songname 30 3-32 - Artist 30 33-62 - Album 30 63-92 - Year 4 93-96 - Comment 30 97-126 - Genre 1 127 - - - The string-fields contain ASCII-data, coded in ISO-Latin 1 codepage. - Strings which are smaller than the field length are padded with zero- - bytes. - - Tag: The tag is valid if this field contains the string "TAG". This - has to be uppercase! - - Songname: This field contains the title of the MP3 (string as - above). - - Artist: This field contains the artist of the MP3 (string as above). - - Album: this field contains the album where the MP3 comes from - (string as above). - - Year: this field contains the year when this song has originally - been released (string as above). - - Comment: this field contains a comment for the MP3 (string as - above). Revision to this field has been made in ID3v1.1. See - A.4. - - Genre: this byte contains the offset of a genre in a predefined - list the byte is treated as an unsigned byte. The offset is - starting from 0. See A.3. - - -A.3. Genre List - - The following genres is defined in ID3v1 - - 0.Blues - 1.Classic Rock - 2.Country - 3.Dance - 4.Disco - 5.Funk - 6.Grunge - 7.Hip-Hop - 8.Jazz - 9.Metal - 10.New Age - 11.Oldies - 12.Other - 13.Pop - 14.R&B - 15.Rap - 16.Reggae - 17.Rock - 18.Techno - 19.Industrial - 20.Alternative - 21.Ska - 22.Death Metal - 23.Pranks - 24.Soundtrack - 25.Euro-Techno - 26.Ambient - 27.Trip-Hop - 28.Vocal - 29.Jazz+Funk - 30.Fusion - 31.Trance - 32.Classical - 33.Instrumental - 34.Acid - 35.House - 36.Game - 37.Sound Clip - 38.Gospel - 39.Noise - 40.AlternRock - 41.Bass - 42.Soul - 43.Punk - 44.Space - 45.Meditative - 46.Instrumental Pop - 47.Instrumental Rock - 48.Ethnic - 49.Gothic - 50.Darkwave - 51.Techno-Industrial - 52.Electronic - 53.Pop-Folk - 54.Eurodance - 55.Dream - 56.Southern Rock - 57.Comedy - 58.Cult - 59.Gangsta - 60.Top 40 - 61.Christian Rap - 62.Pop/Funk - 63.Jungle - 64.Native American - 65.Cabaret - 66.New Wave - 67.Psychadelic - 68.Rave - 69.Showtunes - 70.Trailer - 71.Lo-Fi - 72.Tribal - 73.Acid Punk - 74.Acid Jazz - 75.Polka - 76.Retro - 77.Musical - 78.Rock & Roll - 79.Hard Rock - - The following genres are Winamp extensions - - 80.Folk - 81.Folk-Rock - 82.National Folk - 83.Swing - 84.Fast Fusion - 85.Bebob - 86.Latin - 87.Revival - 88.Celtic - 89.Bluegrass - 90.Avantgarde - 91.Gothic Rock - 92.Progressive Rock - 93.Psychedelic Rock - 94.Symphonic Rock - 95.Slow Rock - 96.Big Band - 97.Chorus - 98.Easy Listening - 99.Acoustic - 100.Humour - 101.Speech - 102.Chanson - 103.Opera - 104.Chamber Music - 105.Sonata - 106.Symphony - 107.Booty Bass - 108.Primus - 109.Porn Groove - 110.Satire - 111.Slow Jam - 112.Club - 113.Tango - 114.Samba - 115.Folklore - 116.Ballad - 117.Power Ballad - 118.Rhythmic Soul - 119.Freestyle - 120.Duet - 121.Punk Rock - 122.Drum Solo - 123.A capella - 124.Euro-House - 125.Dance Hall - - -A.4. Track addition - ID3v1.1 - - In ID3v1.1, Michael Mutschler revised the specification of the - comment field in order to implement the track number. The new format - of the comment field is a 28 character string followed by a mandatory - null ($00) character and the original album tracknumber stored as an - unsigned byte-size integer. In such cases where the 29th byte is not - the null character or when the 30th is a null character, the - tracknumber is to be considered undefined. - - -9. Author's Address - - Martin Nilsson - Rydsvägen 246 C. 30 - S-584 34 Linköping - Sweden - - Email: nilsson@id3.org - - Co-authors: - - Johan Sundström Email: johan@id3.org - - diff --git a/taglib/taglib/mpeg/id3v2/id3v2.3.0.txt b/taglib/taglib/mpeg/id3v2/id3v2.3.0.txt deleted file mode 100644 index b4ed763..0000000 --- a/taglib/taglib/mpeg/id3v2/id3v2.3.0.txt +++ /dev/null @@ -1,2022 +0,0 @@ -Informal standard M. Nilsson -Document: id3v2.3.0.txt 3rd February 1999 - - - ID3 tag version 2.3.0 - -Status of this document - - This document is an informal standard and replaces the ID3v2.2.0 - standard [ID3v2]. The informal standard is released so that - implementors could have a set standard before a formal standard is - set. The formal standard will use another version or revision number - if not identical to what is described in this document. The contents - in this document may change for clarifications but never for added or - altered functionallity. - - Distribution of this document is unlimited. - - -Abstract - - This document describes the ID3v2.3.0, which is a more developed - version of the ID3v2 informal standard [ID3v2] (version 2.2.0), - evolved from the ID3 tagging system. The ID3v2 offers a flexible way - of storing information about an audio file within itself to determine - its origin and contents. The information may be technical - information, such as equalisation curves, as well as related meta - information, such as title, performer, copyright etc. - - -1. Table of contents - - 2. Conventions in this document - 3. ID3v2 overview - 3.1. ID3v2 header - 3.2. ID3v2 extended header - 3.3. ID3v2 frames overview - 3.3.1. Frame header flags - 3.3.2. Default flags - 4. Declared ID3v2 frames - 4.1. Unique file identifier - 4.2. Text information frames - 4.2.1. Text information frames - details - 4.2.2. User defined text information frame - 4.3. URL link frames - 4.3.1. URL link frames - details - 4.3.2. User defined URL link frame - 4.4. Involved people list - 4.5. Music CD Identifier - 4.6. Event timing codes - 4.7. MPEG location lookup table - 4.8. Synced tempo codes - 4.9. Unsychronised lyrics/text transcription - 4.10. Synchronised lyrics/text - 4.11. Comments - 4.12. Relative volume adjustment - 4.13. Equalisation - 4.14. Reverb - 4.15. Attached picture - 4.16. General encapsulated object - 4.17. Play counter - 4.18. Popularimeter - 4.19. Recommended buffer size - 4.20. Audio encryption - 4.21. Linked information - 4.22. Position synchronisation frame - 4.23. Terms of use - 4.24. Ownership frame - 4.25. Commercial frame - 4.26. Encryption method registration - 4.27. Group identification registration - 4.28. Private frame - 5. The 'unsynchronisation scheme' - 6. Copyright - 7. References - 8. Appendix - A. Appendix A - Genre List from ID3v1 - 9. Author's Address - - -2. Conventions in this document - - In the examples, text within "" is a text string exactly as it - appears in a file. Numbers preceded with $ are hexadecimal and - numbers preceded with % are binary. $xx is used to indicate a byte - with unknown content. %x is used to indicate a bit with unknown - content. The most significant bit (MSB) of a byte is called 'bit 7' - and the least significant bit (LSB) is called 'bit 0'. - - A tag is the whole tag described in this document. A frame is a block - of information in the tag. The tag consists of a header, frames and - optional padding. A field is a piece of information; one value, a - string etc. A numeric string is a string that consists of the - characters 0-9 only. - - -3. ID3v2 overview - - The two biggest design goals were to be able to implement ID3v2 - without disturbing old software too much and that ID3v2 should be - as flexible and expandable as possible. - - The first criterion is met by the simple fact that the MPEG [MPEG] - decoding software uses a syncsignal, embedded in the audiostream, to - 'lock on to' the audio. Since the ID3v2 tag doesn't contain a valid - syncsignal, no software will attempt to play the tag. If, for any - reason, coincidence make a syncsignal appear within the tag it will - be taken care of by the 'unsynchronisation scheme' described in - section 5. - - The second criterion has made a more noticeable impact on the design - of the ID3v2 tag. It is constructed as a container for several - information blocks, called frames, whose format need not be known to - the software that encounters them. At the start of every frame there - is an identifier that explains the frames' format and content, and a - size descriptor that allows software to skip unknown frames. - - If a total revision of the ID3v2 tag should be needed, there is a - version number and a size descriptor in the ID3v2 header. - - The ID3 tag described in this document is mainly targeted at files - encoded with MPEG-1/2 layer I, MPEG-1/2 layer II, MPEG-1/2 layer III - and MPEG-2.5, but may work with other types of encoded audio. - - The bitorder in ID3v2 is most significant bit first (MSB). The - byteorder in multibyte numbers is most significant byte first (e.g. - $12345678 would be encoded $12 34 56 78). - - It is permitted to include padding after all the final frame (at the - end of the ID3 tag), making the size of all the frames together - smaller than the size given in the head of the tag. A possible - purpose of this padding is to allow for adding a few additional - frames or enlarge existing frames within the tag without having to - rewrite the entire file. The value of the padding bytes must be $00. - - -3.1. ID3v2 header - - The ID3v2 tag header, which should be the first information in the - file, is 10 bytes as follows: - - ID3v2/file identifier "ID3" - ID3v2 version $03 00 - ID3v2 flags %abc00000 - ID3v2 size 4 * %0xxxxxxx - - The first three bytes of the tag are always "ID3" to indicate that - this is an ID3v2 tag, directly followed by the two version bytes. The - first byte of ID3v2 version is it's major version, while the second - byte is its revision number. In this case this is ID3v2.3.0. All - revisions are backwards compatible while major versions are not. If - software with ID3v2.2.0 and below support should encounter version - three or higher it should simply ignore the whole tag. Version and - revision will never be $FF. - - The version is followed by one the ID3v2 flags field, of which - currently only three flags are used. - - - a - Unsynchronisation - - Bit 7 in the 'ID3v2 flags' indicates whether or not - unsynchronisation is used (see section 5 for details); a set bit - indicates usage. - - - b - Extended header - - The second bit (bit 6) indicates whether or not the header is - followed by an extended header. The extended header is described in - section 3.2. - - - c - Experimental indicator - - The third bit (bit 5) should be used as an 'experimental - indicator'. This flag should always be set when the tag is in an - experimental stage. - - All the other flags should be cleared. If one of these undefined - flags are set that might mean that the tag is not readable for a - parser that does not know the flags function. - - The ID3v2 tag size is encoded with four bytes where the most - significant bit (bit 7) is set to zero in every byte, making a total - of 28 bits. The zeroed bits are ignored, so a 257 bytes long tag is - represented as $00 00 02 01. - - The ID3v2 tag size is the size of the complete tag after - unsychronisation, including padding, excluding the header but not - excluding the extended header (total tag size - 10). Only 28 bits - (representing up to 256MB) are used in the size description to avoid - the introducuction of 'false syncsignals'. - - An ID3v2 tag can be detected with the following pattern: - $49 44 33 yy yy xx zz zz zz zz - Where yy is less than $FF, xx is the 'flags' byte and zz is less than - $80. - - -3.2. ID3v2 extended header - - The extended header contains information that is not vital to the - correct parsing of the tag information, hence the extended header is - optional. - - Extended header size $xx xx xx xx - Extended Flags $xx xx - Size of padding $xx xx xx xx - - Where the 'Extended header size', currently 6 or 10 bytes, excludes - itself. The 'Size of padding' is simply the total tag size excluding - the frames and the headers, in other words the padding. The extended - header is considered separate from the header proper, and as such is - subject to unsynchronisation. - - The extended flags are a secondary flag set which describes further - attributes of the tag. These attributes are currently defined as - follows - - %x0000000 00000000 - - - x - CRC data present - - If this flag is set four bytes of CRC-32 data is appended to the - extended header. The CRC should be calculated before - unsynchronisation on the data between the extended header and the - padding, i.e. the frames and only the frames. - - Total frame CRC $xx xx xx xx - - -3.3. ID3v2 frame overview - - As the tag consists of a tag header and a tag body with one or more - frames, all the frames consists of a frame header followed by one or - more fields containing the actual information. The layout of the - frame header: - - Frame ID $xx xx xx xx (four characters) - Size $xx xx xx xx - Flags $xx xx - - The frame ID made out of the characters capital A-Z and 0-9. - Identifiers beginning with "X", "Y" and "Z" are for experimental use - and free for everyone to use, without the need to set the - experimental bit in the tag header. Have in mind that someone else - might have used the same identifier as you. All other identifiers are - either used or reserved for future use. - - The frame ID is followed by a size descriptor, making a total header - size of ten bytes in every frame. The size is calculated as frame - size excluding frame header (frame size - 10). - - In the frame header the size descriptor is followed by two flags - bytes. These flags are described in section 3.3.1. - - There is no fixed order of the frames' appearance in the tag, - although it is desired that the frames are arranged in order of - significance concerning the recognition of the file. An example of - such order: UFID, TIT2, MCDI, TRCK ... - - A tag must contain at least one frame. A frame must be at least 1 - byte big, excluding the header. - - If nothing else is said a string is represented as ISO-8859-1 - [ISO-8859-1] characters in the range $20 - $FF. Such strings are - represented as <text string>, or <full text string> if newlines are - allowed, in the frame descriptions. All Unicode strings [UNICODE] use - 16-bit unicode 2.0 (ISO/IEC 10646-1:1993, UCS-2). Unicode strings - must begin with the Unicode BOM ($FF FE or $FE FF) to identify the - byte order. - - All numeric strings and URLs [URL] are always encoded as ISO-8859-1. - Terminated strings are terminated with $00 if encoded with ISO-8859-1 - and $00 00 if encoded as unicode. If nothing else is said newline - character is forbidden. In ISO-8859-1 a new line is represented, when - allowed, with $0A only. Frames that allow different types of text - encoding have a text encoding description byte directly after the - frame size. If ISO-8859-1 is used this byte should be $00, if Unicode - is used it should be $01. Strings dependent on encoding is - represented as <text string according to encoding>, or <full text - string according to encoding> if newlines are allowed. Any empty - Unicode strings which are NULL-terminated may have the Unicode BOM - followed by a Unicode NULL ($FF FE 00 00 or $FE FF 00 00). - - The three byte language field is used to describe the language of the - frame's content, according to ISO-639-2 [ISO-639-2]. - - All URLs [URL] may be relative, e.g. "picture.png", "../doc.txt". - - If a frame is longer than it should be, e.g. having more fields than - specified in this document, that indicates that additions to the - frame have been made in a later version of the ID3v2 standard. This - is reflected by the revision number in the header of the tag. - - -3.3.1. Frame header flags - - In the frame header the size descriptor is followed by two flags - bytes. All unused flags must be cleared. The first byte is for - 'status messages' and the second byte is for encoding purposes. If an - unknown flag is set in the first byte the frame may not be changed - without the bit cleared. If an unknown flag is set in the second byte - it is likely to not be readable. The flags field is defined as - follows. - - %abc00000 %ijk00000 - - - a - Tag alter preservation - - This flag tells the software what to do with this frame if it is - unknown and the tag is altered in any way. This applies to all - kinds of alterations, including adding more padding and reordering - the frames. - - 0 Frame should be preserved. - 1 Frame should be discarded. - - - b - File alter preservation - - This flag tells the software what to do with this frame if it is - unknown and the file, excluding the tag, is altered. This does not - apply when the audio is completely replaced with other audio data. - - 0 Frame should be preserved. - 1 Frame should be discarded. - - - c - Read only - - This flag, if set, tells the software that the contents of this - frame is intended to be read only. Changing the contents might - break something, e.g. a signature. If the contents are changed, - without knowledge in why the frame was flagged read only and - without taking the proper means to compensate, e.g. recalculating - the signature, the bit should be cleared. - - - i - Compression - - This flag indicates whether or not the frame is compressed. - - 0 Frame is not compressed. - 1 Frame is compressed using zlib [zlib] with 4 bytes for - 'decompressed size' appended to the frame header. - - - j - Encryption - - This flag indicates wether or not the frame is enrypted. If set - one byte indicating with which method it was encrypted will be - appended to the frame header. See section 4.26. for more - information about encryption method registration. - - 0 Frame is not encrypted. - 1 Frame is encrypted. - - - k - Grouping identity - - This flag indicates whether or not this frame belongs in a group - with other frames. If set a group identifier byte is added to the - frame header. Every frame with the same group identifier belongs - to the same group. - - 0 Frame does not contain group information - 1 Frame contains group information - - - Some flags indicates that the frame header is extended with - additional information. This information will be added to the frame - header in the same order as the flags indicating the additions. I.e. - the four bytes of decompressed size will preceed the encryption - method byte. These additions to the frame header, while not included - in the frame header size but are included in the 'frame size' field, - are not subject to encryption or compression. - - -3.3.2. Default flags - - The default settings for the frames described in this document can be - divided into the following classes. The flags may be set differently - if found more suitable by the software. - - 1. Discarded if tag is altered, discarded if file is altered. - - None. - - 2. Discarded if tag is altered, preserved if file is altered. - - None. - - 3. Preserved if tag is altered, discarded if file is altered. - - AENC, ETCO, EQUA, MLLT, POSS, SYLT, SYTC, RVAD, TENC, TLEN, TSIZ - - 4. Preserved if tag is altered, preserved if file is altered. - - The rest of the frames. - - -4. Declared ID3v2 frames - - The following frames are declared in this draft. - - 4.21 AENC Audio encryption - 4.15 APIC Attached picture - - 4.11 COMM Comments - 4.25 COMR Commercial frame - - 4.26 ENCR Encryption method registration - 4.13 EQUA Equalization - 4.6 ETCO Event timing codes - - 4.16 GEOB General encapsulated object - 4.27 GRID Group identification registration - - 4.4 IPLS Involved people list - - 4.21 LINK Linked information - - 4.5 MCDI Music CD identifier - 4.7 MLLT MPEG location lookup table - - 4.24 OWNE Ownership frame - - 4.28. PRIV Private frame - 4.17 PCNT Play counter - 4.18 POPM Popularimeter - 4.22 POSS Position synchronisation frame - - 4.19 RBUF Recommended buffer size - 4.12 RVAD Relative volume adjustment - 4.14 RVRB Reverb - - 4.10 SYLT Synchronized lyric/text - 4.8 SYTC Synchronized tempo codes - - 4.2.1 TALB Album/Movie/Show title - 4.2.1 TBPM BPM (beats per minute) - 4.2.1 TCOM Composer - 4.2.1 TCON Content type - 4.2.1 TCOP Copyright message - 4.2.1 TDAT Date - 4.2.1 TDLY Playlist delay - 4.2.1 TENC Encoded by - 4.2.1 TEXT Lyricist/Text writer - 4.2.1 TFLT File type - 4.2.1 TIME Time - 4.2.1 TIT1 Content group description - 4.2.1 TIT2 Title/songname/content description - 4.2.1 TIT3 Subtitle/Description refinement - 4.2.1 TKEY Initial key - 4.2.1 TLAN Language(s) - 4.2.1 TLEN Length - 4.2.1 TMED Media type - 4.2.1 TOAL Original album/movie/show title - 4.2.1 TOFN Original filename - 4.2.1 TOLY Original lyricist(s)/text writer(s) - 4.2.1 TOPE Original artist(s)/performer(s) - 4.2.1 TORY Original release year - 4.2.1 TOWN File owner/licensee - 4.2.1 TPE1 Lead performer(s)/Soloist(s) - 4.2.1 TPE2 Band/orchestra/accompaniment - 4.2.1 TPE3 Conductor/performer refinement - 4.2.1 TPE4 Interpreted, remixed, or otherwise modified by - 4.2.1 TPOS Part of a set - 4.2.1 TPUB Publisher - 4.2.1 TRCK Track number/Position in set - 4.2.1 TRDA Recording dates - 4.2.1 TRSN Internet radio station name - 4.2.1 TRSO Internet radio station owner - 4.2.1 TSIZ Size - 4.2.1 TSRC ISRC (international standard recording code) - 4.2.1 TSSE Software/Hardware and settings used for encoding - 4.2.1 TYER Year - 4.2.2 TXXX User defined text information frame - - 4.1 UFID Unique file identifier - 4.23 USER Terms of use - 4.9 USLT Unsychronized lyric/text transcription - - 4.3.1 WCOM Commercial information - 4.3.1 WCOP Copyright/Legal information - 4.3.1 WOAF Official audio file webpage - 4.3.1 WOAR Official artist/performer webpage - 4.3.1 WOAS Official audio source webpage - 4.3.1 WORS Official internet radio station homepage - 4.3.1 WPAY Payment - 4.3.1 WPUB Publishers official webpage - 4.3.2 WXXX User defined URL link frame - - -4.1. Unique file identifier - - This frame's purpose is to be able to identify the audio file in a - database that may contain more information relevant to the content. - Since standardisation of such a database is beyond this document, all - frames begin with a null-terminated string with a URL [URL] - containing an email address, or a link to a location where an email - address can be found, that belongs to the organisation responsible - for this specific database implementation. Questions regarding the - database should be sent to the indicated email address. The URL - should not be used for the actual database queries. The string - "<a href="http://www.id3.org/dummy/ufid.html">http://www.id3.org/dummy/ufid.html</a>" should be used for tests. - Software that isn't told otherwise may safely remove such frames. The - 'Owner identifier' must be non-empty (more than just a termination). - The 'Owner identifier' is then followed by the actual identifier, - which may be up to 64 bytes. There may be more than one "UFID" frame - in a tag, but only one with the same 'Owner identifier'. - - <Header for 'Unique file identifier', ID: "UFID"> - Owner identifier <text string> $00 - Identifier <up to 64 bytes binary data> - - -4.2. Text information frames - - The text information frames are the most important frames, containing - information like artist, album and more. There may only be one text - information frame of its kind in an tag. If the textstring is - followed by a termination ($00 (00)) all the following information - should be ignored and not be displayed. All text frame identifiers - begin with "T". Only text frame identifiers begin with "T", with the - exception of the "TXXX" frame. All the text information frames have - the following format: - - <Header for 'Text information frame', ID: "T000" - "TZZZ", - excluding "TXXX" described in 4.2.2.> - Text encoding $xx - Information <text string according to encoding> - - -4.2.1. Text information frames - details - - TALB - The 'Album/Movie/Show title' frame is intended for the title of the - recording(/source of sound) which the audio in the file is taken - from. - - TBPM - The 'BPM' frame contains the number of beats per minute in the - mainpart of the audio. The BPM is an integer and represented as a - numerical string. - - TCOM - The 'Composer(s)' frame is intended for the name of the composer(s). - They are seperated with the "/" character. - - TCON - The 'Content type', which previously was stored as a one byte numeric - value only, is now a numeric string. You may use one or several of - the types as ID3v1.1 did or, since the category list would be - impossible to maintain with accurate and up to date categories, - define your own. - - References to the ID3v1 genres can be made by, as first byte, enter - "(" followed by a number from the genres list (appendix A.) and - ended with a ")" character. This is optionally followed by a - refinement, e.g. "(21)" or "(4)Eurodisco". Several references can be - made in the same frame, e.g. "(51)(39)". If the refinement should - begin with a "(" character it should be replaced with "((", e.g. "((I - can figure out any genre)" or "(55)((I think...)". The following new - content types is defined in ID3v2 and is implemented in the same way - as the numerig content types, e.g. "(RX)". - - RX Remix - CR Cover - - TCOP - The 'Copyright message' frame, which must begin with a year and a - space character (making five characters), is intended for the - copyright holder of the original sound, not the audio file itself. - The absence of this frame means only that the copyright information - is unavailable or has been removed, and must not be interpreted to - mean that the sound is public domain. Every time this field is - displayed the field must be preceded with "Copyright " (C) " ", where - (C) is one character showing a C in a circle. - - TDAT - The 'Date' frame is a numeric string in the DDMM format containing - the date for the recording. This field is always four characters - long. - - TDLY - The 'Playlist delay' defines the numbers of milliseconds of silence - between every song in a playlist. The player should use the "ETC" - frame, if present, to skip initial silence and silence at the end of - the audio to match the 'Playlist delay' time. The time is represented - as a numeric string. - - TENC - The 'Encoded by' frame contains the name of the person or - organisation that encoded the audio file. This field may contain a - copyright message, if the audio file also is copyrighted by the - encoder. - - TEXT - The 'Lyricist(s)/Text writer(s)' frame is intended for the writer(s) - of the text or lyrics in the recording. They are seperated with the - "/" character. - - TFLT - The 'File type' frame indicates which type of audio this tag defines. - The following type and refinements are defined: - - MPG MPEG Audio - /1 MPEG 1/2 layer I - /2 MPEG 1/2 layer II - /3 MPEG 1/2 layer III - /2.5 MPEG 2.5 - /AAC Advanced audio compression - VQF Transform-domain Weighted Interleave Vector Quantization - PCM Pulse Code Modulated audio - - but other types may be used, not for these types though. This is used - in a similar way to the predefined types in the "TMED" frame, but - without parentheses. If this frame is not present audio type is - assumed to be "MPG". - - TIME - The 'Time' frame is a numeric string in the HHMM format containing - the time for the recording. This field is always four characters - long. - - TIT1 - The 'Content group description' frame is used if the sound belongs to - a larger category of sounds/music. For example, classical music is - often sorted in different musical sections (e.g. "Piano Concerto", - "Weather - Hurricane"). - - TIT2 - The 'Title/Songname/Content description' frame is the actual name of - the piece (e.g. "Adagio", "Hurricane Donna"). - - TIT3 - The 'Subtitle/Description refinement' frame is used for information - directly related to the contents title (e.g. "Op. 16" or "Performed - live at Wembley"). - - TKEY - The 'Initial key' frame contains the musical key in which the sound - starts. It is represented as a string with a maximum length of three - characters. The ground keys are represented with "A","B","C","D","E", - "F" and "G" and halfkeys represented with "b" and "#". Minor is - represented as "m". Example "Cbm". Off key is represented with an "o" - only. - - TLAN - The 'Language(s)' frame should contain the languages of the text or - lyrics spoken or sung in the audio. The language is represented with - three characters according to ISO-639-2. If more than one language is - used in the text their language codes should follow according to - their usage. - - TLEN - The 'Length' frame contains the length of the audiofile in - milliseconds, represented as a numeric string. - - TMED - The 'Media type' frame describes from which media the sound - originated. This may be a text string or a reference to the - predefined media types found in the list below. References are made - within "(" and ")" and are optionally followed by a text refinement, - e.g. "(MC) with four channels". If a text refinement should begin - with a "(" character it should be replaced with "((" in the same way - as in the "TCO" frame. Predefined refinements is appended after the - media type, e.g. "(CD/A)" or "(VID/PAL/VHS)". - - DIG Other digital media - /A Analog transfer from media - - ANA Other analog media - /WAC Wax cylinder - /8CA 8-track tape cassette - - CD CD - /A Analog transfer from media - /DD DDD - /AD ADD - /AA AAD - - LD Laserdisc - /A Analog transfer from media - - TT Turntable records - /33 33.33 rpm - /45 45 rpm - /71 71.29 rpm - /76 76.59 rpm - /78 78.26 rpm - /80 80 rpm - - MD MiniDisc - /A Analog transfer from media - - DAT DAT - /A Analog transfer from media - /1 standard, 48 kHz/16 bits, linear - /2 mode 2, 32 kHz/16 bits, linear - /3 mode 3, 32 kHz/12 bits, nonlinear, low speed - /4 mode 4, 32 kHz/12 bits, 4 channels - /5 mode 5, 44.1 kHz/16 bits, linear - /6 mode 6, 44.1 kHz/16 bits, 'wide track' play - - DCC DCC - /A Analog transfer from media - - DVD DVD - /A Analog transfer from media - - TV Television - /PAL PAL - /NTSC NTSC - /SECAM SECAM - - VID Video - /PAL PAL - /NTSC NTSC - /SECAM SECAM - /VHS VHS - /SVHS S-VHS - /BETA BETAMAX - - RAD Radio - /FM FM - /AM AM - /LW LW - /MW MW - - TEL Telephone - /I ISDN - - MC MC (normal cassette) - /4 4.75 cm/s (normal speed for a two sided cassette) - /9 9.5 cm/s - /I Type I cassette (ferric/normal) - /II Type II cassette (chrome) - /III Type III cassette (ferric chrome) - /IV Type IV cassette (metal) - - REE Reel - /9 9.5 cm/s - /19 19 cm/s - /38 38 cm/s - /76 76 cm/s - /I Type I cassette (ferric/normal) - /II Type II cassette (chrome) - /III Type III cassette (ferric chrome) - /IV Type IV cassette (metal) - - TOAL - The 'Original album/movie/show title' frame is intended for the title - of the original recording (or source of sound), if for example the - music in the file should be a cover of a previously released song. - - TOFN - The 'Original filename' frame contains the preferred filename for the - file, since some media doesn't allow the desired length of the - filename. The filename is case sensitive and includes its suffix. - - TOLY - The 'Original lyricist(s)/text writer(s)' frame is intended for the - text writer(s) of the original recording, if for example the music in - the file should be a cover of a previously released song. The text - writers are seperated with the "/" character. - - TOPE - The 'Original artist(s)/performer(s)' frame is intended for the - performer(s) of the original recording, if for example the music in - the file should be a cover of a previously released song. The - performers are seperated with the "/" character. - - TORY - The 'Original release year' frame is intended for the year when the - original recording, if for example the music in the file should be a - cover of a previously released song, was released. The field is - formatted as in the "TYER" frame. - - TOWN - The 'File owner/licensee' frame contains the name of the owner or - licensee of the file and it's contents. - - TPE1 - The 'Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group' is - used for the main artist(s). They are seperated with the "/" - character. - - TPE2 - The 'Band/Orchestra/Accompaniment' frame is used for additional - information about the performers in the recording. - - TPE3 - The 'Conductor' frame is used for the name of the conductor. - - TPE4 - The 'Interpreted, remixed, or otherwise modified by' frame contains - more information about the people behind a remix and similar - interpretations of another existing piece. - - TPOS - The 'Part of a set' frame is a numeric string that describes which - part of a set the audio came from. This frame is used if the source - described in the "TALB" frame is divided into several mediums, e.g. a - double CD. The value may be extended with a "/" character and a - numeric string containing the total number of parts in the set. E.g. - "1/2". - - TPUB - The 'Publisher' frame simply contains the name of the label or - publisher. - - TRCK - The 'Track number/Position in set' frame is a numeric string - containing the order number of the audio-file on its original - recording. This may be extended with a "/" character and a numeric - string containing the total numer of tracks/elements on the original - recording. E.g. "4/9". - - TRDA - The 'Recording dates' frame is a intended to be used as complement to - the "TYER", "TDAT" and "TIME" frames. E.g. "4th-7th June, 12th June" - in combination with the "TYER" frame. - - TRSN - The 'Internet radio station name' frame contains the name of the - internet radio station from which the audio is streamed. - - TRSO - The 'Internet radio station owner' frame contains the name of the - owner of the internet radio station from which the audio is - streamed. - - TSIZ - The 'Size' frame contains the size of the audiofile in bytes, - excluding the ID3v2 tag, represented as a numeric string. - - TSRC - The 'ISRC' frame should contain the International Standard Recording - Code [ISRC] (12 characters). - - TSSE - The 'Software/Hardware and settings used for encoding' frame - includes the used audio encoder and its settings when the file was - encoded. Hardware refers to hardware encoders, not the computer on - which a program was run. - - TYER - The 'Year' frame is a numeric string with a year of the recording. - This frames is always four characters long (until the year 10000). - - -4.2.2. User defined text information frame - - This frame is intended for one-string text information concerning the - audiofile in a similar way to the other "T"-frames. The frame body - consists of a description of the string, represented as a terminated - string, followed by the actual string. There may be more than one - "TXXX" frame in each tag, but only one with the same description. - - <Header for 'User defined text information frame', ID: "TXXX"> - Text encoding $xx - Description <text string according to encoding> $00 (00) - Value <text string according to encoding> - - -4.3. URL link frames - - With these frames dynamic data such as webpages with touring - information, price information or plain ordinary news can be added to - the tag. There may only be one URL [URL] link frame of its kind in an - tag, except when stated otherwise in the frame description. If the - textstring is followed by a termination ($00 (00)) all the following - information should be ignored and not be displayed. All URL link - frame identifiers begins with "W". Only URL link frame identifiers - begins with "W". All URL link frames have the following format: - - <Header for 'URL link frame', ID: "W000" - "WZZZ", excluding "WXXX" - described in 4.3.2.> - URL <text string> - - -4.3.1. URL link frames - details - - WCOM - The 'Commercial information' frame is a URL pointing at a webpage - with information such as where the album can be bought. There may be - more than one "WCOM" frame in a tag, but not with the same content. - - WCOP - The 'Copyright/Legal information' frame is a URL pointing at a - webpage where the terms of use and ownership of the file is - described. - - WOAF - The 'Official audio file webpage' frame is a URL pointing at a file - specific webpage. - - WOAR - The 'Official artist/performer webpage' frame is a URL pointing at - the artists official webpage. There may be more than one "WOAR" frame - in a tag if the audio contains more than one performer, but not with - the same content. - - WOAS - The 'Official audio source webpage' frame is a URL pointing at the - official webpage for the source of the audio file, e.g. a movie. - - WORS - The 'Official internet radio station homepage' contains a URL - pointing at the homepage of the internet radio station. - - WPAY - The 'Payment' frame is a URL pointing at a webpage that will handle - the process of paying for this file. - - WPUB - The 'Publishers official webpage' frame is a URL pointing at the - official wepage for the publisher. - - -4.3.2. User defined URL link frame - - This frame is intended for URL [URL] links concerning the audiofile - in a similar way to the other "W"-frames. The frame body consists - of a description of the string, represented as a terminated string, - followed by the actual URL. The URL is always encoded with ISO-8859-1 - [ISO-8859-1]. There may be more than one "WXXX" frame in each tag, - but only one with the same description. - - <Header for 'User defined URL link frame', ID: "WXXX"> - Text encoding $xx - Description <text string according to encoding> $00 (00) - URL <text string> - - -4.4. Involved people list - - Since there might be a lot of people contributing to an audio file in - various ways, such as musicians and technicians, the 'Text - information frames' are often insufficient to list everyone involved - in a project. The 'Involved people list' is a frame containing the - names of those involved, and how they were involved. The body simply - contains a terminated string with the involvement directly followed - by a terminated string with the involvee followed by a new - involvement and so on. There may only be one "IPLS" frame in each - tag. - - <Header for 'Involved people list', ID: "IPLS"> - Text encoding $xx - People list strings <text strings according to encoding> - - -4.5. Music CD identifier - - This frame is intended for music that comes from a CD, so that the CD - can be identified in databases such as the CDDB [CDDB]. The frame - consists of a binary dump of the Table Of Contents, TOC, from the CD, - which is a header of 4 bytes and then 8 bytes/track on the CD plus 8 - bytes for the 'lead out' making a maximum of 804 bytes. The offset to - the beginning of every track on the CD should be described with a - four bytes absolute CD-frame address per track, and not with absolute - time. This frame requires a present and valid "TRCK" frame, even if - the CD's only got one track. There may only be one "MCDI" frame in - each tag. - - <Header for 'Music CD identifier', ID: "MCDI"> - CD TOC <binary data> - - -4.6. Event timing codes - - This frame allows synchronisation with key events in a song or sound. - The header is: - - <Header for 'Event timing codes', ID: "ETCO"> - Time stamp format $xx - - Where time stamp format is: - - $01 Absolute time, 32 bit sized, using MPEG [MPEG] frames as unit - $02 Absolute time, 32 bit sized, using milliseconds as unit - - Abolute time means that every stamp contains the time from the - beginning of the file. - - Followed by a list of key events in the following format: - - Type of event $xx - Time stamp $xx (xx ...) - - The 'Time stamp' is set to zero if directly at the beginning of the - sound or after the previous event. All events should be sorted in - chronological order. The type of event is as follows: - - $00 padding (has no meaning) - $01 end of initial silence - $02 intro start - $03 mainpart start - $04 outro start - $05 outro end - $06 verse start - $07 refrain start - $08 interlude start - $09 theme start - $0A variation start - $0B key change - $0C time change - $0D momentary unwanted noise (Snap, Crackle & Pop) - $0E sustained noise - $0F sustained noise end - $10 intro end - $11 mainpart end - $12 verse end - $13 refrain end - $14 theme end - - $15-$DF reserved for future use - - $E0-$EF not predefined sync 0-F - - $F0-$FC reserved for future use - - $FD audio end (start of silence) - $FE audio file ends - $FF one more byte of events follows (all the following bytes with - the value $FF have the same function) - - Terminating the start events such as "intro start" is not required. - The 'Not predefined sync's ($E0-EF) are for user events. You might - want to synchronise your music to something, like setting of an - explosion on-stage, turning on your screensaver etc. - - There may only be one "ETCO" frame in each tag. - - -4.7. MPEG location lookup table - - To increase performance and accuracy of jumps within a MPEG [MPEG] - audio file, frames with timecodes in different locations in the file - might be useful. The ID3v2 frame includes references that the - software can use to calculate positions in the file. After the frame - header is a descriptor of how much the 'frame counter' should - increase for every reference. If this value is two then the first - reference points out the second frame, the 2nd reference the 4th - frame, the 3rd reference the 6th frame etc. In a similar way the - 'bytes between reference' and 'milliseconds between reference' points - out bytes and milliseconds respectively. - - Each reference consists of two parts; a certain number of bits, as - defined in 'bits for bytes deviation', that describes the difference - between what is said in 'bytes between reference' and the reality and - a certain number of bits, as defined in 'bits for milliseconds - deviation', that describes the difference between what is said in - 'milliseconds between reference' and the reality. The number of bits - in every reference, i.e. 'bits for bytes deviation'+'bits for - milliseconds deviation', must be a multiple of four. There may only - be one "MLLT" frame in each tag. - - <Header for 'Location lookup table', ID: "MLLT"> - MPEG frames between reference $xx xx - Bytes between reference $xx xx xx - Milliseconds between reference $xx xx xx - Bits for bytes deviation $xx - Bits for milliseconds dev. $xx - - Then for every reference the following data is included; - - Deviation in bytes %xxx.... - Deviation in milliseconds %xxx.... - - -4.8. Synchronised tempo codes - - For a more accurate description of the tempo of a musical piece this - frame might be used. After the header follows one byte describing - which time stamp format should be used. Then follows one or more - tempo codes. Each tempo code consists of one tempo part and one time - part. The tempo is in BPM described with one or two bytes. If the - first byte has the value $FF, one more byte follows, which is added - to the first giving a range from 2 - 510 BPM, since $00 and $01 is - reserved. $00 is used to describe a beat-free time period, which is - not the same as a music-free time period. $01 is used to indicate one - single beat-stroke followed by a beat-free period. - - The tempo descriptor is followed by a time stamp. Every time the - tempo in the music changes, a tempo descriptor may indicate this for - the player. All tempo descriptors should be sorted in chronological - order. The first beat-stroke in a time-period is at the same time as - the beat description occurs. There may only be one "SYTC" frame in - each tag. - - <Header for 'Synchronised tempo codes', ID: "SYTC"> - Time stamp format $xx - Tempo data <binary data> - - Where time stamp format is: - - $01 Absolute time, 32 bit sized, using MPEG [MPEG] frames as unit - $02 Absolute time, 32 bit sized, using milliseconds as unit - - Abolute time means that every stamp contains the time from the - beginning of the file. - - -4.9. Unsychronised lyrics/text transcription - - This frame contains the lyrics of the song or a text transcription of - other vocal activities. The head includes an encoding descriptor and - a content descriptor. The body consists of the actual text. The - 'Content descriptor' is a terminated string. If no descriptor is - entered, 'Content descriptor' is $00 (00) only. Newline characters - are allowed in the text. There may be more than one 'Unsynchronised - lyrics/text transcription' frame in each tag, but only one with the - same language and content descriptor. - - <Header for 'Unsynchronised lyrics/text transcription', ID: "USLT"> - Text encoding $xx - Language $xx xx xx - Content descriptor <text string according to encoding> $00 (00) - Lyrics/text <full text string according to encoding> - - -4.10. Synchronised lyrics/text - - This is another way of incorporating the words, said or sung lyrics, - in the audio file as text, this time, however, in sync with the - audio. It might also be used to describing events e.g. occurring on a - stage or on the screen in sync with the audio. The header includes a - content descriptor, represented with as terminated textstring. If no - descriptor is entered, 'Content descriptor' is $00 (00) only. - - <Header for 'Synchronised lyrics/text', ID: "SYLT"> - Text encoding $xx - Language $xx xx xx - Time stamp format $xx - Content type $xx - Content descriptor <text string according to encoding> $00 (00) - - - Encoding: $00 ISO-8859-1 [ISO-8859-1] character set is used => $00 - is sync identifier. - $01 Unicode [UNICODE] character set is used => $00 00 is - sync identifier. - - Content type: $00 is other - $01 is lyrics - $02 is text transcription - $03 is movement/part name (e.g. "Adagio") - $04 is events (e.g. "Don Quijote enters the stage") - $05 is chord (e.g. "Bb F Fsus") - $06 is trivia/'pop up' information - - Time stamp format is: - - $01 Absolute time, 32 bit sized, using MPEG [MPEG] frames as unit - $02 Absolute time, 32 bit sized, using milliseconds as unit - - Abolute time means that every stamp contains the time from the - beginning of the file. - - The text that follows the frame header differs from that of the - unsynchronised lyrics/text transcription in one major way. Each - syllable (or whatever size of text is considered to be convenient by - the encoder) is a null terminated string followed by a time stamp - denoting where in the sound file it belongs. Each sync thus has the - following structure: - - Terminated text to be synced (typically a syllable) - Sync identifier (terminator to above string) $00 (00) - Time stamp $xx (xx ...) - - The 'time stamp' is set to zero or the whole sync is omitted if - located directly at the beginning of the sound. All time stamps - should be sorted in chronological order. The sync can be considered - as a validator of the subsequent string. - - Newline ($0A) characters are allowed in all "SYLT" frames and should - be used after every entry (name, event etc.) in a frame with the - content type $03 - $04. - - A few considerations regarding whitespace characters: Whitespace - separating words should mark the beginning of a new word, thus - occurring in front of the first syllable of a new word. This is also - valid for new line characters. A syllable followed by a comma should - not be broken apart with a sync (both the syllable and the comma - should be before the sync). - - An example: The "USLT" passage - - "Strangers in the night" $0A "Exchanging glances" - - would be "SYLT" encoded as: - - "Strang" $00 xx xx "ers" $00 xx xx " in" $00 xx xx " the" $00 xx xx - " night" $00 xx xx 0A "Ex" $00 xx xx "chang" $00 xx xx "ing" $00 xx - xx "glan" $00 xx xx "ces" $00 xx xx - - There may be more than one "SYLT" frame in each tag, but only one - with the same language and content descriptor. - - -4.11. Comments - - This frame is indended for any kind of full text information that - does not fit in any other frame. It consists of a frame header - followed by encoding, language and content descriptors and is ended - with the actual comment as a text string. Newline characters are - allowed in the comment text string. There may be more than one - comment frame in each tag, but only one with the same language and - content descriptor. - - <Header for 'Comment', ID: "COMM"> - Text encoding $xx - Language $xx xx xx - Short content descrip. <text string according to encoding> $00 (00) - The actual text <full text string according to encoding> - - -4.12. Relative volume adjustment - - This is a more subjective function than the previous ones. It allows - the user to say how much he wants to increase/decrease the volume on - each channel while the file is played. The purpose is to be able to - align all files to a reference volume, so that you don't have to - change the volume constantly. This frame may also be used to balance - adjust the audio. If the volume peak levels are known then this could - be described with the 'Peak volume right' and 'Peak volume left' - field. If Peakvolume is not known these fields could be left zeroed - or, if no other data follows, be completely omitted. There may only - be one "RVAD" frame in each tag. - - <Header for 'Relative volume adjustment', ID: "RVAD"> - Increment/decrement %00xxxxxx - Bits used for volume descr. $xx - Relative volume change, right $xx xx (xx ...) - Relative volume change, left $xx xx (xx ...) - Peak volume right $xx xx (xx ...) - Peak volume left $xx xx (xx ...) - - In the increment/decrement field bit 0 is used to indicate the right - channel and bit 1 is used to indicate the left channel. 1 is - increment and 0 is decrement. - - The 'bits used for volume description' field is normally $10 (16 - bits) for MPEG 2 layer I, II and III [MPEG] and MPEG 2.5. This value - may not be $00. The volume is always represented with whole bytes, - padded in the beginning (highest bits) when 'bits used for volume - description' is not a multiple of eight. - - This datablock is then optionally followed by a volume definition for - the left and right back channels. If this information is appended to - the frame the first two channels will be treated as front channels. - In the increment/decrement field bit 2 is used to indicate the right - back channel and bit 3 for the left back channel. - - Relative volume change, right back $xx xx (xx ...) - Relative volume change, left back $xx xx (xx ...) - Peak volume right back $xx xx (xx ...) - Peak volume left back $xx xx (xx ...) - - If the center channel adjustment is present the following is appended - to the existing frame, after the left and right back channels. The - center channel is represented by bit 4 in the increase/decrease - field. - - Relative volume change, center $xx xx (xx ...) - Peak volume center $xx xx (xx ...) - - If the bass channel adjustment is present the following is appended - to the existing frame, after the center channel. The bass channel is - represented by bit 5 in the increase/decrease field. - - Relative volume change, bass $xx xx (xx ...) - Peak volume bass $xx xx (xx ...) - - -4.13. Equalisation - - This is another subjective, alignment frame. It allows the user to - predefine an equalisation curve within the audio file. There may only - be one "EQUA" frame in each tag. - - <Header of 'Equalisation', ID: "EQUA"> - Adjustment bits $xx - - The 'adjustment bits' field defines the number of bits used for - representation of the adjustment. This is normally $10 (16 bits) for - MPEG 2 layer I, II and III [MPEG] and MPEG 2.5. This value may not be - $00. - - This is followed by 2 bytes + ('adjustment bits' rounded up to the - nearest byte) for every equalisation band in the following format, - giving a frequency range of 0 - 32767Hz: - - Increment/decrement %x (MSB of the Frequency) - Frequency (lower 15 bits) - Adjustment $xx (xx ...) - - The increment/decrement bit is 1 for increment and 0 for decrement. - The equalisation bands should be ordered increasingly with reference - to frequency. All frequencies don't have to be declared. The - equalisation curve in the reading software should be interpolated - between the values in this frame. Three equal adjustments for three - subsequent frequencies. A frequency should only be described once in - the frame. - - -4.14. Reverb - - Yet another subjective one. You may here adjust echoes of different - kinds. Reverb left/right is the delay between every bounce in ms. - Reverb bounces left/right is the number of bounces that should be - made. $FF equals an infinite number of bounces. Feedback is the - amount of volume that should be returned to the next echo bounce. $00 - is 0%, $FF is 100%. If this value were $7F, there would be 50% volume - reduction on the first bounce, 50% of that on the second and so on. - Left to left means the sound from the left bounce to be played in the - left speaker, while left to right means sound from the left bounce to - be played in the right speaker. - - 'Premix left to right' is the amount of left sound to be mixed in the - right before any reverb is applied, where $00 id 0% and $FF is 100%. - 'Premix right to left' does the same thing, but right to left. - Setting both premix to $FF would result in a mono output (if the - reverb is applied symmetric). There may only be one "RVRB" frame in - each tag. - - <Header for 'Reverb', ID: "RVRB"> - Reverb left (ms) $xx xx - Reverb right (ms) $xx xx - Reverb bounces, left $xx - Reverb bounces, right $xx - Reverb feedback, left to left $xx - Reverb feedback, left to right $xx - Reverb feedback, right to right $xx - Reverb feedback, right to left $xx - Premix left to right $xx - Premix right to left $xx - - -4.15. Attached picture - - This frame contains a picture directly related to the audio file. - Image format is the MIME type and subtype [MIME] for the image. In - the event that the MIME media type name is omitted, "image/" will be - implied. The "image/png" [PNG] or "image/jpeg" [JFIF] picture format - should be used when interoperability is wanted. Description is a - short description of the picture, represented as a terminated - textstring. The description has a maximum length of 64 characters, - but may be empty. There may be several pictures attached to one file, - each in their individual "APIC" frame, but only one with the same - content descriptor. There may only be one picture with the picture - type declared as picture type $01 and $02 respectively. There is the - possibility to put only a link to the image file by using the 'MIME - type' "-->" and having a complete URL [URL] instead of picture data. - The use of linked files should however be used sparingly since there - is the risk of separation of files. - - <Header for 'Attached picture', ID: "APIC"> - Text encoding $xx - MIME type <text string> $00 - Picture type $xx - Description <text string according to encoding> $00 (00) - Picture data <binary data> - - - Picture type: $00 Other - $01 32x32 pixels 'file icon' (PNG only) - $02 Other file icon - $03 Cover (front) - $04 Cover (back) - $05 Leaflet page - $06 Media (e.g. lable side of CD) - $07 Lead artist/lead performer/soloist - $08 Artist/performer - $09 Conductor - $0A Band/Orchestra - $0B Composer - $0C Lyricist/text writer - $0D Recording Location - $0E During recording - $0F During performance - $10 Movie/video screen capture - $11 A bright coloured fish - $12 Illustration - $13 Band/artist logotype - $14 Publisher/Studio logotype - - -4.16. General encapsulated object - - In this frame any type of file can be encapsulated. After the header, - 'Frame size' and 'Encoding' follows 'MIME type' [MIME] represented as - as a terminated string encoded with ISO 8859-1 [ISO-8859-1]. The - filename is case sensitive and is encoded as 'Encoding'. Then follows - a content description as terminated string, encoded as 'Encoding'. - The last thing in the frame is the actual object. The first two - strings may be omitted, leaving only their terminations. MIME type is - always an ISO-8859-1 text string. There may be more than one "GEOB" - frame in each tag, but only one with the same content descriptor. - - <Header for 'General encapsulated object', ID: "GEOB"> - Text encoding $xx - MIME type <text string> $00 - Filename <text string according to encoding> $00 (00) - Content description <text string according to encóding> $00 (00) - Encapsulated object <binary data> - - -4.17. Play counter - - This is simply a counter of the number of times a file has been - played. The value is increased by one every time the file begins to - play. There may only be one "PCNT" frame in each tag. When the - counter reaches all one's, one byte is inserted in front of the - counter thus making the counter eight bits bigger. The counter must - be at least 32-bits long to begin with. - - <Header for 'Play counter', ID: "PCNT"> - Counter $xx xx xx xx (xx ...) - - -4.18. Popularimeter - - The purpose of this frame is to specify how good an audio file is. - Many interesting applications could be found to this frame such as a - playlist that features better audiofiles more often than others or it - could be used to profile a person's taste and find other 'good' files - by comparing people's profiles. The frame is very simple. It contains - the email address to the user, one rating byte and a four byte play - counter, intended to be increased with one for every time the file is - played. The email is a terminated string. The rating is 1-255 where - 1 is worst and 255 is best. 0 is unknown. If no personal counter is - wanted it may be omitted. When the counter reaches all one's, one - byte is inserted in front of the counter thus making the counter - eight bits bigger in the same away as the play counter ("PCNT"). - There may be more than one "POPM" frame in each tag, but only one - with the same email address. - - <Header for 'Popularimeter', ID: "POPM"> - Email to user <text string> $00 - Rating $xx - Counter $xx xx xx xx (xx ...) - - -4.19. Recommended buffer size - - Sometimes the server from which a audio file is streamed is aware of - transmission or coding problems resulting in interruptions in the - audio stream. In these cases, the size of the buffer can be - recommended by the server using this frame. If the 'embedded info - flag' is true (1) then this indicates that an ID3 tag with the - maximum size described in 'Buffer size' may occur in the audiostream. - In such case the tag should reside between two MPEG [MPEG] frames, if - the audio is MPEG encoded. If the position of the next tag is known, - 'offset to next tag' may be used. The offset is calculated from the - end of tag in which this frame resides to the first byte of the - header in the next. This field may be omitted. Embedded tags are - generally not recommended since this could render unpredictable - behaviour from present software/hardware. - - For applications like streaming audio it might be an idea to embed - tags into the audio stream though. If the clients connects to - individual connections like HTTP and there is a possibility to begin - every transmission with a tag, then this tag should include a - 'recommended buffer size' frame. If the client is connected to a - arbitrary point in the stream, such as radio or multicast, then the - 'recommended buffer size' frame should be included in every tag. - Every tag that is picked up after the initial/first tag is to be - considered as an update of the previous one. E.g. if there is a - "TIT2" frame in the first received tag and one in the second tag, - then the first should be 'replaced' with the second. - - The 'Buffer size' should be kept to a minimum. There may only be one - "RBUF" frame in each tag. - - <Header for 'Recommended buffer size', ID: "RBUF"> - Buffer size $xx xx xx - Embedded info flag %0000000x - Offset to next tag $xx xx xx xx - - -4.20. Audio encryption - - This frame indicates if the actual audio stream is encrypted, and by - whom. Since standardisation of such encrypion scheme is beyond this - document, all "AENC" frames begin with a terminated string with a - URL containing an email address, or a link to a location where an - email address can be found, that belongs to the organisation - responsible for this specific encrypted audio file. Questions - regarding the encrypted audio should be sent to the email address - specified. If a $00 is found directly after the 'Frame size' and the - audiofile indeed is encrypted, the whole file may be considered - useless. - - After the 'Owner identifier', a pointer to an unencrypted part of the - audio can be specified. The 'Preview start' and 'Preview length' is - described in frames. If no part is unencrypted, these fields should - be left zeroed. After the 'preview length' field follows optionally a - datablock required for decryption of the audio. There may be more - than one "AENC" frames in a tag, but only one with the same 'Owner - identifier'. - - <Header for 'Audio encryption', ID: "AENC"> - Owner identifier <text string> $00 - Preview start $xx xx - Preview length $xx xx - Encryption info <binary data> - - -4.21. Linked information - - To keep space waste as low as possible this frame may be used to link - information from another ID3v2 tag that might reside in another audio - file or alone in a binary file. It is recommended that this method is - only used when the files are stored on a CD-ROM or other - circumstances when the risk of file seperation is low. The frame - contains a frame identifier, which is the frame that should be linked - into this tag, a URL [URL] field, where a reference to the file where - the frame is given, and additional ID data, if needed. Data should be - retrieved from the first tag found in the file to which this link - points. There may be more than one "LINK" frame in a tag, but only - one with the same contents. A linked frame is to be considered as - part of the tag and has the same restrictions as if it was a physical - part of the tag (i.e. only one "RVRB" frame allowed, whether it's - linked or not). - - <Header for 'Linked information', ID: "LINK"> - Frame identifier $xx xx xx - URL <text string> $00 - ID and additional data <text string(s)> - - Frames that may be linked and need no additional data are "IPLS", - "MCID", "ETCO", "MLLT", "SYTC", "RVAD", "EQUA", "RVRB", "RBUF", the - text information frames and the URL link frames. - - The "TXXX", "APIC", "GEOB" and "AENC" frames may be linked with - the content descriptor as additional ID data. - - The "COMM", "SYLT" and "USLT" frames may be linked with three bytes - of language descriptor directly followed by a content descriptor as - additional ID data. - - -4.22. Position synchronisation frame - - This frame delivers information to the listener of how far into the - audio stream he picked up; in effect, it states the time offset of - the first frame in the stream. The frame layout is: - - <Head for 'Position synchronisation', ID: "POSS"> - Time stamp format $xx - Position $xx (xx ...) - - Where time stamp format is: - - $01 Absolute time, 32 bit sized, using MPEG frames as unit - $02 Absolute time, 32 bit sized, using milliseconds as unit - - and position is where in the audio the listener starts to receive, - i.e. the beginning of the next frame. If this frame is used in the - beginning of a file the value is always 0. There may only be one - "POSS" frame in each tag. - - -4.23. Terms of use frame - - This frame contains a brief description of the terms of use and - ownership of the file. More detailed information concerning the legal - terms might be available through the "WCOP" frame. Newlines are - allowed in the text. There may only be one "USER" frame in a tag. - - <Header for 'Terms of use frame', ID: "USER"> - Text encoding $xx - Language $xx xx xx - The actual text <text string according to encoding> - - -4.24. Ownership frame - - The ownership frame might be used as a reminder of a made transaction - or, if signed, as proof. Note that the "USER" and "TOWN" frames are - good to use in conjunction with this one. The frame begins, after the - frame ID, size and encoding fields, with a 'price payed' field. The - first three characters of this field contains the currency used for - the transaction, encoded according to ISO 4217 [ISO-4217] alphabetic - currency code. Concatenated to this is the actual price payed, as a - numerical string using "." as the decimal separator. Next is an 8 - character date string (YYYYMMDD) followed by a string with the name - of the seller as the last field in the frame. There may only be one - "OWNE" frame in a tag. - - <Header for 'Ownership frame', ID: "OWNE"> - Text encoding $xx - Price payed <text string> $00 - Date of purch. <text string> - Seller <text string according to encoding> - - -4.25. Commercial frame - - This frame enables several competing offers in the same tag by - bundling all needed information. That makes this frame rather complex - but it's an easier solution than if one tries to achieve the same - result with several frames. The frame begins, after the frame ID, - size and encoding fields, with a price string field. A price is - constructed by one three character currency code, encoded according - to ISO 4217 [ISO-4217] alphabetic currency code, followed by a - numerical value where "." is used as decimal seperator. In the price - string several prices may be concatenated, seperated by a "/" - character, but there may only be one currency of each type. - - The price string is followed by an 8 character date string in the - format YYYYMMDD, describing for how long the price is valid. After - that is a contact URL, with which the user can contact the seller, - followed by a one byte 'received as' field. It describes how the - audio is delivered when bought according to the following list: - - $00 Other - $01 Standard CD album with other songs - $02 Compressed audio on CD - $03 File over the Internet - $04 Stream over the Internet - $05 As note sheets - $06 As note sheets in a book with other sheets - $07 Music on other media - $08 Non-musical merchandise - - Next follows a terminated string with the name of the seller followed - by a terminated string with a short description of the product. The - last thing is the ability to include a company logotype. The first of - them is the 'Picture MIME type' field containing information about - which picture format is used. In the event that the MIME media type - name is omitted, "image/" will be implied. Currently only "image/png" - and "image/jpeg" are allowed. This format string is followed by the - binary picture data. This two last fields may be omitted if no - picture is to attach. - - <Header for 'Commercial frame', ID: "COMR"> - Text encoding $xx - Price string <text string> $00 - Valid until <text string> - Contact URL <text string> $00 - Received as $xx - Name of seller <text string according to encoding> $00 (00) - Description <text string according to encoding> $00 (00) - Picture MIME type <string> $00 - Seller logo <binary data> - - -4.26. Encryption method registration - - To identify with which method a frame has been encrypted the - encryption method must be registered in the tag with this frame. The - 'Owner identifier' is a null-terminated string with a URL [URL] - containing an email address, or a link to a location where an email - address can be found, that belongs to the organisation responsible - for this specific encryption method. Questions regarding the - encryption method should be sent to the indicated email address. The - 'Method symbol' contains a value that is associated with this method - throughout the whole tag. Values below $80 are reserved. The 'Method - symbol' may optionally be followed by encryption specific data. There - may be several "ENCR" frames in a tag but only one containing the - same symbol and only one containing the same owner identifier. The - method must be used somewhere in the tag. See section 3.3.1, flag j - for more information. - - <Header for 'Encryption method registration', ID: "ENCR"> - Owner identifier <text string> $00 - Method symbol $xx - Encryption data <binary data> - - -4.27. Group identification registration - - This frame enables grouping of otherwise unrelated frames. This can - be used when some frames are to be signed. To identify which frames - belongs to a set of frames a group identifier must be registered in - the tag with this frame. The 'Owner identifier' is a null-terminated - string with a URL [URL] containing an email address, or a link to a - location where an email address can be found, that belongs to the - organisation responsible for this grouping. Questions regarding the - grouping should be sent to the indicated email address. The 'Group - symbol' contains a value that associates the frame with this group - throughout the whole tag. Values below $80 are reserved. The 'Group - symbol' may optionally be followed by some group specific data, e.g. - a digital signature. There may be several "GRID" frames in a tag but - only one containing the same symbol and only one containing the same - owner identifier. The group symbol must be used somewhere in the tag. - See section 3.3.1, flag j for more information. - - <Header for 'Group ID registration', ID: "GRID"> - Owner identifier <text string> $00 - Group symbol $xx - Group dependent data <binary data> - - -4.28. Private frame - - This frame is used to contain information from a software producer - that its program uses and does not fit into the other frames. The - frame consists of an 'Owner identifier' string and the binary data. - The 'Owner identifier' is a null-terminated string with a URL [URL] - containing an email address, or a link to a location where an email - address can be found, that belongs to the organisation responsible - for the frame. Questions regarding the frame should be sent to the - indicated email address. The tag may contain more than one "PRIV" - frame but only with different contents. It is recommended to keep the - number of "PRIV" frames as low as possible. - - <Header for 'Private frame', ID: "PRIV"> - Owner identifier <text string> $00 - The private data <binary data> - - -5. The 'unsynchronisation scheme' - - The only purpose of the 'unsynchronisation scheme' is to make the - ID3v2 tag as compatible as possible with existing software. There is - no use in 'unsynchronising' tags if the file is only to be processed - by new software. Unsynchronisation may only be made with MPEG 2 layer - I, II and III and MPEG 2.5 files. - - Whenever a false synchronisation is found within the tag, one zeroed - byte is inserted after the first false synchronisation byte. The - format of a correct sync that should be altered by ID3 encoders is as - follows: - - %11111111 111xxxxx - - And should be replaced with: - - %11111111 00000000 111xxxxx - - This has the side effect that all $FF 00 combinations have to be - altered, so they won't be affected by the decoding process. Therefore - all the $FF 00 combinations have to be replaced with the $FF 00 00 - combination during the unsynchronisation. - - To indicate usage of the unsynchronisation, the first bit in 'ID3 - flags' should be set. This bit should only be set if the tag - contains a, now corrected, false synchronisation. The bit should - only be clear if the tag does not contain any false synchronisations. - - Do bear in mind, that if a compression scheme is used by the encoder, - the unsynchronisation scheme should be applied *afterwards*. When - decoding a compressed, 'unsynchronised' file, the 'unsynchronisation - scheme' should be parsed first, decompression afterwards. - - If the last byte in the tag is $FF, and there is a need to eliminate - false synchronisations in the tag, at least one byte of padding - should be added. - - -6. Copyright - - Copyright (C) Martin Nilsson 1998. All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that a reference to this document is included on all - such copies and derivative works. However, this document itself may - not be modified in any way and reissued as the original document. - - The limited permissions granted above are perpetual and will not be - revoked. - - This document and the information contained herein is provided on an - "AS IS" basis and THE AUTHORS DISCLAIMS ALL WARRANTIES, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF - THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED - WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - - -7. References - - [CDDB] Compact Disc Data Base - - http://www.cddb.com - - [ID3v2] Martin Nilsson, "ID3v2 informal standard". - - http://www.id3lib.org/id3/id3v2-00.txt - - [ISO-639-2] ISO/FDIS 639-2. - Codes for the representation of names of languages, Part 2: Alpha-3 - code. Technical committee / subcommittee: TC 37 / SC 2 - - [ISO-4217] ISO 4217:1995. - Codes for the representation of currencies and funds. - Technical committee / subcommittee: TC 68 - - [ISO-8859-1] ISO/IEC DIS 8859-1. - 8-bit single-byte coded graphic character sets, Part 1: Latin - alphabet No. 1. Technical committee / subcommittee: JTC 1 / SC 2 - - [ISRC] ISO 3901:1986 - International Standard Recording Code (ISRC). - Technical committee / subcommittee: TC 46 / SC 9 - - [JFIF] JPEG File Interchange Format, version 1.02 - - http://www.w3.org/Graphics/JPEG/jfif.txt">http://www.w3.org/Graphics/JPEG/jfif.txt - - [MIME] Freed, N. and N. Borenstein, "Multipurpose Internet Mail - Extensions (MIME) Part One: Format of Internet Message Bodies", - RFC 2045, November 1996. - - ftp://ftp.isi.edu/in-notes/rfc2045.txt">ftp://ftp.isi.edu/in-notes/rfc2045.txt - - [MPEG] ISO/IEC 11172-3:1993. - Coding of moving pictures and associated audio for digital storage - media at up to about 1,5 Mbit/s, Part 3: Audio. - Technical committee / subcommittee: JTC 1 / SC 29 - and - ISO/IEC 13818-3:1995 - Generic coding of moving pictures and associated audio information, - Part 3: Audio. - Technical committee / subcommittee: JTC 1 / SC 29 - and - ISO/IEC DIS 13818-3 - Generic coding of moving pictures and associated audio information, - Part 3: Audio (Revision of ISO/IEC 13818-3:1995) - - - [PNG] Portable Network Graphics, version 1.0 - - http://www.w3.org/TR/REC-png-multi.html - - [UNICODE] ISO/IEC 10646-1:1993. - Universal Multiple-Octet Coded Character Set (UCS), Part 1: - Architecture and Basic Multilingual Plane. - Technical committee / subcommittee: JTC 1 / SC 2 - - http://www.unicode.org/ - - [URL] T. Berners-Lee, L. Masinter & M. McCahill, "Uniform Resource - Locators (URL).", RFC 1738, December 1994. - - ftp://ftp.isi.edu/in-notes/rfc1738.txt - - [ZLIB] P. Deutsch, Aladdin Enterprises & J-L. Gailly, "ZLIB - Compressed - Data Format Specification version 3.3", RFC 1950, May 1996. - - ftp://ftp.isi.edu/in-notes/rfc1950.txt - - -8. Appendix - - -A. Appendix A - Genre List from ID3v1 - - The following genres is defined in ID3v1 - - 0.Blues - 1.Classic Rock - 2.Country - 3.Dance - 4.Disco - 5.Funk - 6.Grunge - 7.Hip-Hop - 8.Jazz - 9.Metal - 10.New Age - 11.Oldies - 12.Other - 13.Pop - 14.R&B - 15.Rap - 16.Reggae - 17.Rock - 18.Techno - 19.Industrial - 20.Alternative - 21.Ska - 22.Death Metal - 23.Pranks - 24.Soundtrack - 25.Euro-Techno - 26.Ambient - 27.Trip-Hop - 28.Vocal - 29.Jazz+Funk - 30.Fusion - 31.Trance - 32.Classical - 33.Instrumental - 34.Acid - 35.House - 36.Game - 37.Sound Clip - 38.Gospel - 39.Noise - 40.AlternRock - 41.Bass - 42.Soul - 43.Punk - 44.Space - 45.Meditative - 46.Instrumental Pop - 47.Instrumental Rock - 48.Ethnic - 49.Gothic - 50.Darkwave - 51.Techno-Industrial - 52.Electronic - 53.Pop-Folk - 54.Eurodance - 55.Dream - 56.Southern Rock - 57.Comedy - 58.Cult - 59.Gangsta - 60.Top 40 - 61.Christian Rap - 62.Pop/Funk - 63.Jungle - 64.Native American - 65.Cabaret - 66.New Wave - 67.Psychadelic - 68.Rave - 69.Showtunes - 70.Trailer - 71.Lo-Fi - 72.Tribal - 73.Acid Punk - 74.Acid Jazz - 75.Polka - 76.Retro - 77.Musical - 78.Rock & Roll - 79.Hard Rock - - The following genres are Winamp extensions - - 80.Folk - 81.Folk-Rock - 82.National Folk - 83.Swing - 84.Fast Fusion - 85.Bebob - 86.Latin - 87.Revival - 88.Celtic - 89.Bluegrass - 90.Avantgarde - 91.Gothic Rock - 92.Progressive Rock - 93.Psychedelic Rock - 94.Symphonic Rock - 95.Slow Rock - 96.Big Band - 97.Chorus - 98.Easy Listening - 99.Acoustic - 100.Humour - 101.Speech - 102.Chanson - 103.Opera - 104.Chamber Music - 105.Sonata - 106.Symphony - 107.Booty Bass - 108.Primus - 109.Porn Groove - 110.Satire - 111.Slow Jam - 112.Club - 113.Tango - 114.Samba - 115.Folklore - 116.Ballad - 117.Power Ballad - 118.Rhythmic Soul - 119.Freestyle - 120.Duet - 121.Punk Rock - 122.Drum Solo - 123.Acapella - 124.Euro-House - 125.Dance Hall - - -9. Author's Address - - Written by - - Martin Nilsson - Rydsvägen 246 C. 30 - S-584 34 Linköping - Sweden - - Email: nilsson@id3.org - - - Edited by - - Dirk Mahoney - 57 Pechey Street - Chermside Q - Australia 4032 - - Email: dirk@id3.org - - - Johan Sundström - Alsättersgatan 5 A. 34 - S-584 35 Linköping - Sweden - - Email: johan@id3.org diff --git a/taglib/taglib/mpeg/id3v2/id3v2.4.0-frames.txt b/taglib/taglib/mpeg/id3v2/id3v2.4.0-frames.txt deleted file mode 100644 index 74a21be..0000000 --- a/taglib/taglib/mpeg/id3v2/id3v2.4.0-frames.txt +++ /dev/null @@ -1,1734 +0,0 @@ -$Id$ - -Informal standard M. Nilsson -Document: id3v2.4.0-frames.txt 1st November 2000 - - - ID3 tag version 2.4.0 - Native Frames - -Status of this document - - This document is an informal standard and replaces the ID3v2.3.0 - standard [ID3v2]. A formal standard will use another revision number - even if the content is identical to document. The contents in this - document may change for clarifications but never for added or altered - functionallity. - - Distribution of this document is unlimited. - - -Abstract - - This document describes the frames natively supported by ID3v2.4.0, - which is a revised version of the ID3v2 informal standard [ID3v2.3.0] - version 2.3.0. The ID3v2 offers a flexible way of storing audio meta - information within audio file itself. The information may be - technical information, such as equalisation curves, as well as title, - performer, copyright etc. - - ID3v2.4.0 is meant to be as close as possible to ID3v2.3.0 in order - to allow for implementations to be revised as easily as possible. - - -1. Table of contents - - 2. Conventions in this document - 3. Default flags - 4. Declared ID3v2 frames - 4.1. Unique file identifier - 4.2. Text information frames - 4.2.1. Identification frames - 4.2.2. Involved persons frames - 4.2.3. Derived and subjective properties frames - 4.2.4. Rights and license frames - 4.2.5. Other text frames - 4.2.6. User defined text information frame - 4.3. URL link frames - 4.3.1. URL link frames - details - 4.3.2. User defined URL link frame - 4.4. Music CD Identifier - 4.5. Event timing codes - 4.6. MPEG location lookup table - 4.7. Synced tempo codes - 4.8. Unsynchronised lyrics/text transcription - 4.9. Synchronised lyrics/text - 4.10. Comments - 4.11. Relative volume adjustment (2) - 4.12. Equalisation (2) - 4.13. Reverb - 4.14. Attached picture - 4.15. General encapsulated object - 4.16. Play counter - 4.17. Popularimeter - 4.18. Recommended buffer size - 4.19. Audio encryption - 4.20. Linked information - 4.21. Position synchronisation frame - 4.22. Terms of use - 4.23. Ownership frame - 4.24. Commercial frame - 4.25. Encryption method registration - 4.26. Group identification registration - 4.27. Private frame - 4.28. Signature frame - 4.29. Seek frame - 4.30. Audio seek point index - 5. Copyright - 6. References - 7. Appendix - A. Appendix A - Genre List from ID3v1 - 8. Author's Address - - -2. Conventions in this document - - Text within "" is a text string exactly as it appears in a tag. - Numbers preceded with $ are hexadecimal and numbers preceded with % - are binary. $xx is used to indicate a byte with unknown content. %x - is used to indicate a bit with unknown content. The most significant - bit (MSB) of a byte is called 'bit 7' and the least significant bit - (LSB) is called 'bit 0'. - - A tag is the whole tag described the ID3v2 main structure document - [ID3v2-strct]. A frame is a block of information in the tag. The tag - consists of a header, frames and optional padding. A field is a piece - of information; one value, a string etc. A numeric string is a string - that consists of the characters "0123456789" only. - - The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", - "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this - document are to be interpreted as described in RFC 2119 [KEYWORDS]. - - -3. Default flags - - The default settings for the frames described in this document can be - divided into the following classes. The flags may be set differently - if found more suitable by the software. - - 1. Discarded if tag is altered, discarded if file is altered. - - None. - - 2. Discarded if tag is altered, preserved if file is altered. - - None. - - 3. Preserved if tag is altered, discarded if file is altered. - - ASPI, AENC, ETCO, EQU2, MLLT, POSS, SEEK, SYLT, SYTC, RVA2, TENC, - TLEN - - 4. Preserved if tag is altered, preserved if file is altered. - - The rest of the frames. - - -4. Declared ID3v2 frames - - The following frames are declared in this draft. - - 4.19 AENC Audio encryption - 4.14 APIC Attached picture - 4.30 ASPI Audio seek point index - - 4.10 COMM Comments - 4.24 COMR Commercial frame - - 4.25 ENCR Encryption method registration - 4.12 EQU2 Equalisation (2) - 4.5 ETCO Event timing codes - - 4.15 GEOB General encapsulated object - 4.26 GRID Group identification registration - - 4.20 LINK Linked information - - 4.4 MCDI Music CD identifier - 4.6 MLLT MPEG location lookup table - - 4.23 OWNE Ownership frame - - 4.27 PRIV Private frame - 4.16 PCNT Play counter - 4.17 POPM Popularimeter - 4.21 POSS Position synchronisation frame - - 4.18 RBUF Recommended buffer size - 4.11 RVA2 Relative volume adjustment (2) - 4.13 RVRB Reverb - - 4.29 SEEK Seek frame - 4.28 SIGN Signature frame - 4.9 SYLT Synchronised lyric/text - 4.7 SYTC Synchronised tempo codes - - 4.2.1 TALB Album/Movie/Show title - 4.2.3 TBPM BPM (beats per minute) - 4.2.2 TCOM Composer - 4.2.3 TCON Content type - 4.2.4 TCOP Copyright message - 4.2.5 TDEN Encoding time - 4.2.5 TDLY Playlist delay - 4.2.5 TDOR Original release time - 4.2.5 TDRC Recording time - 4.2.5 TDRL Release time - 4.2.5 TDTG Tagging time - 4.2.2 TENC Encoded by - 4.2.2 TEXT Lyricist/Text writer - 4.2.3 TFLT File type - 4.2.2 TIPL Involved people list - 4.2.1 TIT1 Content group description - 4.2.1 TIT2 Title/songname/content description - 4.2.1 TIT3 Subtitle/Description refinement - 4.2.3 TKEY Initial key - 4.2.3 TLAN Language(s) - 4.2.3 TLEN Length - 4.2.2 TMCL Musician credits list - 4.2.3 TMED Media type - 4.2.3 TMOO Mood - 4.2.1 TOAL Original album/movie/show title - 4.2.5 TOFN Original filename - 4.2.2 TOLY Original lyricist(s)/text writer(s) - 4.2.2 TOPE Original artist(s)/performer(s) - 4.2.4 TOWN File owner/licensee - 4.2.2 TPE1 Lead performer(s)/Soloist(s) - 4.2.2 TPE2 Band/orchestra/accompaniment - 4.2.2 TPE3 Conductor/performer refinement - 4.2.2 TPE4 Interpreted, remixed, or otherwise modified by - 4.2.1 TPOS Part of a set - 4.2.4 TPRO Produced notice - 4.2.4 TPUB Publisher - 4.2.1 TRCK Track number/Position in set - 4.2.4 TRSN Internet radio station name - 4.2.4 TRSO Internet radio station owner - 4.2.5 TSOA Album sort order - 4.2.5 TSOP Performer sort order - 4.2.5 TSOT Title sort order - 4.2.1 TSRC ISRC (international standard recording code) - 4.2.5 TSSE Software/Hardware and settings used for encoding - 4.2.1 TSST Set subtitle - 4.2.2 TXXX User defined text information frame - - 4.1 UFID Unique file identifier - 4.22 USER Terms of use - 4.8 USLT Unsynchronised lyric/text transcription - - 4.3.1 WCOM Commercial information - 4.3.1 WCOP Copyright/Legal information - 4.3.1 WOAF Official audio file webpage - 4.3.1 WOAR Official artist/performer webpage - 4.3.1 WOAS Official audio source webpage - 4.3.1 WORS Official Internet radio station homepage - 4.3.1 WPAY Payment - 4.3.1 WPUB Publishers official webpage - 4.3.2 WXXX User defined URL link frame - - -4.1. Unique file identifier - - This frame's purpose is to be able to identify the audio file in a - database, that may provide more information relevant to the content. - Since standardisation of such a database is beyond this document, all - UFID frames begin with an 'owner identifier' field. It is a null- - terminated string with a URL [URL] containing an email address, or a - link to a location where an email address can be found, that belongs - to the organisation responsible for this specific database - implementation. Questions regarding the database should be sent to - the indicated email address. The URL should not be used for the - actual database queries. The string - "http://www.id3.org/dummy/ufid.html" should be used for tests. The - 'Owner identifier' must be non-empty (more than just a termination). - The 'Owner identifier' is then followed by the actual identifier, - which may be up to 64 bytes. There may be more than one "UFID" frame - in a tag, but only one with the same 'Owner identifier'. - - <Header for 'Unique file identifier', ID: "UFID"> - Owner identifier <text string> $00 - Identifier <up to 64 bytes binary data> - - -4.2. Text information frames - - The text information frames are often the most important frames, - containing information like artist, album and more. There may only be - one text information frame of its kind in an tag. All text - information frames supports multiple strings, stored as a null - separated list, where null is reperesented by the termination code - for the charater encoding. All text frame identifiers begin with "T". - Only text frame identifiers begin with "T", with the exception of the - "TXXX" frame. All the text information frames have the following - format: - - <Header for 'Text information frame', ID: "T000" - "TZZZ", - excluding "TXXX" described in 4.2.6.> - Text encoding $xx - Information <text string(s) according to encoding> - - -4.2.1. Identification frames - - TIT1 - The 'Content group description' frame is used if the sound belongs to - a larger category of sounds/music. For example, classical music is - often sorted in different musical sections (e.g. "Piano Concerto", - "Weather - Hurricane"). - - TIT2 - The 'Title/Songname/Content description' frame is the actual name of - the piece (e.g. "Adagio", "Hurricane Donna"). - - TIT3 - The 'Subtitle/Description refinement' frame is used for information - directly related to the contents title (e.g. "Op. 16" or "Performed - live at Wembley"). - - TALB - The 'Album/Movie/Show title' frame is intended for the title of the - recording (or source of sound) from which the audio in the file is - taken. - - TOAL - The 'Original album/movie/show title' frame is intended for the title - of the original recording (or source of sound), if for example the - music in the file should be a cover of a previously released song. - - TRCK - The 'Track number/Position in set' frame is a numeric string - containing the order number of the audio-file on its original - recording. This MAY be extended with a "/" character and a numeric - string containing the total number of tracks/elements on the original - recording. E.g. "4/9". - - TPOS - The 'Part of a set' frame is a numeric string that describes which - part of a set the audio came from. This frame is used if the source - described in the "TALB" frame is divided into several mediums, e.g. a - double CD. The value MAY be extended with a "/" character and a - numeric string containing the total number of parts in the set. E.g. - "1/2". - - TSST - The 'Set subtitle' frame is intended for the subtitle of the part of - a set this track belongs to. - - TSRC - The 'ISRC' frame should contain the International Standard Recording - Code [ISRC] (12 characters). - - -4.2.2. Involved persons frames - - TPE1 - The 'Lead artist/Lead performer/Soloist/Performing group' is - used for the main artist. - - TPE2 - The 'Band/Orchestra/Accompaniment' frame is used for additional - information about the performers in the recording. - - TPE3 - The 'Conductor' frame is used for the name of the conductor. - - TPE4 - The 'Interpreted, remixed, or otherwise modified by' frame contains - more information about the people behind a remix and similar - interpretations of another existing piece. - - TOPE - The 'Original artist/performer' frame is intended for the performer - of the original recording, if for example the music in the file - should be a cover of a previously released song. - - TEXT - The 'Lyricist/Text writer' frame is intended for the writer of the - text or lyrics in the recording. - - TOLY - The 'Original lyricist/text writer' frame is intended for the - text writer of the original recording, if for example the music in - the file should be a cover of a previously released song. - - TCOM - The 'Composer' frame is intended for the name of the composer. - - TMCL - The 'Musician credits list' is intended as a mapping between - instruments and the musician that played it. Every odd field is an - instrument and every even is an artist or a comma delimited list of - artists. - - TIPL - The 'Involved people list' is very similar to the musician credits - list, but maps between functions, like producer, and names. - - TENC - The 'Encoded by' frame contains the name of the person or - organisation that encoded the audio file. This field may contain a - copyright message, if the audio file also is copyrighted by the - encoder. - - -4.2.3. Derived and subjective properties frames - - TBPM - The 'BPM' frame contains the number of beats per minute in the - main part of the audio. The BPM is an integer and represented as a - numerical string. - - TLEN - The 'Length' frame contains the length of the audio file in - milliseconds, represented as a numeric string. - - TKEY - The 'Initial key' frame contains the musical key in which the sound - starts. It is represented as a string with a maximum length of three - characters. The ground keys are represented with "A","B","C","D","E", - "F" and "G" and halfkeys represented with "b" and "#". Minor is - represented as "m", e.g. "Dbm" $00. Off key is represented with an - "o" only. - - TLAN - The 'Language' frame should contain the languages of the text or - lyrics spoken or sung in the audio. The language is represented with - three characters according to ISO-639-2 [ISO-639-2]. If more than one - language is used in the text their language codes should follow - according to the amount of their usage, e.g. "eng" $00 "sve" $00. - - TCON - The 'Content type', which ID3v1 was stored as a one byte numeric - value only, is now a string. You may use one or several of the ID3v1 - types as numerical strings, or, since the category list would be - impossible to maintain with accurate and up to date categories, - define your own. Example: "21" $00 "Eurodisco" $00 - - You may also use any of the following keywords: - - RX Remix - CR Cover - - TFLT - The 'File type' frame indicates which type of audio this tag defines. - The following types and refinements are defined: - - MIME MIME type follows - MPG MPEG Audio - /1 MPEG 1/2 layer I - /2 MPEG 1/2 layer II - /3 MPEG 1/2 layer III - /2.5 MPEG 2.5 - /AAC Advanced audio compression - VQF Transform-domain Weighted Interleave Vector Quantisation - PCM Pulse Code Modulated audio - - but other types may be used, but not for these types though. This is - used in a similar way to the predefined types in the "TMED" frame, - but without parentheses. If this frame is not present audio type is - assumed to be "MPG". - - TMED - The 'Media type' frame describes from which media the sound - originated. This may be a text string or a reference to the - predefined media types found in the list below. Example: - "VID/PAL/VHS" $00. - - DIG Other digital media - /A Analogue transfer from media - - ANA Other analogue media - /WAC Wax cylinder - /8CA 8-track tape cassette - - CD CD - /A Analogue transfer from media - /DD DDD - /AD ADD - /AA AAD - - LD Laserdisc - - TT Turntable records - /33 33.33 rpm - /45 45 rpm - /71 71.29 rpm - /76 76.59 rpm - /78 78.26 rpm - /80 80 rpm - - MD MiniDisc - /A Analogue transfer from media - - DAT DAT - /A Analogue transfer from media - /1 standard, 48 kHz/16 bits, linear - /2 mode 2, 32 kHz/16 bits, linear - /3 mode 3, 32 kHz/12 bits, non-linear, low speed - /4 mode 4, 32 kHz/12 bits, 4 channels - /5 mode 5, 44.1 kHz/16 bits, linear - /6 mode 6, 44.1 kHz/16 bits, 'wide track' play - - DCC DCC - /A Analogue transfer from media - - DVD DVD - /A Analogue transfer from media - - TV Television - /PAL PAL - /NTSC NTSC - /SECAM SECAM - - VID Video - /PAL PAL - /NTSC NTSC - /SECAM SECAM - /VHS VHS - /SVHS S-VHS - /BETA BETAMAX - - RAD Radio - /FM FM - /AM AM - /LW LW - /MW MW - - TEL Telephone - /I ISDN - - MC MC (normal cassette) - /4 4.75 cm/s (normal speed for a two sided cassette) - /9 9.5 cm/s - /I Type I cassette (ferric/normal) - /II Type II cassette (chrome) - /III Type III cassette (ferric chrome) - /IV Type IV cassette (metal) - - REE Reel - /9 9.5 cm/s - /19 19 cm/s - /38 38 cm/s - /76 76 cm/s - /I Type I cassette (ferric/normal) - /II Type II cassette (chrome) - /III Type III cassette (ferric chrome) - /IV Type IV cassette (metal) - - TMOO - The 'Mood' frame is intended to reflect the mood of the audio with a - few keywords, e.g. "Romantic" or "Sad". - - -4.2.4. Rights and license frames - - TCOP - The 'Copyright message' frame, in which the string must begin with a - year and a space character (making five characters), is intended for - the copyright holder of the original sound, not the audio file - itself. The absence of this frame means only that the copyright - information is unavailable or has been removed, and must not be - interpreted to mean that the audio is public domain. Every time this - field is displayed the field must be preceded with "Copyright " (C) " - ", where (C) is one character showing a C in a circle. - - TPRO - The 'Produced notice' frame, in which the string must begin with a - year and a space character (making five characters), is intended for - the production copyright holder of the original sound, not the audio - file itself. The absence of this frame means only that the production - copyright information is unavailable or has been removed, and must - not be interpreted to mean that the audio is public domain. Every - time this field is displayed the field must be preceded with - "Produced " (P) " ", where (P) is one character showing a P in a - circle. - - TPUB - The 'Publisher' frame simply contains the name of the label or - publisher. - - TOWN - The 'File owner/licensee' frame contains the name of the owner or - licensee of the file and it's contents. - - TRSN - The 'Internet radio station name' frame contains the name of the - internet radio station from which the audio is streamed. - - TRSO - The 'Internet radio station owner' frame contains the name of the - owner of the internet radio station from which the audio is - streamed. - -4.2.5. Other text frames - - TOFN - The 'Original filename' frame contains the preferred filename for the - file, since some media doesn't allow the desired length of the - filename. The filename is case sensitive and includes its suffix. - - TDLY - The 'Playlist delay' defines the numbers of milliseconds of silence - that should be inserted before this audio. The value zero indicates - that this is a part of a multifile audio track that should be played - continuously. - - TDEN - The 'Encoding time' frame contains a timestamp describing when the - audio was encoded. Timestamp format is described in the ID3v2 - structure document [ID3v2-strct]. - - TDOR - The 'Original release time' frame contains a timestamp describing - when the original recording of the audio was released. Timestamp - format is described in the ID3v2 structure document [ID3v2-strct]. - - TDRC - The 'Recording time' frame contains a timestamp describing when the - audio was recorded. Timestamp format is described in the ID3v2 - structure document [ID3v2-strct]. - - TDRL - The 'Release time' frame contains a timestamp describing when the - audio was first released. Timestamp format is described in the ID3v2 - structure document [ID3v2-strct]. - - TDTG - The 'Tagging time' frame contains a timestamp describing then the - audio was tagged. Timestamp format is described in the ID3v2 - structure document [ID3v2-strct]. - - TSSE - The 'Software/Hardware and settings used for encoding' frame - includes the used audio encoder and its settings when the file was - encoded. Hardware refers to hardware encoders, not the computer on - which a program was run. - - TSOA - The 'Album sort order' frame defines a string which should be used - instead of the album name (TALB) for sorting purposes. E.g. an album - named "A Soundtrack" might preferably be sorted as "Soundtrack". - - TSOP - The 'Performer sort order' frame defines a string which should be - used instead of the performer (TPE2) for sorting purposes. - - TSOT - The 'Title sort order' frame defines a string which should be used - instead of the title (TIT2) for sorting purposes. - - -4.2.6. User defined text information frame - - This frame is intended for one-string text information concerning the - audio file in a similar way to the other "T"-frames. The frame body - consists of a description of the string, represented as a terminated - string, followed by the actual string. There may be more than one - "TXXX" frame in each tag, but only one with the same description. - - <Header for 'User defined text information frame', ID: "TXXX"> - Text encoding $xx - Description <text string according to encoding> $00 (00) - Value <text string according to encoding> - - -4.3. URL link frames - - With these frames dynamic data such as webpages with touring - information, price information or plain ordinary news can be added to - the tag. There may only be one URL [URL] link frame of its kind in an - tag, except when stated otherwise in the frame description. If the - text string is followed by a string termination, all the following - information should be ignored and not be displayed. All URL link - frame identifiers begins with "W". Only URL link frame identifiers - begins with "W", except for "WXXX". All URL link frames have the - following format: - - <Header for 'URL link frame', ID: "W000" - "WZZZ", excluding "WXXX" - described in 4.3.2.> - URL <text string> - - -4.3.1. URL link frames - details - - WCOM - The 'Commercial information' frame is a URL pointing at a webpage - with information such as where the album can be bought. There may be - more than one "WCOM" frame in a tag, but not with the same content. - - WCOP - The 'Copyright/Legal information' frame is a URL pointing at a - webpage where the terms of use and ownership of the file is - described. - - WOAF - The 'Official audio file webpage' frame is a URL pointing at a file - specific webpage. - - WOAR - The 'Official artist/performer webpage' frame is a URL pointing at - the artists official webpage. There may be more than one "WOAR" frame - in a tag if the audio contains more than one performer, but not with - the same content. - - WOAS - The 'Official audio source webpage' frame is a URL pointing at the - official webpage for the source of the audio file, e.g. a movie. - - WORS - The 'Official Internet radio station homepage' contains a URL - pointing at the homepage of the internet radio station. - - WPAY - The 'Payment' frame is a URL pointing at a webpage that will handle - the process of paying for this file. - - WPUB - The 'Publishers official webpage' frame is a URL pointing at the - official webpage for the publisher. - - -4.3.2. User defined URL link frame - - This frame is intended for URL [URL] links concerning the audio file - in a similar way to the other "W"-frames. The frame body consists - of a description of the string, represented as a terminated string, - followed by the actual URL. The URL is always encoded with ISO-8859-1 - [ISO-8859-1]. There may be more than one "WXXX" frame in each tag, - but only one with the same description. - - <Header for 'User defined URL link frame', ID: "WXXX"> - Text encoding $xx - Description <text string according to encoding> $00 (00) - URL <text string> - - -4.4. Music CD identifier - - This frame is intended for music that comes from a CD, so that the CD - can be identified in databases such as the CDDB [CDDB]. The frame - consists of a binary dump of the Table Of Contents, TOC, from the CD, - which is a header of 4 bytes and then 8 bytes/track on the CD plus 8 - bytes for the 'lead out', making a maximum of 804 bytes. The offset - to the beginning of every track on the CD should be described with a - four bytes absolute CD-frame address per track, and not with absolute - time. When this frame is used the presence of a valid "TRCK" frame is - REQUIRED, even if the CD's only got one track. It is recommended that - this frame is always added to tags originating from CDs. There may - only be one "MCDI" frame in each tag. - - <Header for 'Music CD identifier', ID: "MCDI"> - CD TOC <binary data> - - -4.5. Event timing codes - - This frame allows synchronisation with key events in the audio. The - header is: - - <Header for 'Event timing codes', ID: "ETCO"> - Time stamp format $xx - - Where time stamp format is: - - $01 Absolute time, 32 bit sized, using MPEG [MPEG] frames as unit - $02 Absolute time, 32 bit sized, using milliseconds as unit - - Absolute time means that every stamp contains the time from the - beginning of the file. - - Followed by a list of key events in the following format: - - Type of event $xx - Time stamp $xx (xx ...) - - The 'Time stamp' is set to zero if directly at the beginning of the - sound or after the previous event. All events MUST be sorted in - chronological order. The type of event is as follows: - - $00 padding (has no meaning) - $01 end of initial silence - $02 intro start - $03 main part start - $04 outro start - $05 outro end - $06 verse start - $07 refrain start - $08 interlude start - $09 theme start - $0A variation start - $0B key change - $0C time change - $0D momentary unwanted noise (Snap, Crackle & Pop) - $0E sustained noise - $0F sustained noise end - $10 intro end - $11 main part end - $12 verse end - $13 refrain end - $14 theme end - $15 profanity - $16 profanity end - - $17-$DF reserved for future use - - $E0-$EF not predefined synch 0-F - - $F0-$FC reserved for future use - - $FD audio end (start of silence) - $FE audio file ends - $FF one more byte of events follows (all the following bytes with - the value $FF have the same function) - - Terminating the start events such as "intro start" is OPTIONAL. The - 'Not predefined synch's ($E0-EF) are for user events. You might want - to synchronise your music to something, like setting off an explosion - on-stage, activating a screensaver etc. - - There may only be one "ETCO" frame in each tag. - - -4.6. MPEG location lookup table - - To increase performance and accuracy of jumps within a MPEG [MPEG] - audio file, frames with time codes in different locations in the file - might be useful. This ID3v2 frame includes references that the - software can use to calculate positions in the file. After the frame - header follows a descriptor of how much the 'frame counter' should be - increased for every reference. If this value is two then the first - reference points out the second frame, the 2nd reference the 4th - frame, the 3rd reference the 6th frame etc. In a similar way the - 'bytes between reference' and 'milliseconds between reference' points - out bytes and milliseconds respectively. - - Each reference consists of two parts; a certain number of bits, as - defined in 'bits for bytes deviation', that describes the difference - between what is said in 'bytes between reference' and the reality and - a certain number of bits, as defined in 'bits for milliseconds - deviation', that describes the difference between what is said in - 'milliseconds between reference' and the reality. The number of bits - in every reference, i.e. 'bits for bytes deviation'+'bits for - milliseconds deviation', must be a multiple of four. There may only - be one "MLLT" frame in each tag. - - <Header for 'Location lookup table', ID: "MLLT"> - MPEG frames between reference $xx xx - Bytes between reference $xx xx xx - Milliseconds between reference $xx xx xx - Bits for bytes deviation $xx - Bits for milliseconds dev. $xx - - Then for every reference the following data is included; - - Deviation in bytes %xxx.... - Deviation in milliseconds %xxx.... - - -4.7. Synchronised tempo codes - - For a more accurate description of the tempo of a musical piece, this - frame might be used. After the header follows one byte describing - which time stamp format should be used. Then follows one or more - tempo codes. Each tempo code consists of one tempo part and one time - part. The tempo is in BPM described with one or two bytes. If the - first byte has the value $FF, one more byte follows, which is added - to the first giving a range from 2 - 510 BPM, since $00 and $01 is - reserved. $00 is used to describe a beat-free time period, which is - not the same as a music-free time period. $01 is used to indicate one - single beat-stroke followed by a beat-free period. - - The tempo descriptor is followed by a time stamp. Every time the - tempo in the music changes, a tempo descriptor may indicate this for - the player. All tempo descriptors MUST be sorted in chronological - order. The first beat-stroke in a time-period is at the same time as - the beat description occurs. There may only be one "SYTC" frame in - each tag. - - <Header for 'Synchronised tempo codes', ID: "SYTC"> - Time stamp format $xx - Tempo data <binary data> - - Where time stamp format is: - - $01 Absolute time, 32 bit sized, using MPEG [MPEG] frames as unit - $02 Absolute time, 32 bit sized, using milliseconds as unit - - Absolute time means that every stamp contains the time from the - beginning of the file. - - -4.8. Unsynchronised lyrics/text transcription - - This frame contains the lyrics of the song or a text transcription of - other vocal activities. The head includes an encoding descriptor and - a content descriptor. The body consists of the actual text. The - 'Content descriptor' is a terminated string. If no descriptor is - entered, 'Content descriptor' is $00 (00) only. Newline characters - are allowed in the text. There may be more than one 'Unsynchronised - lyrics/text transcription' frame in each tag, but only one with the - same language and content descriptor. - - <Header for 'Unsynchronised lyrics/text transcription', ID: "USLT"> - Text encoding $xx - Language $xx xx xx - Content descriptor <text string according to encoding> $00 (00) - Lyrics/text <full text string according to encoding> - - -4.9. Synchronised lyrics/text - - This is another way of incorporating the words, said or sung lyrics, - in the audio file as text, this time, however, in sync with the - audio. It might also be used to describing events e.g. occurring on a - stage or on the screen in sync with the audio. The header includes a - content descriptor, represented with as terminated text string. If no - descriptor is entered, 'Content descriptor' is $00 (00) only. - - <Header for 'Synchronised lyrics/text', ID: "SYLT"> - Text encoding $xx - Language $xx xx xx - Time stamp format $xx - Content type $xx - Content descriptor <text string according to encoding> $00 (00) - - Content type: $00 is other - $01 is lyrics - $02 is text transcription - $03 is movement/part name (e.g. "Adagio") - $04 is events (e.g. "Don Quijote enters the stage") - $05 is chord (e.g. "Bb F Fsus") - $06 is trivia/'pop up' information - $07 is URLs to webpages - $08 is URLs to images - - Time stamp format: - - $01 Absolute time, 32 bit sized, using MPEG [MPEG] frames as unit - $02 Absolute time, 32 bit sized, using milliseconds as unit - - Absolute time means that every stamp contains the time from the - beginning of the file. - - The text that follows the frame header differs from that of the - unsynchronised lyrics/text transcription in one major way. Each - syllable (or whatever size of text is considered to be convenient by - the encoder) is a null terminated string followed by a time stamp - denoting where in the sound file it belongs. Each sync thus has the - following structure: - - Terminated text to be synced (typically a syllable) - Sync identifier (terminator to above string) $00 (00) - Time stamp $xx (xx ...) - - The 'time stamp' is set to zero or the whole sync is omitted if - located directly at the beginning of the sound. All time stamps - should be sorted in chronological order. The sync can be considered - as a validator of the subsequent string. - - Newline characters are allowed in all "SYLT" frames and MUST be used - after every entry (name, event etc.) in a frame with the content type - $03 - $04. - - A few considerations regarding whitespace characters: Whitespace - separating words should mark the beginning of a new word, thus - occurring in front of the first syllable of a new word. This is also - valid for new line characters. A syllable followed by a comma should - not be broken apart with a sync (both the syllable and the comma - should be before the sync). - - An example: The "USLT" passage - - "Strangers in the night" $0A "Exchanging glances" - - would be "SYLT" encoded as: - - "Strang" $00 xx xx "ers" $00 xx xx " in" $00 xx xx " the" $00 xx xx - " night" $00 xx xx 0A "Ex" $00 xx xx "chang" $00 xx xx "ing" $00 xx - xx "glan" $00 xx xx "ces" $00 xx xx - - There may be more than one "SYLT" frame in each tag, but only one - with the same language and content descriptor. - - -4.10. Comments - - This frame is intended for any kind of full text information that - does not fit in any other frame. It consists of a frame header - followed by encoding, language and content descriptors and is ended - with the actual comment as a text string. Newline characters are - allowed in the comment text string. There may be more than one - comment frame in each tag, but only one with the same language and - content descriptor. - - <Header for 'Comment', ID: "COMM"> - Text encoding $xx - Language $xx xx xx - Short content descrip. <text string according to encoding> $00 (00) - The actual text <full text string according to encoding> - - -4.11. Relative volume adjustment (2) - - This is a more subjective frame than the previous ones. It allows the - user to say how much he wants to increase/decrease the volume on each - channel when the file is played. The purpose is to be able to align - all files to a reference volume, so that you don't have to change the - volume constantly. This frame may also be used to balance adjust the - audio. The volume adjustment is encoded as a fixed point decibel - value, 16 bit signed integer representing (adjustment*512), giving - +/- 64 dB with a precision of 0.001953125 dB. E.g. +2 dB is stored as - $04 00 and -2 dB is $FC 00. There may be more than one "RVA2" frame - in each tag, but only one with the same identification string. - - <Header for 'Relative volume adjustment (2)', ID: "RVA2"> - Identification <text string> $00 - - The 'identification' string is used to identify the situation and/or - device where this adjustment should apply. The following is then - repeated for every channel - - Type of channel $xx - Volume adjustment $xx xx - Bits representing peak $xx - Peak volume $xx (xx ...) - - - Type of channel: $00 Other - $01 Master volume - $02 Front right - $03 Front left - $04 Back right - $05 Back left - $06 Front centre - $07 Back centre - $08 Subwoofer - - Bits representing peak can be any number between 0 and 255. 0 means - that there is no peak volume field. The peak volume field is always - padded to whole bytes, setting the most significant bits to zero. - - -4.12. Equalisation (2) - - This is another subjective, alignment frame. It allows the user to - predefine an equalisation curve within the audio file. There may be - more than one "EQU2" frame in each tag, but only one with the same - identification string. - - <Header of 'Equalisation (2)', ID: "EQU2"> - Interpolation method $xx - Identification <text string> $00 - - The 'interpolation method' describes which method is preferred when - an interpolation between the adjustment point that follows. The - following methods are currently defined: - - $00 Band - No interpolation is made. A jump from one adjustment level to - another occurs in the middle between two adjustment points. - $01 Linear - Interpolation between adjustment points is linear. - - The 'identification' string is used to identify the situation and/or - device where this adjustment should apply. The following is then - repeated for every adjustment point - - Frequency $xx xx - Volume adjustment $xx xx - - The frequency is stored in units of 1/2 Hz, giving it a range from 0 - to 32767 Hz. - - The volume adjustment is encoded as a fixed point decibel value, 16 - bit signed integer representing (adjustment*512), giving +/- 64 dB - with a precision of 0.001953125 dB. E.g. +2 dB is stored as $04 00 - and -2 dB is $FC 00. - - Adjustment points should be ordered by frequency and one frequency - should only be described once in the frame. - - -4.13. Reverb - - Yet another subjective frame, with which you can adjust echoes of - different kinds. Reverb left/right is the delay between every bounce - in ms. Reverb bounces left/right is the number of bounces that should - be made. $FF equals an infinite number of bounces. Feedback is the - amount of volume that should be returned to the next echo bounce. $00 - is 0%, $FF is 100%. If this value were $7F, there would be 50% volume - reduction on the first bounce, 50% of that on the second and so on. - Left to left means the sound from the left bounce to be played in the - left speaker, while left to right means sound from the left bounce to - be played in the right speaker. - - 'Premix left to right' is the amount of left sound to be mixed in the - right before any reverb is applied, where $00 id 0% and $FF is 100%. - 'Premix right to left' does the same thing, but right to left. - Setting both premix to $FF would result in a mono output (if the - reverb is applied symmetric). There may only be one "RVRB" frame in - each tag. - - <Header for 'Reverb', ID: "RVRB"> - Reverb left (ms) $xx xx - Reverb right (ms) $xx xx - Reverb bounces, left $xx - Reverb bounces, right $xx - Reverb feedback, left to left $xx - Reverb feedback, left to right $xx - Reverb feedback, right to right $xx - Reverb feedback, right to left $xx - Premix left to right $xx - Premix right to left $xx - - -4.14. Attached picture - - This frame contains a picture directly related to the audio file. - Image format is the MIME type and subtype [MIME] for the image. In - the event that the MIME media type name is omitted, "image/" will be - implied. The "image/png" [PNG] or "image/jpeg" [JFIF] picture format - should be used when interoperability is wanted. Description is a - short description of the picture, represented as a terminated - text string. There may be several pictures attached to one file, each - in their individual "APIC" frame, but only one with the same content - descriptor. There may only be one picture with the picture type - declared as picture type $01 and $02 respectively. There is the - possibility to put only a link to the image file by using the 'MIME - type' "-->" and having a complete URL [URL] instead of picture data. - The use of linked files should however be used sparingly since there - is the risk of separation of files. - - <Header for 'Attached picture', ID: "APIC"> - Text encoding $xx - MIME type <text string> $00 - Picture type $xx - Description <text string according to encoding> $00 (00) - Picture data <binary data> - - - Picture type: $00 Other - $01 32x32 pixels 'file icon' (PNG only) - $02 Other file icon - $03 Cover (front) - $04 Cover (back) - $05 Leaflet page - $06 Media (e.g. label side of CD) - $07 Lead artist/lead performer/soloist - $08 Artist/performer - $09 Conductor - $0A Band/Orchestra - $0B Composer - $0C Lyricist/text writer - $0D Recording Location - $0E During recording - $0F During performance - $10 Movie/video screen capture - $11 A bright coloured fish - $12 Illustration - $13 Band/artist logotype - $14 Publisher/Studio logotype - - -4.15. General encapsulated object - - In this frame any type of file can be encapsulated. After the header, - 'Frame size' and 'Encoding' follows 'MIME type' [MIME] represented as - as a terminated string encoded with ISO 8859-1 [ISO-8859-1]. The - filename is case sensitive and is encoded as 'Encoding'. Then follows - a content description as terminated string, encoded as 'Encoding'. - The last thing in the frame is the actual object. The first two - strings may be omitted, leaving only their terminations. MIME type is - always an ISO-8859-1 text string. There may be more than one "GEOB" - frame in each tag, but only one with the same content descriptor. - - <Header for 'General encapsulated object', ID: "GEOB"> - Text encoding $xx - MIME type <text string> $00 - Filename <text string according to encoding> $00 (00) - Content description <text string according to encoding> $00 (00) - Encapsulated object <binary data> - - -4.16. Play counter - - This is simply a counter of the number of times a file has been - played. The value is increased by one every time the file begins to - play. There may only be one "PCNT" frame in each tag. When the - counter reaches all one's, one byte is inserted in front of the - counter thus making the counter eight bits bigger. The counter must - be at least 32-bits long to begin with. - - <Header for 'Play counter', ID: "PCNT"> - Counter $xx xx xx xx (xx ...) - - -4.17. Popularimeter - - The purpose of this frame is to specify how good an audio file is. - Many interesting applications could be found to this frame such as a - playlist that features better audio files more often than others or - it could be used to profile a person's taste and find other 'good' - files by comparing people's profiles. The frame contains the email - address to the user, one rating byte and a four byte play counter, - intended to be increased with one for every time the file is played. - The email is a terminated string. The rating is 1-255 where 1 is - worst and 255 is best. 0 is unknown. If no personal counter is wanted - it may be omitted. When the counter reaches all one's, one byte is - inserted in front of the counter thus making the counter eight bits - bigger in the same away as the play counter ("PCNT"). There may be - more than one "POPM" frame in each tag, but only one with the same - email address. - - <Header for 'Popularimeter', ID: "POPM"> - Email to user <text string> $00 - Rating $xx - Counter $xx xx xx xx (xx ...) - - -4.18. Recommended buffer size - - Sometimes the server from which an audio file is streamed is aware of - transmission or coding problems resulting in interruptions in the - audio stream. In these cases, the size of the buffer can be - recommended by the server using this frame. If the 'embedded info - flag' is true (1) then this indicates that an ID3 tag with the - maximum size described in 'Buffer size' may occur in the audio - stream. In such case the tag should reside between two MPEG [MPEG] - frames, if the audio is MPEG encoded. If the position of the next tag - is known, 'offset to next tag' may be used. The offset is calculated - from the end of tag in which this frame resides to the first byte of - the header in the next. This field may be omitted. Embedded tags are - generally not recommended since this could render unpredictable - behaviour from present software/hardware. - - For applications like streaming audio it might be an idea to embed - tags into the audio stream though. If the clients connects to - individual connections like HTTP and there is a possibility to begin - every transmission with a tag, then this tag should include a - 'recommended buffer size' frame. If the client is connected to a - arbitrary point in the stream, such as radio or multicast, then the - 'recommended buffer size' frame SHOULD be included in every tag. - - The 'Buffer size' should be kept to a minimum. There may only be one - "RBUF" frame in each tag. - - <Header for 'Recommended buffer size', ID: "RBUF"> - Buffer size $xx xx xx - Embedded info flag %0000000x - Offset to next tag $xx xx xx xx - - -4.19. Audio encryption - - This frame indicates if the actual audio stream is encrypted, and by - whom. Since standardisation of such encryption scheme is beyond this - document, all "AENC" frames begin with a terminated string with a - URL containing an email address, or a link to a location where an - email address can be found, that belongs to the organisation - responsible for this specific encrypted audio file. Questions - regarding the encrypted audio should be sent to the email address - specified. If a $00 is found directly after the 'Frame size' and the - audio file indeed is encrypted, the whole file may be considered - useless. - - After the 'Owner identifier', a pointer to an unencrypted part of the - audio can be specified. The 'Preview start' and 'Preview length' is - described in frames. If no part is unencrypted, these fields should - be left zeroed. After the 'preview length' field follows optionally a - data block required for decryption of the audio. There may be more - than one "AENC" frames in a tag, but only one with the same 'Owner - identifier'. - - <Header for 'Audio encryption', ID: "AENC"> - Owner identifier <text string> $00 - Preview start $xx xx - Preview length $xx xx - Encryption info <binary data> - - -4.20. Linked information - - To keep information duplication as low as possible this frame may be - used to link information from another ID3v2 tag that might reside in - another audio file or alone in a binary file. It is RECOMMENDED that - this method is only used when the files are stored on a CD-ROM or - other circumstances when the risk of file separation is low. The - frame contains a frame identifier, which is the frame that should be - linked into this tag, a URL [URL] field, where a reference to the - file where the frame is given, and additional ID data, if needed. - Data should be retrieved from the first tag found in the file to - which this link points. There may be more than one "LINK" frame in a - tag, but only one with the same contents. A linked frame is to be - considered as part of the tag and has the same restrictions as if it - was a physical part of the tag (i.e. only one "RVRB" frame allowed, - whether it's linked or not). - - <Header for 'Linked information', ID: "LINK"> - Frame identifier $xx xx xx xx - URL <text string> $00 - ID and additional data <text string(s)> - - Frames that may be linked and need no additional data are "ASPI", - "ETCO", "EQU2", "MCID", "MLLT", "OWNE", "RVA2", "RVRB", "SYTC", the - text information frames and the URL link frames. - - The "AENC", "APIC", "GEOB" and "TXXX" frames may be linked with - the content descriptor as additional ID data. - - The "USER" frame may be linked with the language field as additional - ID data. - - The "PRIV" frame may be linked with the owner identifier as - additional ID data. - - The "COMM", "SYLT" and "USLT" frames may be linked with three bytes - of language descriptor directly followed by a content descriptor as - additional ID data. - - -4.21. Position synchronisation frame - - This frame delivers information to the listener of how far into the - audio stream he picked up; in effect, it states the time offset from - the first frame in the stream. The frame layout is: - - <Head for 'Position synchronisation', ID: "POSS"> - Time stamp format $xx - Position $xx (xx ...) - - Where time stamp format is: - - $01 Absolute time, 32 bit sized, using MPEG frames as unit - $02 Absolute time, 32 bit sized, using milliseconds as unit - - and position is where in the audio the listener starts to receive, - i.e. the beginning of the next frame. If this frame is used in the - beginning of a file the value is always 0. There may only be one - "POSS" frame in each tag. - - -4.22. Terms of use frame - - This frame contains a brief description of the terms of use and - ownership of the file. More detailed information concerning the legal - terms might be available through the "WCOP" frame. Newlines are - allowed in the text. There may be more than one 'Terms of use' frame - in a tag, but only one with the same 'Language'. - - <Header for 'Terms of use frame', ID: "USER"> - Text encoding $xx - Language $xx xx xx - The actual text <text string according to encoding> - - -4.23. Ownership frame - - The ownership frame might be used as a reminder of a made transaction - or, if signed, as proof. Note that the "USER" and "TOWN" frames are - good to use in conjunction with this one. The frame begins, after the - frame ID, size and encoding fields, with a 'price paid' field. The - first three characters of this field contains the currency used for - the transaction, encoded according to ISO 4217 [ISO-4217] alphabetic - currency code. Concatenated to this is the actual price paid, as a - numerical string using "." as the decimal separator. Next is an 8 - character date string (YYYYMMDD) followed by a string with the name - of the seller as the last field in the frame. There may only be one - "OWNE" frame in a tag. - - <Header for 'Ownership frame', ID: "OWNE"> - Text encoding $xx - Price paid <text string> $00 - Date of purch. <text string> - Seller <text string according to encoding> - - -4.24. Commercial frame - - This frame enables several competing offers in the same tag by - bundling all needed information. That makes this frame rather complex - but it's an easier solution than if one tries to achieve the same - result with several frames. The frame begins, after the frame ID, - size and encoding fields, with a price string field. A price is - constructed by one three character currency code, encoded according - to ISO 4217 [ISO-4217] alphabetic currency code, followed by a - numerical value where "." is used as decimal separator. In the price - string several prices may be concatenated, separated by a "/" - character, but there may only be one currency of each type. - - The price string is followed by an 8 character date string in the - format YYYYMMDD, describing for how long the price is valid. After - that is a contact URL, with which the user can contact the seller, - followed by a one byte 'received as' field. It describes how the - audio is delivered when bought according to the following list: - - $00 Other - $01 Standard CD album with other songs - $02 Compressed audio on CD - $03 File over the Internet - $04 Stream over the Internet - $05 As note sheets - $06 As note sheets in a book with other sheets - $07 Music on other media - $08 Non-musical merchandise - - Next follows a terminated string with the name of the seller followed - by a terminated string with a short description of the product. The - last thing is the ability to include a company logotype. The first of - them is the 'Picture MIME type' field containing information about - which picture format is used. In the event that the MIME media type - name is omitted, "image/" will be implied. Currently only "image/png" - and "image/jpeg" are allowed. This format string is followed by the - binary picture data. This two last fields may be omitted if no - picture is attached. There may be more than one 'commercial frame' in - a tag, but no two may be identical. - - <Header for 'Commercial frame', ID: "COMR"> - Text encoding $xx - Price string <text string> $00 - Valid until <text string> - Contact URL <text string> $00 - Received as $xx - Name of seller <text string according to encoding> $00 (00) - Description <text string according to encoding> $00 (00) - Picture MIME type <string> $00 - Seller logo <binary data> - - -4.25. Encryption method registration - - To identify with which method a frame has been encrypted the - encryption method must be registered in the tag with this frame. The - 'Owner identifier' is a null-terminated string with a URL [URL] - containing an email address, or a link to a location where an email - address can be found, that belongs to the organisation responsible - for this specific encryption method. Questions regarding the - encryption method should be sent to the indicated email address. The - 'Method symbol' contains a value that is associated with this method - throughout the whole tag, in the range $80-F0. All other values are - reserved. The 'Method symbol' may optionally be followed by - encryption specific data. There may be several "ENCR" frames in a tag - but only one containing the same symbol and only one containing the - same owner identifier. The method must be used somewhere in the tag. - See the description of the frame encryption flag in the ID3v2 - structure document [ID3v2-strct] for more information. - - <Header for 'Encryption method registration', ID: "ENCR"> - Owner identifier <text string> $00 - Method symbol $xx - Encryption data <binary data> - - -4.26. Group identification registration - - This frame enables grouping of otherwise unrelated frames. This can - be used when some frames are to be signed. To identify which frames - belongs to a set of frames a group identifier must be registered in - the tag with this frame. The 'Owner identifier' is a null-terminated - string with a URL [URL] containing an email address, or a link to a - location where an email address can be found, that belongs to the - organisation responsible for this grouping. Questions regarding the - grouping should be sent to the indicated email address. The 'Group - symbol' contains a value that associates the frame with this group - throughout the whole tag, in the range $80-F0. All other values are - reserved. The 'Group symbol' may optionally be followed by some group - specific data, e.g. a digital signature. There may be several "GRID" - frames in a tag but only one containing the same symbol and only one - containing the same owner identifier. The group symbol must be used - somewhere in the tag. See the description of the frame grouping flag - in the ID3v2 structure document [ID3v2-strct] for more information. - - <Header for 'Group ID registration', ID: "GRID"> - Owner identifier <text string> $00 - Group symbol $xx - Group dependent data <binary data> - - -4.27. Private frame - - This frame is used to contain information from a software producer - that its program uses and does not fit into the other frames. The - frame consists of an 'Owner identifier' string and the binary data. - The 'Owner identifier' is a null-terminated string with a URL [URL] - containing an email address, or a link to a location where an email - address can be found, that belongs to the organisation responsible - for the frame. Questions regarding the frame should be sent to the - indicated email address. The tag may contain more than one "PRIV" - frame but only with different contents. - - <Header for 'Private frame', ID: "PRIV"> - Owner identifier <text string> $00 - The private data <binary data> - - -4.28. Signature frame - - This frame enables a group of frames, grouped with the 'Group - identification registration', to be signed. Although signatures can - reside inside the registration frame, it might be desired to store - the signature elsewhere, e.g. in watermarks. There may be more than - one 'signature frame' in a tag, but no two may be identical. - - <Header for 'Signature frame', ID: "SIGN"> - Group symbol $xx - Signature <binary data> - - -4.29. Seek frame - - This frame indicates where other tags in a file/stream can be found. - The 'minimum offset to next tag' is calculated from the end of this - tag to the beginning of the next. There may only be one 'seek frame' - in a tag. - - <Header for 'Seek frame', ID: "SEEK"> - Minimum offset to next tag $xx xx xx xx - - -4.30. Audio seek point index - - Audio files with variable bit rates are intrinsically difficult to - deal with in the case of seeking within the file. The ASPI frame - makes seeking easier by providing a list a seek points within the - audio file. The seek points are a fractional offset within the audio - data, providing a starting point from which to find an appropriate - point to start decoding. The presence of an ASPI frame requires the - existence of a TLEN frame, indicating the duration of the file in - milliseconds. There may only be one 'audio seek point index' frame in - a tag. - - <Header for 'Seek Point Index', ID: "ASPI"> - Indexed data start (S) $xx xx xx xx - Indexed data length (L) $xx xx xx xx - Number of index points (N) $xx xx - Bits per index point (b) $xx - - Then for every index point the following data is included; - - Fraction at index (Fi) $xx (xx) - - 'Indexed data start' is a byte offset from the beginning of the file. - 'Indexed data length' is the byte length of the audio data being - indexed. 'Number of index points' is the number of index points, as - the name implies. The recommended number is 100. 'Bits per index - point' is 8 or 16, depending on the chosen precision. 8 bits works - well for short files (less than 5 minutes of audio), while 16 bits is - advantageous for long files. 'Fraction at index' is the numerator of - the fraction representing a relative position in the data. The - denominator is 2 to the power of b. - - Here are the algorithms to be used in the calculation. The known data - must be the offset of the start of the indexed data (S), the offset - of the end of the indexed data (E), the number of index points (N), - the offset at index i (Oi). We calculate the fraction at index i - (Fi). - - Oi is the offset of the frame whose start is soonest after the point - for which the time offset is (i/N * duration). - - The frame data should be calculated as follows: - - Fi = Oi/L * 2^b (rounded down to the nearest integer) - - Offset calculation should be calculated as follows from data in the - frame: - - Oi = (Fi/2^b)*L (rounded up to the nearest integer) - - -5. Copyright - - Copyright (C) Martin Nilsson 2000. All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that a reference to this document is included on all - such copies and derivative works. However, this document itself may - not be modified in any way and reissued as the original document. - - The limited permissions granted above are perpetual and will not be - revoked. - - This document and the information contained herein is provided on an - "AS IS" basis and THE AUTHORS DISCLAIMS ALL WARRANTIES, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF - THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED - WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - - -6. References - - [CDDB] Compact Disc Data Base - - <url:http://www.cddb.com> - - [ID3v2.3.0] Martin Nilsson, "ID3v2 informal standard". - - <url:http://www.id3.org/id3v2.3.0.txt> - - [ID3v2-strct] Martin Nilsson, - "ID3 tag version 2.4.0 - Main Structure" - - <url:http//www.id3.org/id3v2.4.0-structure.txt> - - [ISO-639-2] ISO/FDIS 639-2. - Codes for the representation of names of languages, Part 2: Alpha-3 - code. Technical committee / subcommittee: TC 37 / SC 2 - - [ISO-4217] ISO 4217:1995. - Codes for the representation of currencies and funds. - Technical committee / subcommittee: TC 68 - - [ISO-8859-1] ISO/IEC DIS 8859-1. - 8-bit single-byte coded graphic character sets, Part 1: Latin - alphabet No. 1. Technical committee / subcommittee: JTC 1 / SC 2 - - [ISRC] ISO 3901:1986 - International Standard Recording Code (ISRC). - Technical committee / subcommittee: TC 46 / SC 9 - - [JFIF] JPEG File Interchange Format, version 1.02 - - <url:http://www.w3.org/Graphics/JPEG/jfif.txt> - - [KEYWORDS] S. Bradner, 'Key words for use in RFCs to Indicate - Requirement Levels', RFC 2119, March 1997. - - <url:ftp://ftp.isi.edu/in-notes/rfc2119.txt> - - [MIME] Freed, N. and N. Borenstein, "Multipurpose Internet Mail - Extensions (MIME) Part One: Format of Internet Message Bodies", - RFC 2045, November 1996. - - <url:ftp://ftp.isi.edu/in-notes/rfc2045.txt> - - [MPEG] ISO/IEC 11172-3:1993. - Coding of moving pictures and associated audio for digital storage - media at up to about 1,5 Mbit/s, Part 3: Audio. - Technical committee / subcommittee: JTC 1 / SC 29 - and - ISO/IEC 13818-3:1995 - Generic coding of moving pictures and associated audio information, - Part 3: Audio. - Technical committee / subcommittee: JTC 1 / SC 29 - and - ISO/IEC DIS 13818-3 - Generic coding of moving pictures and associated audio information, - Part 3: Audio (Revision of ISO/IEC 13818-3:1995) - - - [PNG] Portable Network Graphics, version 1.0 - - <url:http://www.w3.org/TR/REC-png-multi.html> - - [URL] T. Berners-Lee, L. Masinter & M. McCahill, "Uniform Resource - Locators (URL).", RFC 1738, December 1994. - - <url:ftp://ftp.isi.edu/in-notes/rfc1738.txt> - - [ZLIB] P. Deutsch, Aladdin Enterprises & J-L. Gailly, "ZLIB - Compressed - Data Format Specification version 3.3", RFC 1950, May 1996. - - <url:ftp://ftp.isi.edu/in-notes/rfc1950.txt> - - -7. Appendix - - -A. Appendix A - Genre List from ID3v1 - - The following genres is defined in ID3v1 - - 0.Blues - 1.Classic Rock - 2.Country - 3.Dance - 4.Disco - 5.Funk - 6.Grunge - 7.Hip-Hop - 8.Jazz - 9.Metal - 10.New Age - 11.Oldies - 12.Other - 13.Pop - 14.R&B - 15.Rap - 16.Reggae - 17.Rock - 18.Techno - 19.Industrial - 20.Alternative - 21.Ska - 22.Death Metal - 23.Pranks - 24.Soundtrack - 25.Euro-Techno - 26.Ambient - 27.Trip-Hop - 28.Vocal - 29.Jazz+Funk - 30.Fusion - 31.Trance - 32.Classical - 33.Instrumental - 34.Acid - 35.House - 36.Game - 37.Sound Clip - 38.Gospel - 39.Noise - 40.AlternRock - 41.Bass - 42.Soul - 43.Punk - 44.Space - 45.Meditative - 46.Instrumental Pop - 47.Instrumental Rock - 48.Ethnic - 49.Gothic - 50.Darkwave - 51.Techno-Industrial - 52.Electronic - 53.Pop-Folk - 54.Eurodance - 55.Dream - 56.Southern Rock - 57.Comedy - 58.Cult - 59.Gangsta - 60.Top 40 - 61.Christian Rap - 62.Pop/Funk - 63.Jungle - 64.Native American - 65.Cabaret - 66.New Wave - 67.Psychadelic - 68.Rave - 69.Showtunes - 70.Trailer - 71.Lo-Fi - 72.Tribal - 73.Acid Punk - 74.Acid Jazz - 75.Polka - 76.Retro - 77.Musical - 78.Rock & Roll - 79.Hard Rock - - -8. Author's Address - - Written by - - Martin Nilsson - Rydsvägen 246 C. 30 - SE-584 34 Linköping - Sweden - - Email: nilsson@id3.org diff --git a/taglib/taglib/mpeg/id3v2/id3v2.4.0-structure.txt b/taglib/taglib/mpeg/id3v2/id3v2.4.0-structure.txt deleted file mode 100644 index 5fa156a..0000000 --- a/taglib/taglib/mpeg/id3v2/id3v2.4.0-structure.txt +++ /dev/null @@ -1,733 +0,0 @@ - -Informal standard M. Nilsson -Document: id3v2.4.0-structure.txt 16 September 2001 - - - ID3 tag version 2.4.0 - Main Structure - -Status of this document - - This document is an informal standard and replaces the ID3v2.3.0 - standard [ID3v2]. A formal standard will use another revision number - even if the content is identical to document. The contents in this - document may change for clarifications but never for added or altered - functionallity. - - Distribution of this document is unlimited. - - -Abstract - - This document describes the main structure of ID3v2.4.0, which is a - revised version of the ID3v2 informal standard [ID3v2] version - 2.3.0. The ID3v2 offers a flexible way of storing audio meta - information within the audio file itself. The information may be - technical information, such as equalisation curves, as well as - title, performer, copyright etc. - - ID3v2.4.0 is meant to be as close as possible to ID3v2.3.0 in order - to allow for implementations to be revised as easily as possible. - - -1. Table of contents - - Status of this document - Abstract - 1. Table of contents - 2. Conventions in this document - 2. Standard overview - 3. ID3v2 overview - 3.1. ID3v2 header - 3.2. ID3v2 extended header - 3.3. Padding - 3.4. ID3v2 footer - 4. ID3v2 frames overview - 4.1. Frame header flags - 4.1.1. Frame status flags - 4.1.2. Frame format flags - 5. Tag location - 6. Unsynchronisation - 6.1. The unsynchronisation scheme - 6.2. Synchsafe integers - 7. Copyright - 8. References - 9. Author's Address - - -2. Conventions in this document - - Text within "" is a text string exactly as it appears in a tag. - Numbers preceded with $ are hexadecimal and numbers preceded with % - are binary. $xx is used to indicate a byte with unknown content. %x - is used to indicate a bit with unknown content. The most significant - bit (MSB) of a byte is called 'bit 7' and the least significant bit - (LSB) is called 'bit 0'. - - A tag is the whole tag described in this document. A frame is a block - of information in the tag. The tag consists of a header, frames and - optional padding. A field is a piece of information; one value, a - string etc. A numeric string is a string that consists of the - characters "0123456789" only. - - The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", - "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this - document are to be interpreted as described in RFC 2119 [KEYWORDS]. - - -3. ID3v2 overview - - ID3v2 is a general tagging format for audio, which makes it possible - to store meta data about the audio inside the audio file itself. The - ID3 tag described in this document is mainly targeted at files - encoded with MPEG-1/2 layer I, MPEG-1/2 layer II, MPEG-1/2 layer III - and MPEG-2.5, but may work with other types of encoded audio or as a - stand alone format for audio meta data. - - ID3v2 is designed to be as flexible and expandable as possible to - meet new meta information needs that might arise. To achieve that - ID3v2 is constructed as a container for several information blocks, - called frames, whose format need not be known to the software that - encounters them. At the start of every frame is an unique and - predefined identifier, a size descriptor that allows software to skip - unknown frames and a flags field. The flags describes encoding - details and if the frame should remain in the tag, should it be - unknown to the software, if the file is altered. - - The bitorder in ID3v2 is most significant bit first (MSB). The - byteorder in multibyte numbers is most significant byte first (e.g. - $12345678 would be encoded $12 34 56 78), also known as big endian - and network byte order. - - Overall tag structure: - - +-----------------------------+ - | Header (10 bytes) | - +-----------------------------+ - | Extended Header | - | (variable length, OPTIONAL) | - +-----------------------------+ - | Frames (variable length) | - +-----------------------------+ - | Padding | - | (variable length, OPTIONAL) | - +-----------------------------+ - | Footer (10 bytes, OPTIONAL) | - +-----------------------------+ - - In general, padding and footer are mutually exclusive. See details in - sections 3.3, 3.4 and 5. - - -3.1. ID3v2 header - - The first part of the ID3v2 tag is the 10 byte tag header, laid out - as follows: - - ID3v2/file identifier "ID3" - ID3v2 version $04 00 - ID3v2 flags %abcd0000 - ID3v2 size 4 * %0xxxxxxx - - The first three bytes of the tag are always "ID3", to indicate that - this is an ID3v2 tag, directly followed by the two version bytes. The - first byte of ID3v2 version is its major version, while the second - byte is its revision number. In this case this is ID3v2.4.0. All - revisions are backwards compatible while major versions are not. If - software with ID3v2.4.0 and below support should encounter version - five or higher it should simply ignore the whole tag. Version or - revision will never be $FF. - - The version is followed by the ID3v2 flags field, of which currently - four flags are used. - - - a - Unsynchronisation - - Bit 7 in the 'ID3v2 flags' indicates whether or not - unsynchronisation is applied on all frames (see section 6.1 for - details); a set bit indicates usage. - - - b - Extended header - - The second bit (bit 6) indicates whether or not the header is - followed by an extended header. The extended header is described in - section 3.2. A set bit indicates the presence of an extended - header. - - - c - Experimental indicator - - The third bit (bit 5) is used as an 'experimental indicator'. This - flag SHALL always be set when the tag is in an experimental stage. - - - d - Footer present - - Bit 4 indicates that a footer (section 3.4) is present at the very - end of the tag. A set bit indicates the presence of a footer. - - - All the other flags MUST be cleared. If one of these undefined flags - are set, the tag might not be readable for a parser that does not - know the flags function. - - The ID3v2 tag size is stored as a 32 bit synchsafe integer (section - 6.2), making a total of 28 effective bits (representing up to 256MB). - - The ID3v2 tag size is the sum of the byte length of the extended - header, the padding and the frames after unsynchronisation. If a - footer is present this equals to ('total size' - 20) bytes, otherwise - ('total size' - 10) bytes. - - An ID3v2 tag can be detected with the following pattern: - $49 44 33 yy yy xx zz zz zz zz - Where yy is less than $FF, xx is the 'flags' byte and zz is less than - $80. - - -3.2. Extended header - - The extended header contains information that can provide further - insight in the structure of the tag, but is not vital to the correct - parsing of the tag information; hence the extended header is - optional. - - Extended header size 4 * %0xxxxxxx - Number of flag bytes $01 - Extended Flags $xx - - Where the 'Extended header size' is the size of the whole extended - header, stored as a 32 bit synchsafe integer. An extended header can - thus never have a size of fewer than six bytes. - - The extended flags field, with its size described by 'number of flag - bytes', is defined as: - - %0bcd0000 - - Each flag that is set in the extended header has data attached, which - comes in the order in which the flags are encountered (i.e. the data - for flag 'b' comes before the data for flag 'c'). Unset flags cannot - have any attached data. All unknown flags MUST be unset and their - corresponding data removed when a tag is modified. - - Every set flag's data starts with a length byte, which contains a - value between 0 and 127 ($00 - $7f), followed by data that has the - field length indicated by the length byte. If a flag has no attached - data, the value $00 is used as length byte. - - - b - Tag is an update - - If this flag is set, the present tag is an update of a tag found - earlier in the present file or stream. If frames defined as unique - are found in the present tag, they are to override any - corresponding ones found in the earlier tag. This flag has no - corresponding data. - - Flag data length $00 - - c - CRC data present - - If this flag is set, a CRC-32 [ISO-3309] data is included in the - extended header. The CRC is calculated on all the data between the - header and footer as indicated by the header's tag length field, - minus the extended header. Note that this includes the padding (if - there is any), but excludes the footer. The CRC-32 is stored as an - 35 bit synchsafe integer, leaving the upper four bits always - zeroed. - - Flag data length $05 - Total frame CRC 5 * %0xxxxxxx - - d - Tag restrictions - - For some applications it might be desired to restrict a tag in more - ways than imposed by the ID3v2 specification. Note that the - presence of these restrictions does not affect how the tag is - decoded, merely how it was restricted before encoding. If this flag - is set the tag is restricted as follows: - - Flag data length $01 - Restrictions %ppqrrstt - - p - Tag size restrictions - - 00 No more than 128 frames and 1 MB total tag size. - 01 No more than 64 frames and 128 KB total tag size. - 10 No more than 32 frames and 40 KB total tag size. - 11 No more than 32 frames and 4 KB total tag size. - - q - Text encoding restrictions - - 0 No restrictions - 1 Strings are only encoded with ISO-8859-1 [ISO-8859-1] or - UTF-8 [UTF-8]. - - r - Text fields size restrictions - - 00 No restrictions - 01 No string is longer than 1024 characters. - 10 No string is longer than 128 characters. - 11 No string is longer than 30 characters. - - Note that nothing is said about how many bytes is used to - represent those characters, since it is encoding dependent. If a - text frame consists of more than one string, the sum of the - strungs is restricted as stated. - - s - Image encoding restrictions - - 0 No restrictions - 1 Images are encoded only with PNG [PNG] or JPEG [JFIF]. - - t - Image size restrictions - - 00 No restrictions - 01 All images are 256x256 pixels or smaller. - 10 All images are 64x64 pixels or smaller. - 11 All images are exactly 64x64 pixels, unless required - otherwise. - - -3.3. Padding - - It is OPTIONAL to include padding after the final frame (at the end - of the ID3 tag), making the size of all the frames together smaller - than the size given in the tag header. A possible purpose of this - padding is to allow for adding a few additional frames or enlarge - existing frames within the tag without having to rewrite the entire - file. The value of the padding bytes must be $00. A tag MUST NOT have - any padding between the frames or between the tag header and the - frames. Furthermore it MUST NOT have any padding when a tag footer is - added to the tag. - - -3.4. ID3v2 footer - - To speed up the process of locating an ID3v2 tag when searching from - the end of a file, a footer can be added to the tag. It is REQUIRED - to add a footer to an appended tag, i.e. a tag located after all - audio data. The footer is a copy of the header, but with a different - identifier. - - ID3v2 identifier "3DI" - ID3v2 version $04 00 - ID3v2 flags %abcd0000 - ID3v2 size 4 * %0xxxxxxx - - -4. ID3v2 frame overview - - All ID3v2 frames consists of one frame header followed by one or more - fields containing the actual information. The header is always 10 - bytes and laid out as follows: - - Frame ID $xx xx xx xx (four characters) - Size 4 * %0xxxxxxx - Flags $xx xx - - The frame ID is made out of the characters capital A-Z and 0-9. - Identifiers beginning with "X", "Y" and "Z" are for experimental - frames and free for everyone to use, without the need to set the - experimental bit in the tag header. Bear in mind that someone else - might have used the same identifier as you. All other identifiers are - either used or reserved for future use. - - The frame ID is followed by a size descriptor containing the size of - the data in the final frame, after encryption, compression and - unsynchronisation. The size is excluding the frame header ('total - frame size' - 10 bytes) and stored as a 32 bit synchsafe integer. - - In the frame header the size descriptor is followed by two flag - bytes. These flags are described in section 4.1. - - There is no fixed order of the frames' appearance in the tag, - although it is desired that the frames are arranged in order of - significance concerning the recognition of the file. An example of - such order: UFID, TIT2, MCDI, TRCK ... - - A tag MUST contain at least one frame. A frame must be at least 1 - byte big, excluding the header. - - If nothing else is said, strings, including numeric strings and URLs - [URL], are represented as ISO-8859-1 [ISO-8859-1] characters in the - range $20 - $FF. Such strings are represented in frame descriptions - as <text string>, or <full text string> if newlines are allowed. If - nothing else is said newline character is forbidden. In ISO-8859-1 a - newline is represented, when allowed, with $0A only. - - Frames that allow different types of text encoding contains a text - encoding description byte. Possible encodings: - - $00 ISO-8859-1 [ISO-8859-1]. Terminated with $00. - $01 UTF-16 [UTF-16] encoded Unicode [UNICODE] with BOM. All - strings in the same frame SHALL have the same byteorder. - Terminated with $00 00. - $02 UTF-16BE [UTF-16] encoded Unicode [UNICODE] without BOM. - Terminated with $00 00. - $03 UTF-8 [UTF-8] encoded Unicode [UNICODE]. Terminated with $00. - - Strings dependent on encoding are represented in frame descriptions - as <text string according to encoding>, or <full text string - according to encoding> if newlines are allowed. Any empty strings of - type $01 which are NULL-terminated may have the Unicode BOM followed - by a Unicode NULL ($FF FE 00 00 or $FE FF 00 00). - - The timestamp fields are based on a subset of ISO 8601. When being as - precise as possible the format of a time string is - yyyy-MM-ddTHH:mm:ss (year, "-", month, "-", day, "T", hour (out of - 24), ":", minutes, ":", seconds), but the precision may be reduced by - removing as many time indicators as wanted. Hence valid timestamps - are - yyyy, yyyy-MM, yyyy-MM-dd, yyyy-MM-ddTHH, yyyy-MM-ddTHH:mm and - yyyy-MM-ddTHH:mm:ss. All time stamps are UTC. For durations, use - the slash character as described in 8601, and for multiple non- - contiguous dates, use multiple strings, if allowed by the frame - definition. - - The three byte language field, present in several frames, is used to - describe the language of the frame's content, according to ISO-639-2 - [ISO-639-2]. The language should be represented in lower case. If the - language is not known the string "XXX" should be used. - - All URLs [URL] MAY be relative, e.g. "picture.png", "../doc.txt". - - If a frame is longer than it should be, e.g. having more fields than - specified in this document, that indicates that additions to the - frame have been made in a later version of the ID3v2 standard. This - is reflected by the revision number in the header of the tag. - - -4.1. Frame header flags - - In the frame header the size descriptor is followed by two flag - bytes. All unused flags MUST be cleared. The first byte is for - 'status messages' and the second byte is a format description. If an - unknown flag is set in the first byte the frame MUST NOT be changed - without that bit cleared. If an unknown flag is set in the second - byte the frame is likely to not be readable. Some flags in the second - byte indicates that extra information is added to the header. These - fields of extra information is ordered as the flags that indicates - them. The flags field is defined as follows (l and o left out because - ther resemblence to one and zero): - - %0abc0000 %0h00kmnp - - Some frame format flags indicate that additional information fields - are added to the frame. This information is added after the frame - header and before the frame data in the same order as the flags that - indicates them. I.e. the four bytes of decompressed size will precede - the encryption method byte. These additions affects the 'frame size' - field, but are not subject to encryption or compression. - - The default status flags setting for a frame is, unless stated - otherwise, 'preserved if tag is altered' and 'preserved if file is - altered', i.e. %00000000. - - -4.1.1. Frame status flags - - a - Tag alter preservation - - This flag tells the tag parser what to do with this frame if it is - unknown and the tag is altered in any way. This applies to all - kinds of alterations, including adding more padding and reordering - the frames. - - 0 Frame should be preserved. - 1 Frame should be discarded. - - - b - File alter preservation - - This flag tells the tag parser what to do with this frame if it is - unknown and the file, excluding the tag, is altered. This does not - apply when the audio is completely replaced with other audio data. - - 0 Frame should be preserved. - 1 Frame should be discarded. - - - c - Read only - - This flag, if set, tells the software that the contents of this - frame are intended to be read only. Changing the contents might - break something, e.g. a signature. If the contents are changed, - without knowledge of why the frame was flagged read only and - without taking the proper means to compensate, e.g. recalculating - the signature, the bit MUST be cleared. - - -4.1.2. Frame format flags - - h - Grouping identity - - This flag indicates whether or not this frame belongs in a group - with other frames. If set, a group identifier byte is added to the - frame. Every frame with the same group identifier belongs to the - same group. - - 0 Frame does not contain group information - 1 Frame contains group information - - - k - Compression - - This flag indicates whether or not the frame is compressed. - A 'Data Length Indicator' byte MUST be included in the frame. - - 0 Frame is not compressed. - 1 Frame is compressed using zlib [zlib] deflate method. - If set, this requires the 'Data Length Indicator' bit - to be set as well. - - - m - Encryption - - This flag indicates whether or not the frame is encrypted. If set, - one byte indicating with which method it was encrypted will be - added to the frame. See description of the ENCR frame for more - information about encryption method registration. Encryption - should be done after compression. Whether or not setting this flag - requires the presence of a 'Data Length Indicator' depends on the - specific algorithm used. - - 0 Frame is not encrypted. - 1 Frame is encrypted. - - n - Unsynchronisation - - This flag indicates whether or not unsynchronisation was applied - to this frame. See section 6 for details on unsynchronisation. - If this flag is set all data from the end of this header to the - end of this frame has been unsynchronised. Although desirable, the - presence of a 'Data Length Indicator' is not made mandatory by - unsynchronisation. - - 0 Frame has not been unsynchronised. - 1 Frame has been unsyrchronised. - - p - Data length indicator - - This flag indicates that a data length indicator has been added to - the frame. The data length indicator is the value one would write - as the 'Frame length' if all of the frame format flags were - zeroed, represented as a 32 bit synchsafe integer. - - 0 There is no Data Length Indicator. - 1 A data length Indicator has been added to the frame. - - -5. Tag location - - The default location of an ID3v2 tag is prepended to the audio so - that players can benefit from the information when the data is - streamed. It is however possible to append the tag, or make a - prepend/append combination. When deciding upon where an unembedded - tag should be located, the following order of preference SHOULD be - considered. - - 1. Prepend the tag. - - 2. Prepend a tag with all vital information and add a second tag at - the end of the file, before tags from other tagging systems. The - first tag is required to have a SEEK frame. - - 3. Add a tag at the end of the file, before tags from other tagging - systems. - - In case 2 and 3 the tag can simply be appended if no other known tags - are present. The suggested method to find ID3v2 tags are: - - 1. Look for a prepended tag using the pattern found in section 3.1. - - 2. If a SEEK frame was found, use its values to guide further - searching. - - 3. Look for a tag footer, scanning from the back of the file. - - For every new tag that is found, the old tag should be discarded - unless the update flag in the extended header (section 3.2) is set. - - -6. Unsynchronisation - - The only purpose of unsynchronisation is to make the ID3v2 tag as - compatible as possible with existing software and hardware. There is - no use in 'unsynchronising' tags if the file is only to be processed - only by ID3v2 aware software and hardware. Unsynchronisation is only - useful with tags in MPEG 1/2 layer I, II and III, MPEG 2.5 and AAC - files. - - -6.1. The unsynchronisation scheme - - Whenever a false synchronisation is found within the tag, one zeroed - byte is inserted after the first false synchronisation byte. The - format of synchronisations that should be altered by ID3 encoders is - as follows: - - %11111111 111xxxxx - - and should be replaced with: - - %11111111 00000000 111xxxxx - - This has the side effect that all $FF 00 combinations have to be - altered, so they will not be affected by the decoding process. - Therefore all the $FF 00 combinations have to be replaced with the - $FF 00 00 combination during the unsynchronisation. - - To indicate usage of the unsynchronisation, the unsynchronisation - flag in the frame header should be set. This bit MUST be set if the - frame was altered by the unsynchronisation and SHOULD NOT be set if - unaltered. If all frames in the tag are unsynchronised the - unsynchronisation flag in the tag header SHOULD be set. It MUST NOT - be set if the tag has a frame which is not unsynchronised. - - Assume the first byte of the audio to be $FF. The special case when - the last byte of the last frame is $FF and no padding nor footer is - used will then introduce a false synchronisation. This can be solved - by adding a footer, adding padding or unsynchronising the frame and - add $00 to the end of the frame data, thus adding more byte to the - frame size than a normal unsynchronisation would. Although not - preferred, it is allowed to apply the last method on all frames - ending with $FF. - - It is preferred that the tag is either completely unsynchronised or - not unsynchronised at all. A completely unsynchronised tag has no - false synchonisations in it, as defined above, and does not end with - $FF. A completely non-unsynchronised tag contains no unsynchronised - frames, and thus the unsynchronisation flag in the header is cleared. - - Do bear in mind, that if compression or encryption is used, the - unsynchronisation scheme MUST be applied afterwards. When decoding an - unsynchronised frame, the unsynchronisation scheme MUST be reversed - first, encryption and decompression afterwards. - - -6.2. Synchsafe integers - - In some parts of the tag it is inconvenient to use the - unsychronisation scheme because the size of unsynchronised data is - not known in advance, which is particularly problematic with size - descriptors. The solution in ID3v2 is to use synchsafe integers, in - which there can never be any false synchs. Synchsafe integers are - integers that keep its highest bit (bit 7) zeroed, making seven bits - out of eight available. Thus a 32 bit synchsafe integer can store 28 - bits of information. - - Example: - - 255 (%11111111) encoded as a 16 bit synchsafe integer is 383 - (%00000001 01111111). - - -7. Copyright - - Copyright (C) Martin Nilsson 2000. All Rights Reserved. - - This document and translations of it may be copied and furnished to - others, and derivative works that comment on or otherwise explain it - or assist in its implementation may be prepared, copied, published - and distributed, in whole or in part, without restriction of any - kind, provided that a reference to this document is included on all - such copies and derivative works. However, this document itself may - not be modified in any way and reissued as the original document. - - The limited permissions granted above are perpetual and will not be - revoked. - - This document and the information contained herein is provided on an - 'AS IS' basis and THE AUTHORS DISCLAIMS ALL WARRANTIES, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF - THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED - WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - - -8. References - - [ID3v2] Martin Nilsson, 'ID3v2 informal standard'. - - <url:http://www.id3.org/id3v2.3.0.txt> - - [ISO-639-2] ISO/FDIS 639-2. - 'Codes for the representation of names of languages, Part 2: Alpha-3 - code.' Technical committee / subcommittee: TC 37 / SC 2 - - [ISO-3309] ISO 3309 - 'Information Processing Systems--Data Communication High-Level Data - Link Control Procedure--Frame Structure', IS 3309, October 1984, 3rd - Edition. - - [ISO-8859-1] ISO/IEC DIS 8859-1. - '8-bit single-byte coded graphic character sets, Part 1: Latin - alphabet No. 1.' Technical committee / subcommittee: JTC 1 / SC 2 - - [JFIF] 'JPEG File Interchange Format, version 1.02' - - <url:http://www.w3.org/Graphics/JPEG/jfif.txt> - - [KEYWORDS] S. Bradner, 'Key words for use in RFCs to Indicate - Requirement Levels', RFC 2119, March 1997. - - <url:ftp://ftp.isi.edu/in-notes/rfc2119.txt> - - [MPEG] ISO/IEC 11172-3:1993. - 'Coding of moving pictures and associated audio for digital storage - media at up to about 1,5 Mbit/s, Part 3: Audio.' - Technical committee / subcommittee: JTC 1 / SC 29 - and - ISO/IEC 13818-3:1995 - 'Generic coding of moving pictures and associated audio information, - Part 3: Audio.' - Technical committee / subcommittee: JTC 1 / SC 29 - and - ISO/IEC DIS 13818-3 - 'Generic coding of moving pictures and associated audio information, - Part 3: Audio (Revision of ISO/IEC 13818-3:1995)' - - [PNG] 'Portable Network Graphics, version 1.0' - - <url:http://www.w3.org/TR/REC-png-multi.html> - - [UNICODE] The Unicode Consortium, - 'The Unicode Standard Version 3.0', ISBN 0-201-61633-5. - - <url:http://www.unicode.org/unicode/standard/versions/Unicode3.0.htm> - - [URL] T. Berners-Lee, L. Masinter & M. McCahill, 'Uniform Resource - Locators (URL)', RFC 1738, December 1994. - - <url:ftp://ftp.isi.edu/in-notes/rfc1738.txt> - - [UTF-8] F. Yergeau, 'UTF-8, a transformation format of ISO 10646', - RFC 2279, January 1998. - - <url:ftp://ftp.isi.edu/in-notes/rfc2279.txt> - - [UTF-16] F. Yergeau, 'UTF-16, an encoding of ISO 10646', RFC 2781, - February 2000. - - <url:ftp://ftp.isi.edu/in-notes/rfc2781.txt> - - [ZLIB] P. Deutsch, Aladdin Enterprises & J-L. Gailly, 'ZLIB - Compressed Data Format Specification version 3.3', RFC 1950, - May 1996. - - <url:ftp://ftp.isi.edu/in-notes/rfc1950.txt> - - -9. Author's Address - - Written by - - Martin Nilsson - Rydsvägen 246 C. 30 - SE-584 34 Linköping - Sweden - - Email: nilsson@id3.org - diff --git a/taglib/taglib/mpeg/id3v2/id3v2extendedheader.cpp b/taglib/taglib/mpeg/id3v2/id3v2extendedheader.cpp deleted file mode 100644 index ddcfd45..0000000 --- a/taglib/taglib/mpeg/id3v2/id3v2extendedheader.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include "id3v2extendedheader.h" -#include "id3v2synchdata.h" - -using namespace TagLib; -using namespace ID3v2; - -class ExtendedHeader::ExtendedHeaderPrivate -{ -public: - ExtendedHeaderPrivate() : size(0) {} - - uint size; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public methods -//////////////////////////////////////////////////////////////////////////////// - -ExtendedHeader::ExtendedHeader() -{ - d = new ExtendedHeaderPrivate(); -} - -ExtendedHeader::~ExtendedHeader() -{ - delete d; -} - -TagLib::uint ExtendedHeader::size() const -{ - return d->size; -} - -void ExtendedHeader::setData(const ByteVector &data) -{ - parse(data); -} - -//////////////////////////////////////////////////////////////////////////////// -// protected members -//////////////////////////////////////////////////////////////////////////////// - -void ExtendedHeader::parse(const ByteVector &data) -{ - d->size = SynchData::toUInt(data.mid(0, 4)); // (structure 3.2 "Extended header size") -} diff --git a/taglib/taglib/mpeg/id3v2/id3v2extendedheader.h b/taglib/taglib/mpeg/id3v2/id3v2extendedheader.h deleted file mode 100644 index d7227e9..0000000 --- a/taglib/taglib/mpeg/id3v2/id3v2extendedheader.h +++ /dev/null @@ -1,93 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_ID3V2EXTENDEDHEADER_H -#define TAGLIB_ID3V2EXTENDEDHEADER_H - -#include "taglib_export.h" -#include "tbytevector.h" -#include "taglib.h" - -namespace TagLib { - - namespace ID3v2 { - - //! ID3v2 extended header implementation - - /*! - * This class implements ID3v2 extended headers. It attempts to follow, - * both semantically and programatically, the structure specified in - * the ID3v2 standard. The API is based on the properties of ID3v2 extended - * headers specified there. If any of the terms used in this documentation - * are unclear please check the specification in the linked section. - * (Structure, <a href="id3v2-structure.html#3.2">3.2</a>) - */ - - class TAGLIB_EXPORT ExtendedHeader - { - public: - /*! - * Constructs an empty ID3v2 extended header. - */ - ExtendedHeader(); - - /*! - * Destroys the extended header. - */ - virtual ~ExtendedHeader(); - - /*! - * Returns the size of the extended header. This is variable for the - * extended header. - */ - uint size() const; - - /*! - * Sets the data that will be used as the extended header. Since the - * length is not known before the extended header has been parsed, this - * should just be a pointer to the first byte of the extended header. It - * will determine the length internally and make that available through - * size(). - */ - void setData(const ByteVector &data); - - protected: - /*! - * Called by setData() to parse the extended header data. It makes this - * information available through the public API. - */ - void parse(const ByteVector &data); - - private: - ExtendedHeader(const ExtendedHeader &); - ExtendedHeader &operator=(const ExtendedHeader &); - - class ExtendedHeaderPrivate; - ExtendedHeaderPrivate *d; - }; - - } -} -#endif diff --git a/taglib/taglib/mpeg/id3v2/id3v2footer.cpp b/taglib/taglib/mpeg/id3v2/id3v2footer.cpp deleted file mode 100644 index defbb17..0000000 --- a/taglib/taglib/mpeg/id3v2/id3v2footer.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include "id3v2footer.h" -#include "id3v2header.h" - -using namespace TagLib; -using namespace ID3v2; - -class Footer::FooterPrivate -{ -public: - static const uint size = 10; -}; - -Footer::Footer() -{ - -} - -Footer::~Footer() -{ - -} - -TagLib::uint Footer::size() -{ - return FooterPrivate::size; -} - -ByteVector Footer::render(const Header *header) const -{ - ByteVector headerData = header->render(); - headerData[0] = '3'; - headerData[1] = 'D'; - headerData[2] = 'I'; - return headerData; -} diff --git a/taglib/taglib/mpeg/id3v2/id3v2footer.h b/taglib/taglib/mpeg/id3v2/id3v2footer.h deleted file mode 100644 index 1374a14..0000000 --- a/taglib/taglib/mpeg/id3v2/id3v2footer.h +++ /dev/null @@ -1,82 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_ID3V2FOOTER_H -#define TAGLIB_ID3V2FOOTER_H - -#include "taglib_export.h" -#include "tbytevector.h" - -namespace TagLib { - - namespace ID3v2 { - - class Header; - - //! ID3v2 footer implementation - - /*! - * Per the ID3v2 specification, the tag's footer is just a copy of the - * information in the header. As such there is no API for reading the - * data from the header, it can just as easily be done from the header. - * - * In fact, at this point, TagLib does not even parse the footer since - * it is not useful internally. However, if the flag to include a footer - * has been set in the ID3v2::Tag, TagLib will render a footer. - */ - - class TAGLIB_EXPORT Footer - { - public: - /*! - * Constructs an empty ID3v2 footer. - */ - Footer(); - /*! - * Destroys the footer. - */ - virtual ~Footer(); - - /*! - * Returns the size of the footer. Presently this is always 10 bytes. - */ - static uint size(); - - /*! - * Renders the footer based on the data in \a header. - */ - ByteVector render(const Header *header) const; - - private: - Footer(const Footer &); - Footer &operator=(const Footer &); - - class FooterPrivate; - FooterPrivate *d; - }; - - } -} -#endif diff --git a/taglib/taglib/mpeg/id3v2/id3v2frame.cpp b/taglib/taglib/mpeg/id3v2/id3v2frame.cpp deleted file mode 100644 index 3cafcff..0000000 --- a/taglib/taglib/mpeg/id3v2/id3v2frame.cpp +++ /dev/null @@ -1,844 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#if HAVE_ZLIB -#include <zlib.h> -#endif - -#include <bitset> - -#include <tdebug.h> -#include <tstringlist.h> - -#include "id3v2tag.h" -#include "id3v2frame.h" -#include "id3v2synchdata.h" -#include "tpropertymap.h" -#include "frames/textidentificationframe.h" -#include "frames/urllinkframe.h" -#include "frames/unsynchronizedlyricsframe.h" -#include "frames/commentsframe.h" -#include "frames/uniquefileidentifierframe.h" -#include "frames/unknownframe.h" - -using namespace TagLib; -using namespace ID3v2; - -class Frame::FramePrivate -{ -public: - FramePrivate() : - header(0) - {} - - ~FramePrivate() - { - delete header; - } - - Frame::Header *header; -}; - -namespace -{ - bool isValidFrameID(const ByteVector &frameID) - { - if(frameID.size() != 4) - return false; - - for(ByteVector::ConstIterator it = frameID.begin(); it != frameID.end(); it++) { - if( (*it < 'A' || *it > 'Z') && (*it < '0' || *it > '9') ) { - return false; - } - } - return true; - } -} - -//////////////////////////////////////////////////////////////////////////////// -// static methods -//////////////////////////////////////////////////////////////////////////////// - -TagLib::uint Frame::headerSize() -{ - return Header::size(); -} - -TagLib::uint Frame::headerSize(uint version) -{ - return Header::size(version); -} - -ByteVector Frame::textDelimiter(String::Type t) -{ - ByteVector d = char(0); - if(t == String::UTF16 || t == String::UTF16BE || t == String::UTF16LE) - d.append(char(0)); - return d; -} - -const String Frame::instrumentPrefix("PERFORMER:"); -const String Frame::commentPrefix("COMMENT:"); -const String Frame::lyricsPrefix("LYRICS:"); -const String Frame::urlPrefix("URL:"); - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -Frame *Frame::createTextualFrame(const String &key, const StringList &values) //static -{ - // check if the key is contained in the key<=>frameID mapping - ByteVector frameID = keyToFrameID(key); - if(!frameID.isNull()) { - if(frameID[0] == 'T'){ // text frame - TextIdentificationFrame *frame = new TextIdentificationFrame(frameID, String::UTF8); - frame->setText(values); - return frame; - } 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(String::UTF8); - frame->setDescription(key == "LYRICS" ? key : key.substr(lyricsPrefix.size())); - frame->setText(values.front()); - return frame; - } - // -URL: depending on the number of values, use WXXX or TXXX (with description=URL) - if((key == "URL" || key.startsWith(urlPrefix)) && values.size() == 1){ - UserUrlLinkFrame *frame = new UserUrlLinkFrame(String::UTF8); - frame->setDescription(key == "URL" ? key : key.substr(urlPrefix.size())); - frame->setUrl(values.front()); - return frame; - } - // -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); - 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(keyToTXXX(key), values, String::UTF8); -} - -Frame::~Frame() -{ - delete d; -} - -ByteVector Frame::frameID() const -{ - if(d->header) - return d->header->frameID(); - else - return ByteVector::null; -} - -TagLib::uint Frame::size() const -{ - if(d->header) - return d->header->frameSize(); - else - return 0; -} - -void Frame::setData(const ByteVector &data) -{ - parse(data); -} - -void Frame::setText(const String &) -{ - -} - -ByteVector Frame::render() const -{ - ByteVector fieldData = renderFields(); - d->header->setFrameSize(fieldData.size()); - ByteVector headerData = d->header->render(); - - return headerData + fieldData; -} - -//////////////////////////////////////////////////////////////////////////////// -// protected members -//////////////////////////////////////////////////////////////////////////////// - -Frame::Frame(const ByteVector &data) -{ - d = new FramePrivate; - d->header = new Header(data); -} - -Frame::Frame(Header *h) -{ - d = new FramePrivate; - d->header = h; -} - -Frame::Header *Frame::header() const -{ - return d->header; -} - -void Frame::setHeader(Header *h, bool deleteCurrent) -{ - if(deleteCurrent) - delete d->header; - - d->header = h; -} - -void Frame::parse(const ByteVector &data) -{ - if(d->header) - d->header->setData(data); - else - d->header = new Header(data); - - parseFields(fieldData(data)); -} - -ByteVector Frame::fieldData(const ByteVector &frameData) const -{ - uint headerSize = Header::size(d->header->version()); - - uint frameDataOffset = headerSize; - uint frameDataLength = size(); - - if(d->header->compression() || d->header->dataLengthIndicator()) { - frameDataLength = SynchData::toUInt(frameData.mid(headerSize, 4)); - frameDataOffset += 4; - } - -#if HAVE_ZLIB - if(d->header->compression() && - !d->header->encryption()) - { - ByteVector data(frameDataLength); - uLongf uLongTmp = frameDataLength; - ::uncompress((Bytef *) data.data(), - (uLongf *) &uLongTmp, - (Bytef *) frameData.data() + frameDataOffset, - size()); - return data; - } - else -#endif - return frameData.mid(frameDataOffset, frameDataLength); -} - -String Frame::readStringField(const ByteVector &data, String::Type encoding, int *position) -{ - int start = 0; - - if(!position) - position = &start; - - ByteVector delimiter = textDelimiter(encoding); - - int end = data.find(delimiter, *position, delimiter.size()); - - if(end < *position) - return String::null; - - 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(); - - return str; -} - -String::Type Frame::checkEncoding(const StringList &fields, String::Type encoding) // static -{ - return checkEncoding(fields, encoding, 4); -} - -String::Type Frame::checkEncoding(const StringList &fields, String::Type encoding, uint version) // static -{ - if((encoding == String::UTF8 || encoding == String::UTF16BE) && version != 4) - return String::UTF16; - - if(encoding != String::Latin1) - return encoding; - - for(StringList::ConstIterator it = fields.begin(); it != fields.end(); ++it) { - if(!(*it).isLatin1()) { - if(version == 4) { - debug("Frame::checkEncoding() -- Rendering using UTF8."); - return String::UTF8; - } - else { - debug("Frame::checkEncoding() -- Rendering using UTF16."); - return String::UTF16; - } - } - } - - return String::Latin1; -} - -String::Type Frame::checkTextEncoding(const StringList &fields, String::Type encoding) const -{ - return checkEncoding(fields, encoding, header()->version()); -} - -static const TagLib::uint frameTranslationSize = 51; -static const char *frameTranslation[][2] = { - // Text information frames - { "TALB", "ALBUM"}, - { "TBPM", "BPM" }, - { "TCOM", "COMPOSER" }, - { "TCON", "GENRE" }, - { "TCOP", "COPYRIGHT" }, - { "TDEN", "ENCODINGTIME" }, - { "TDLY", "PLAYLISTDELAY" }, - { "TDOR", "ORIGINALDATE" }, - { "TDRC", "DATE" }, - // { "TRDA", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4 - // { "TDAT", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4 - // { "TYER", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4 - // { "TIME", "DATE" }, // id3 v2.3, replaced by TDRC in v2.4 - { "TDRL", "RELEASEDATE" }, - { "TDTG", "TAGGINGDATE" }, - { "TENC", "ENCODEDBY" }, - { "TEXT", "LYRICIST" }, - { "TFLT", "FILETYPE" }, - //{ "TIPL", "INVOLVEDPEOPLE" }, handled separately - { "TIT1", "CONTENTGROUP" }, - { "TIT2", "TITLE"}, - { "TIT3", "SUBTITLE" }, - { "TKEY", "INITIALKEY" }, - { "TLAN", "LANGUAGE" }, - { "TLEN", "LENGTH" }, - //{ "TMCL", "MUSICIANCREDITS" }, handled separately - { "TMED", "MEDIA" }, - { "TMOO", "MOOD" }, - { "TOAL", "ORIGINALALBUM" }, - { "TOFN", "ORIGINALFILENAME" }, - { "TOLY", "ORIGINALLYRICIST" }, - { "TOPE", "ORIGINALARTIST" }, - { "TOWN", "OWNER" }, - { "TPE1", "ARTIST"}, - { "TPE2", "ALBUMARTIST" }, // id3's spec says 'PERFORMER', but most programs use 'ALBUMARTIST' - { "TPE3", "CONDUCTOR" }, - { "TPE4", "REMIXER" }, // could also be ARRANGER - { "TPOS", "DISCNUMBER" }, - { "TPRO", "PRODUCEDNOTICE" }, - { "TPUB", "LABEL" }, - { "TRCK", "TRACKNUMBER" }, - { "TRSN", "RADIOSTATION" }, - { "TRSO", "RADIOSTATIONOWNER" }, - { "TSOA", "ALBUMSORT" }, - { "TSOP", "ARTISTSORT" }, - { "TSOT", "TITLESORT" }, - { "TSO2", "ALBUMARTISTSORT" }, // non-standard, used by iTunes - { "TSRC", "ISRC" }, - { "TSSE", "ENCODING" }, - // URL frames - { "WCOP", "COPYRIGHTURL" }, - { "WOAF", "FILEWEBPAGE" }, - { "WOAR", "ARTISTWEBPAGE" }, - { "WOAS", "AUDIOSOURCEWEBPAGE" }, - { "WORS", "RADIOSTATIONWEBPAGE" }, - { "WPAY", "PAYMENTWEBPAGE" }, - { "WPUB", "PUBLISHERWEBPAGE" }, - //{ "WXXX", "URL"}, handled specially - // Other frames - { "COMM", "COMMENT" }, - //{ "USLT", "LYRICS" }, handled specially -}; - -static const TagLib::uint txxxFrameTranslationSize = 8; -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; - if(m.isEmpty()) - for(size_t i = 0; i < frameTranslationSize; ++i) - m[frameTranslation[i][0]] = frameTranslation[i][1]; - 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] = { - {"TRDA", "TDRC"}, // 2.3 -> 2.4 (http://en.wikipedia.org/wiki/ID3) - {"TDAT", "TDRC"}, // 2.3 -> 2.4 - {"TYER", "TDRC"}, // 2.3 -> 2.4 - {"TIME", "TDRC"}, // 2.3 -> 2.4 -}; - -Map<ByteVector,ByteVector> &deprecationMap() -{ - static Map<ByteVector,ByteVector> depMap; - if(depMap.isEmpty()) - for(TagLib::uint i = 0; i < deprecatedFramesSize; ++i) - depMap[deprecatedFrames[i][0]] = deprecatedFrames[i][1]; - return depMap; -} - -String Frame::frameIDToKey(const ByteVector &id) -{ - Map<ByteVector, String> &m = idMap(); - if(m.contains(id)) - return m[id]; - if(deprecationMap().contains(id)) - return m[deprecationMap()[id]]; - return String::null; -} - -ByteVector Frame::keyToFrameID(const String &s) -{ - static Map<String, ByteVector> m; - if(m.isEmpty()) - for(size_t i = 0; i < frameTranslationSize; ++i) - m[frameTranslation[i][1]] = frameTranslation[i][0]; - if(m.contains(s.upper())) - return m[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)) { - PropertyMap m; - m.unsupportedData().append("UNKNOWN/" + frameID()); - return m; - } - const ByteVector &id = frameID(); - // workaround until this function is virtual - if(id == "TXXX") - return dynamic_cast< const UserTextIdentificationFrame* >(this)->asProperties(); - else if(id[0] == 'T') - return dynamic_cast< const TextIdentificationFrame* >(this)->asProperties(); - else if(id == "WXXX") - return dynamic_cast< const UserUrlLinkFrame* >(this)->asProperties(); - else if(id[0] == 'W') - return dynamic_cast< const UrlLinkFrame* >(this)->asProperties(); - else if(id == "COMM") - 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; -} - -void Frame::splitProperties(const PropertyMap &original, PropertyMap &singleFrameProperties, - PropertyMap &tiplProperties, PropertyMap &tmclProperties) -{ - - singleFrameProperties.clear(); - tiplProperties.clear(); - tmclProperties.clear(); - for(PropertyMap::ConstIterator it = original.begin(); it != original.end(); ++it) { - if(TextIdentificationFrame::involvedPeopleMap().contains(it->first)) - tiplProperties.insert(it->first, it->second); - else if(it->first.startsWith(TextIdentificationFrame::instrumentPrefix)) - tmclProperties.insert(it->first, it->second); - else - singleFrameProperties.insert(it->first, it->second); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Frame::Header class -//////////////////////////////////////////////////////////////////////////////// - -class Frame::Header::HeaderPrivate -{ -public: - HeaderPrivate() : - frameSize(0), - version(4), - tagAlterPreservation(false), - fileAlterPreservation(false), - readOnly(false), - groupingIdentity(false), - compression(false), - encryption(false), - unsynchronisation(false), - dataLengthIndicator(false) - {} - - ByteVector frameID; - uint frameSize; - uint version; - - // flags - - bool tagAlterPreservation; - bool fileAlterPreservation; - bool readOnly; - bool groupingIdentity; - bool compression; - bool encryption; - bool unsynchronisation; - bool dataLengthIndicator; -}; - -//////////////////////////////////////////////////////////////////////////////// -// static members (Frame::Header) -//////////////////////////////////////////////////////////////////////////////// - -TagLib::uint Frame::Header::size() -{ - return size(4); -} - -TagLib::uint Frame::Header::size(uint version) -{ - switch(version) { - case 0: - case 1: - case 2: - return 6; - case 3: - case 4: - default: - return 10; - } -} - -//////////////////////////////////////////////////////////////////////////////// -// public members (Frame::Header) -//////////////////////////////////////////////////////////////////////////////// - -Frame::Header::Header(const ByteVector &data, bool synchSafeInts) -{ - d = new HeaderPrivate; - setData(data, synchSafeInts); -} - -Frame::Header::Header(const ByteVector &data, uint version) -{ - d = new HeaderPrivate; - setData(data, version); -} - -Frame::Header::~Header() -{ - delete d; -} - -void Frame::Header::setData(const ByteVector &data, bool synchSafeInts) -{ - setData(data, uint(synchSafeInts ? 4 : 3)); -} - -void Frame::Header::setData(const ByteVector &data, uint version) -{ - d->version = version; - - switch(version) { - case 0: - case 1: - case 2: - { - // ID3v2.2 - - if(data.size() < 3) { - debug("You must at least specify a frame ID."); - return; - } - - // Set the frame ID -- the first three bytes - - d->frameID = data.mid(0, 3); - - // If the full header information was not passed in, do not continue to the - // steps to parse the frame size and flags. - - if(data.size() < 6) { - d->frameSize = 0; - return; - } - - d->frameSize = data.toUInt(3, 3, true); - - break; - } - case 3: - { - // ID3v2.3 - - if(data.size() < 4) { - debug("You must at least specify a frame ID."); - return; - } - - // Set the frame ID -- the first four bytes - - d->frameID = data.mid(0, 4); - - // If the full header information was not passed in, do not continue to the - // steps to parse the frame size and flags. - - if(data.size() < 10) { - d->frameSize = 0; - return; - } - - // Set the size -- the frame size is the four bytes starting at byte four in - // the frame header (structure 4) - - d->frameSize = data.toUInt(4U); - - { // read the first byte of flags - std::bitset<8> flags(data[8]); - d->tagAlterPreservation = flags[7]; // (structure 3.3.1.a) - d->fileAlterPreservation = flags[6]; // (structure 3.3.1.b) - d->readOnly = flags[5]; // (structure 3.3.1.c) - } - - { // read the second byte of flags - std::bitset<8> flags(data[9]); - d->compression = flags[7]; // (structure 3.3.1.i) - d->encryption = flags[6]; // (structure 3.3.1.j) - d->groupingIdentity = flags[5]; // (structure 3.3.1.k) - } - break; - } - case 4: - default: - { - // ID3v2.4 - - if(data.size() < 4) { - debug("You must at least specify a frame ID."); - return; - } - - // Set the frame ID -- the first four bytes - - d->frameID = data.mid(0, 4); - - // If the full header information was not passed in, do not continue to the - // steps to parse the frame size and flags. - - if(data.size() < 10) { - d->frameSize = 0; - return; - } - - // Set the size -- the frame size is the four bytes starting at byte four in - // the frame header (structure 4) - - d->frameSize = SynchData::toUInt(data.mid(4, 4)); -#ifndef NO_ITUNES_HACKS - // 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.toUInt(4U); - if(isValidFrameID(data.mid(uintSize + 10, 4))) { - d->frameSize = uintSize; - } - } - } -#endif - - { // read the first byte of flags - std::bitset<8> flags(data[8]); - d->tagAlterPreservation = flags[6]; // (structure 4.1.1.a) - d->fileAlterPreservation = flags[5]; // (structure 4.1.1.b) - d->readOnly = flags[4]; // (structure 4.1.1.c) - } - - { // read the second byte of flags - std::bitset<8> flags(data[9]); - d->groupingIdentity = flags[6]; // (structure 4.1.2.h) - d->compression = flags[3]; // (structure 4.1.2.k) - d->encryption = flags[2]; // (structure 4.1.2.m) - d->unsynchronisation = flags[1]; // (structure 4.1.2.n) - d->dataLengthIndicator = flags[0]; // (structure 4.1.2.p) - } - break; - } - } -} - -ByteVector Frame::Header::frameID() const -{ - return d->frameID; -} - -void Frame::Header::setFrameID(const ByteVector &id) -{ - d->frameID = id.mid(0, 4); -} - -TagLib::uint Frame::Header::frameSize() const -{ - return d->frameSize; -} - -void Frame::Header::setFrameSize(uint size) -{ - d->frameSize = size; -} - -TagLib::uint Frame::Header::version() const -{ - return d->version; -} - -void Frame::Header::setVersion(TagLib::uint version) -{ - d->version = version; -} - -bool Frame::Header::tagAlterPreservation() const -{ - return d->tagAlterPreservation; -} - -void Frame::Header::setTagAlterPreservation(bool preserve) -{ - d->tagAlterPreservation = preserve; -} - -bool Frame::Header::fileAlterPreservation() const -{ - return d->fileAlterPreservation; -} - -bool Frame::Header::readOnly() const -{ - return d->readOnly; -} - -bool Frame::Header::groupingIdentity() const -{ - return d->groupingIdentity; -} - -bool Frame::Header::compression() const -{ - return d->compression; -} - -bool Frame::Header::encryption() const -{ - return d->encryption; -} - -bool Frame::Header::unsycronisation() const -{ - return unsynchronisation(); -} - -bool Frame::Header::unsynchronisation() const -{ - return d->unsynchronisation; -} - -bool Frame::Header::dataLengthIndicator() const -{ - return d->dataLengthIndicator; -} - -ByteVector Frame::Header::render() const -{ - ByteVector flags(2, char(0)); // just blank for the moment - - ByteVector v = d->frameID + - (d->version == 3 - ? ByteVector::fromUInt(d->frameSize) - : SynchData::fromUInt(d->frameSize)) + - flags; - - return v; -} - -bool Frame::Header::frameAlterPreservation() const -{ - return fileAlterPreservation(); -} diff --git a/taglib/taglib/mpeg/id3v2/id3v2frame.h b/taglib/taglib/mpeg/id3v2/id3v2frame.h deleted file mode 100644 index 3e257d4..0000000 --- a/taglib/taglib/mpeg/id3v2/id3v2frame.h +++ /dev/null @@ -1,518 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_ID3V2FRAME_H -#define TAGLIB_ID3V2FRAME_H - -#include "tstring.h" -#include "tbytevector.h" -#include "taglib_export.h" - -namespace TagLib { - - class StringList; - class PropertyMap; - - namespace ID3v2 { - - class Tag; - class FrameFactory; - - //! ID3v2 frame implementation - - /*! - * This class is the main ID3v2 frame implementation. In ID3v2, a tag is - * split between a collection of frames (which are in turn split into fields - * (Structure, <a href="id3v2-structure.html#4">4</a>) - * (<a href="id3v2-frames.html">Frames</a>). This class provides an API for - * gathering information about and modifying ID3v2 frames. Funtionallity - * specific to a given frame type is handed in one of the many subclasses. - */ - - class TAGLIB_EXPORT Frame - { - friend class Tag; - friend class FrameFactory; - - public: - - /*! - * Creates a textual frame which corresponds to a single key in the PropertyMap - * interface. These are all (User)TextIdentificationFrames except TIPL and TMCL, - * all (User)URLLinkFrames, CommentsFrames, and UnsynchronizedLyricsFrame. - */ - static Frame *createTextualFrame(const String &key, const StringList &values); - - /*! - * Destroys this Frame instance. - */ - virtual ~Frame(); - - /*! - * Returns the Frame ID (Structure, <a href="id3v2-structure.html#4">4</a>) - * (Frames, <a href="id3v2-frames.html#4">4</a>) - */ - ByteVector frameID() const; - - /*! - * Returns the size of the frame. - */ - uint size() const; - - /*! - * Returns the size of the frame header - * - * \deprecated This is only accurate for ID3v2.3 or ID3v2.4. Please use - * the call below which accepts an ID3v2 version number. In the next - * non-binary compatible release this will be made into a non-static - * member that checks the internal ID3v2 version. - */ - static uint headerSize(); // BIC: remove and make non-static - - /*! - * Returns the size of the frame header for the given ID3v2 version. - * - * \deprecated Please see the explanation above. - */ - static uint headerSize(uint version); // BIC: remove and make non-static - - /*! - * Sets the data that will be used as the frame. Since the length is not - * known before the frame has been parsed, this should just be a pointer to - * the first byte of the frame. It will determine the length internally - * and make that available through size(). - */ - void setData(const ByteVector &data); - - /*! - * Set the text of frame in the sanest way possible. This should only be - * reimplemented in frames where there is some logical mapping to text. - * - * \note If the frame type supports multiple text encodings, this will not - * change the text encoding of the frame; the string will be converted to - * that frame's encoding. Please use the specific APIs of the frame types - * to set the encoding if that is desired. - */ - virtual void setText(const String &text); - - /*! - * This returns the textual representation of the data in the frame. - * Subclasses must reimplement this method to provide a string - * representation of the frame's data. - */ - virtual String toString() const = 0; - - /*! - * Render the frame back to its binary format in a ByteVector. - */ - ByteVector render() const; - - /*! - * Returns the text delimiter that is used between fields for the string - * type \a t. - */ - static ByteVector textDelimiter(String::Type t); - - /*! - * The string with which an instrument name is prefixed to build a key in a PropertyMap; - * used to translate PropertyMaps to TMCL frames. In the current implementation, this - * is "PERFORMER:". - */ - static const String instrumentPrefix; - /*! - * The PropertyMap key prefix which triggers the use of a COMM frame instead of a TXXX - * frame for a non-standard key. In the current implementation, this is "COMMENT:". - */ - static const String commentPrefix; - /*! - * The PropertyMap key prefix which triggers the use of a USLT frame instead of a TXXX - * frame for a non-standard key. In the current implementation, this is "LYRICS:". - */ - static const String lyricsPrefix; - /*! - * The PropertyMap key prefix which triggers the use of a WXXX frame instead of a TXX - * frame for a non-standard key. In the current implementation, this is "URL:". - */ - static const String urlPrefix; - - protected: - class Header; - - /*! - * Constructs an ID3v2 frame using \a data to read the header information. - * All other processing of \a data should be handled in a subclass. - * - * \note This need not contain anything more than a frame ID, but - * \e must constain at least that. - */ - explicit Frame(const ByteVector &data); - - /*! - * This creates an Frame using the header \a h. - * - * The ownership of this header will be assigned to the frame and the - * header will be deleted when the frame is destroyed. - */ - Frame(Header *h); - - /*! - * Returns a pointer to the frame header. - */ - Header *header() const; - - /*! - * Sets the header to \a h. If \a deleteCurrent is true, this will free - * the memory of the current header. - * - * The ownership of this header will be assigned to the frame and the - * header will be deleted when the frame is destroyed. - */ - void setHeader(Header *h, bool deleteCurrent = true); - - /*! - * Called by setData() to parse the frame data. It makes this information - * available through the public API. - */ - void parse(const ByteVector &data); - - /*! - * Called by parse() to parse the field data. It makes this information - * available through the public API. This must be overridden by the - * subclasses. - */ - virtual void parseFields(const ByteVector &data) = 0; - - /*! - * Render the field data back to a binary format in a ByteVector. This - * must be overridden by subclasses. - */ - virtual ByteVector renderFields() const = 0; - - /*! - * Returns a ByteVector containing the field data given the frame data. - * This correctly adjusts for the header size plus any additional frame - * data that's specified in the frame header flags. - */ - ByteVector fieldData(const ByteVector &frameData) const; - - /*! - * Reads a String of type \a encodiong from the ByteVector \a data. If \a - * position is passed in it is used both as the starting point and is - * updated to replect the position just after the string that has been read. - * This is useful for reading strings sequentially. - */ - String readStringField(const ByteVector &data, String::Type encoding, - int *positon = 0); - - /*! - * Checks a the list of string values to see if they can be used with the - * specified encoding and returns the recommended encoding. - */ - // BIC: remove and make non-static - static String::Type checkEncoding(const StringList &fields, - String::Type encoding); - - /*! - * Checks a the list of string values to see if they can be used with the - * specified encoding and returns the recommended encoding. This method - * also checks the ID3v2 version and makes sure the encoding can be used - * in the specified version. - */ - // BIC: remove and make non-static - static String::Type checkEncoding(const StringList &fields, - String::Type encoding, uint version); - - /*! - * Checks a the list of string values to see if they can be used with the - * specified encoding and returns the recommended encoding. This method - * also checks the ID3v2 version and makes sure the encoding can be used - * in the version specified by the frame's header. - */ - String::Type checkTextEncoding(const StringList &fields, - String::Type encoding) const; - - - /*! - * Parses the contents of this frame as PropertyMap. If that fails, the returend - * PropertyMap will be empty, and its unsupportedData() will contain this frame's - * ID. - * BIC: Will be a virtual function in future releases. - */ - PropertyMap asProperties() const; - - /*! - * Returns an appropriate ID3 frame ID for the given free-form tag key. This method - * will return ByteVector::null if no specialized translation is found. - */ - static ByteVector keyToFrameID(const String &); - - /*! - * Returns a free-form tag name for the given ID3 frame ID. Note that this does not work - * for general frame IDs such as TXXX or WXXX; in such a case String::null is returned. - */ - 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 - * \a singleFrameProperties, \a tiplProperties, and \a tmclProperties, such that: - * - \a singleFrameProperties contains only of keys which can be represented with - * exactly one ID3 frame per key. In the current implementation - * this is everything except for the fixed "involved people" keys and keys of the - * form "TextIdentificationFrame::instrumentPrefix" + "instrument", which are - * mapped to a TMCL frame. - * - \a tiplProperties will consist of those keys that are present in - * TextIdentificationFrame::involvedPeopleMap() - * - \a tmclProperties contains the "musician credits" keys which should be mapped - * to a TMCL frame - */ - static void splitProperties(const PropertyMap &original, PropertyMap &singleFrameProperties, - PropertyMap &tiplProperties, PropertyMap &tmclProperties); - - private: - Frame(const Frame &); - Frame &operator=(const Frame &); - - class FramePrivate; - friend class FramePrivate; - FramePrivate *d; - }; - - //! ID3v2 frame header implementation - - /*! - * The ID3v2 Frame Header (Structure, <a href="id3v2-structure.html#4">4</a>) - * - * Every ID3v2::Frame has an associated header that gives some general - * properties of the frame and also makes it possible to identify the frame - * type. - * - * As such when reading an ID3v2 tag ID3v2::FrameFactory first creates the - * frame headers and then creates the appropriate Frame subclass based on - * the type and attaches the header. - */ - - class TAGLIB_EXPORT Frame::Header - { - public: - /*! - * Construct a Frame Header based on \a data. \a data must at least - * contain a 4 byte frame ID, and optionally can contain flag data and the - * frame size. i.e. Just the frame id -- "TALB" -- is a valid value. - * - * \deprecated Please use the constructor below that accepts a version - * number. - */ - Header(const ByteVector &data, bool synchSafeInts); - - /*! - * Construct a Frame Header based on \a data. \a data must at least - * contain a 4 byte frame ID, and optionally can contain flag data and the - * frame size. i.e. Just the frame id -- "TALB" -- is a valid value. - * - * \a version should be the ID3v2 version of the tag. - */ - explicit Header(const ByteVector &data, uint version = 4); - - /*! - * Destroys this Header instance. - */ - virtual ~Header(); - - /*! - * Sets the data for the Header. - * - * \deprecated Please use the version below that accepts an ID3v2 version - * number. - */ - void setData(const ByteVector &data, bool synchSafeInts); - - /*! - * Sets the data for the Header. \a version should indicate the ID3v2 - * version number of the tag that this frame is contained in. - */ - void setData(const ByteVector &data, uint version = 4); - - /*! - * Returns the Frame ID (Structure, <a href="id3v2-structure.html#4">4</a>) - * (Frames, <a href="id3v2-frames.html#4">4</a>) - */ - ByteVector frameID() const; - - /*! - * Sets the frame's ID to \a id. Only the first four bytes of \a id will - * be used. - * - * \warning This method should in general be avoided. It exists simply to - * provide a mechanism for transforming frames from a deprecated frame type - * to a newer one -- i.e. TYER to TDRC from ID3v2.3 to ID3v2.4. - */ - void setFrameID(const ByteVector &id); - - /*! - * Returns the size of the frame data portion, as set when setData() was - * called or set explicitly via setFrameSize(). - */ - uint frameSize() const; - - /*! - * Sets the size of the frame data portion. - */ - void setFrameSize(uint size); - - /*! - * Returns the ID3v2 version of the header, as passed in from the - * construction of the header or set via setVersion(). - */ - uint version() const; - - /*! - * Sets the ID3v2 version of the header, changing has impact on the - * correct parsing/rendering of frame data. - */ - void setVersion(uint version); - - /*! - * Returns the size of the frame header in bytes. - * - * \deprecated Please use the version of this method that accepts a - * version. This is only accurate for ID3v2.3 and ID3v2.4. This will be - * removed in the next binary incompatible release (2.0) and will be - * replaced with a non-static method that checks the frame version. - */ - static uint size(); - - /*! - * Returns the size of the frame header in bytes for the ID3v2 version - * that's given. - * - * \deprecated Please see the explanation in the version above. - */ - static uint size(uint version); - - /*! - * Returns true if the flag for tag alter preservation is set. - * - * The semantics are a little backwards from what would seem natural - * (setting the preservation flag to throw away the frame), but this - * follows the ID3v2 standard. - * - * \see setTagAlterPreservation() - */ - bool tagAlterPreservation() const; - - /*! - * Sets the flag for preservation of this frame if the tag is set. If - * this is set to true the frame will not be written when the tag is - * saved. - * - * The semantics are a little backwards from what would seem natural - * (setting the preservation flag to throw away the frame), but this - * follows the ID3v2 standard. - * - * \see tagAlterPreservation() - */ - void setTagAlterPreservation(bool discard); - - /*! - * Returns true if the flag for file alter preservation is set. - * - * \note This flag is currently ignored internally in TagLib. - */ - bool fileAlterPreservation() const; - - /*! - * Returns true if the frame is meant to be read only. - * - * \note This flag is currently ignored internally in TagLib. - */ - bool readOnly() const; - - /*! - * Returns true if the flag for the grouping identifity is set. - * - * \note This flag is currently ignored internally in TagLib. - */ - bool groupingIdentity() const; - - /*! - * Returns true if compression is enabled for this frame. - * - * \note This flag is currently ignored internally in TagLib. - */ - bool compression() const; - - /*! - * Returns true if encryption is enabled for this frame. - * - * \note This flag is currently ignored internally in TagLib. - */ - bool encryption() const; - -#ifndef DO_NOT_DOCUMENT - bool unsycronisation() const; -#endif - - /*! - * Returns true if unsynchronisation is enabled for this frame. - */ - bool unsynchronisation() const; - - /*! - * Returns true if the flag for a data length indicator is set. - */ - bool dataLengthIndicator() const; - - /*! - * Render the Header back to binary format in a ByteVector. - */ - ByteVector render() const; - - /*! - * \deprecated - */ - bool frameAlterPreservation() const; - - private: - Header(const Header &); - Header &operator=(const Header &); - - class HeaderPrivate; - HeaderPrivate *d; - }; - - } -} - -#endif diff --git a/taglib/taglib/mpeg/id3v2/id3v2framefactory.cpp b/taglib/taglib/mpeg/id3v2/id3v2framefactory.cpp deleted file mode 100644 index 3371ca7..0000000 --- a/taglib/taglib/mpeg/id3v2/id3v2framefactory.cpp +++ /dev/null @@ -1,458 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <tdebug.h> - -#include "id3v2framefactory.h" -#include "id3v2synchdata.h" -#include "id3v1genres.h" - -#include "frames/attachedpictureframe.h" -#include "frames/commentsframe.h" -#include "frames/relativevolumeframe.h" -#include "frames/textidentificationframe.h" -#include "frames/uniquefileidentifierframe.h" -#include "frames/unknownframe.h" -#include "frames/generalencapsulatedobjectframe.h" -#include "frames/urllinkframe.h" -#include "frames/unsynchronizedlyricsframe.h" -#include "frames/popularimeterframe.h" -#include "frames/privateframe.h" -#include "frames/ownershipframe.h" - -using namespace TagLib; -using namespace ID3v2; - -class FrameFactory::FrameFactoryPrivate -{ -public: - FrameFactoryPrivate() : - defaultEncoding(String::Latin1), - useDefaultEncoding(false) {} - - String::Type defaultEncoding; - bool useDefaultEncoding; - - template <class T> void setTextEncoding(T *frame) - { - if(useDefaultEncoding) - frame->setTextEncoding(defaultEncoding); - } -}; - -FrameFactory FrameFactory::factory; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -FrameFactory *FrameFactory::instance() -{ - return &factory; -} - -Frame *FrameFactory::createFrame(const ByteVector &data, bool synchSafeInts) const -{ - return createFrame(data, uint(synchSafeInts ? 4 : 3)); -} - -Frame *FrameFactory::createFrame(const ByteVector &data, uint version) const -{ - Header tagHeader; - tagHeader.setMajorVersion(version); - return createFrame(data, &tagHeader); -} - -Frame *FrameFactory::createFrame(const ByteVector &origData, Header *tagHeader) const -{ - ByteVector data = origData; - uint version = tagHeader->majorVersion(); - Frame::Header *header = new Frame::Header(data, version); - ByteVector frameID = header->frameID(); - - // 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) || - header->frameSize() <= uint(header->dataLengthIndicator() ? 4 : 0) || - header->frameSize() > data.size()) - { - delete header; - 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 < '0' || *it > '9') ) { - delete header; - return 0; - } - } - - if(version > 3 && (tagHeader->unsynchronisation() || header->unsynchronisation())) { - // Data lengths are not part of the encoded data, but since they are synch-safe - // integers they will be never actually encoded. - ByteVector frameData = data.mid(Frame::Header::size(version), header->frameSize()); - frameData = SynchData::decode(frameData); - data = data.mid(0, Frame::Header::size(version)) + frameData; - } - - // TagLib doesn't mess with encrypted frames, so just treat them - // as unknown frames. - -#if !defined(HAVE_ZLIB) || HAVE_ZLIB == 0 - if(header->compression()) { - debug("Compressed frames are currently not supported."); - return new UnknownFrame(data, header); - } -#endif - if(header->encryption()) { - debug("Encrypted frames are currently not supported."); - return new UnknownFrame(data, header); - } - - if(!updateFrame(header)) { - header->setTagAlterPreservation(true); - return new UnknownFrame(data, header); - } - - // updateFrame() might have updated the frame ID. - - frameID = header->frameID(); - - // This is where things get necissarily nasty. Here we determine which - // Frame subclass (or if none is found simply an Frame) based - // on the frame ID. Since there are a lot of possibilities, that means - // a lot of if blocks. - - // Text Identification (frames 4.2) - - if(frameID.startsWith("T")) { - - TextIdentificationFrame *f = frameID != "TXXX" - ? new TextIdentificationFrame(data, header) - : new UserTextIdentificationFrame(data, header); - - d->setTextEncoding(f); - - if(frameID == "TCON") - updateGenre(f); - - return f; - } - - // Comments (frames 4.10) - - if(frameID == "COMM") { - CommentsFrame *f = new CommentsFrame(data, header); - d->setTextEncoding(f); - return f; - } - - // Attached Picture (frames 4.14) - - if(frameID == "APIC") { - AttachedPictureFrame *f = new AttachedPictureFrame(data, header); - d->setTextEncoding(f); - return f; - } - - // ID3v2.2 Attached Picture - - if(frameID == "PIC") { - AttachedPictureFrame *f = new AttachedPictureFrameV22(data, header); - d->setTextEncoding(f); - return f; - } - - // Relative Volume Adjustment (frames 4.11) - - if(frameID == "RVA2") - return new RelativeVolumeFrame(data, header); - - // Unique File Identifier (frames 4.1) - - if(frameID == "UFID") - return new UniqueFileIdentifierFrame(data, header); - - // General Encapsulated Object (frames 4.15) - - if(frameID == "GEOB") { - GeneralEncapsulatedObjectFrame *f = new GeneralEncapsulatedObjectFrame(data, header); - d->setTextEncoding(f); - return f; - } - - // URL link (frames 4.3) - - if(frameID.startsWith("W")) { - if(frameID != "WXXX") { - return new UrlLinkFrame(data, header); - } - else { - UserUrlLinkFrame *f = new UserUrlLinkFrame(data, header); - d->setTextEncoding(f); - return f; - } - } - - // Unsynchronized lyric/text transcription (frames 4.8) - - if(frameID == "USLT") { - UnsynchronizedLyricsFrame *f = new UnsynchronizedLyricsFrame(data, header); - if(d->useDefaultEncoding) - f->setTextEncoding(d->defaultEncoding); - return f; - } - - // Popularimeter (frames 4.17) - - if(frameID == "POPM") - return new PopularimeterFrame(data, header); - - // Private (frames 4.27) - - 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); -} - -String::Type FrameFactory::defaultTextEncoding() const -{ - return d->defaultEncoding; -} - -void FrameFactory::setDefaultTextEncoding(String::Type encoding) -{ - d->useDefaultEncoding = true; - d->defaultEncoding = encoding; -} - -//////////////////////////////////////////////////////////////////////////////// -// protected members -//////////////////////////////////////////////////////////////////////////////// - -FrameFactory::FrameFactory() -{ - d = new FrameFactoryPrivate; -} - -FrameFactory::~FrameFactory() -{ - delete d; -} - -bool FrameFactory::updateFrame(Frame::Header *header) const -{ - TagLib::ByteVector frameID = header->frameID(); - - switch(header->version()) { - - case 2: // ID3v2.2 - { - if(frameID == "CRM" || - frameID == "EQU" || - frameID == "LNK" || - frameID == "RVA" || - frameID == "TIM" || - frameID == "TSI" || - frameID == "TDA") - { - debug("ID3v2.4 no longer supports the frame type " + String(frameID) + - ". It will be discarded from the tag."); - return false; - } - - // ID3v2.2 only used 3 bytes for the frame ID, so we need to convert all of - // the frames to their 4 byte ID3v2.4 equivalent. - - convertFrame("BUF", "RBUF", header); - convertFrame("CNT", "PCNT", header); - convertFrame("COM", "COMM", header); - convertFrame("CRA", "AENC", header); - convertFrame("ETC", "ETCO", header); - convertFrame("GEO", "GEOB", header); - convertFrame("IPL", "TIPL", header); - convertFrame("MCI", "MCDI", header); - convertFrame("MLL", "MLLT", header); - convertFrame("POP", "POPM", header); - convertFrame("REV", "RVRB", header); - convertFrame("SLT", "SYLT", header); - convertFrame("STC", "SYTC", header); - convertFrame("TAL", "TALB", header); - convertFrame("TBP", "TBPM", header); - convertFrame("TCM", "TCOM", header); - convertFrame("TCO", "TCON", header); - convertFrame("TCP", "TCMP", header); - convertFrame("TCR", "TCOP", header); - convertFrame("TDY", "TDLY", header); - convertFrame("TEN", "TENC", header); - convertFrame("TFT", "TFLT", header); - convertFrame("TKE", "TKEY", header); - convertFrame("TLA", "TLAN", header); - convertFrame("TLE", "TLEN", header); - convertFrame("TMT", "TMED", header); - convertFrame("TOA", "TOAL", header); - convertFrame("TOF", "TOFN", header); - convertFrame("TOL", "TOLY", header); - convertFrame("TOR", "TDOR", header); - convertFrame("TOT", "TOAL", header); - convertFrame("TP1", "TPE1", header); - convertFrame("TP2", "TPE2", header); - convertFrame("TP3", "TPE3", header); - convertFrame("TP4", "TPE4", header); - convertFrame("TPA", "TPOS", header); - convertFrame("TPB", "TPUB", header); - convertFrame("TRC", "TSRC", header); - convertFrame("TRD", "TDRC", header); - convertFrame("TRK", "TRCK", header); - convertFrame("TS2", "TSO2", header); - convertFrame("TSA", "TSOA", header); - convertFrame("TSC", "TSOC", header); - convertFrame("TSP", "TSOP", header); - convertFrame("TSS", "TSSE", header); - convertFrame("TST", "TSOT", header); - convertFrame("TT1", "TIT1", header); - convertFrame("TT2", "TIT2", header); - convertFrame("TT3", "TIT3", header); - convertFrame("TXT", "TOLY", header); - convertFrame("TXX", "TXXX", header); - convertFrame("TYE", "TDRC", header); - convertFrame("UFI", "UFID", header); - convertFrame("ULT", "USLT", header); - convertFrame("WAF", "WOAF", header); - convertFrame("WAR", "WOAR", header); - convertFrame("WAS", "WOAS", header); - convertFrame("WCM", "WCOM", header); - convertFrame("WCP", "WCOP", header); - convertFrame("WPB", "WPUB", header); - convertFrame("WXX", "WXXX", header); - - break; - } - - case 3: // ID3v2.3 - { - if(frameID == "EQUA" || - frameID == "RVAD" || - frameID == "TIME" || - frameID == "TRDA" || - frameID == "TSIZ" || - frameID == "TDAT") - { - debug("ID3v2.4 no longer supports the frame type " + String(frameID) + - ". It will be discarded from the tag."); - return false; - } - - convertFrame("TORY", "TDOR", header); - convertFrame("TYER", "TDRC", header); - convertFrame("IPLS", "TIPL", header); - - break; - } - - default: - - // This should catch a typo that existed in TagLib up to and including - // version 1.1 where TRDC was used for the year rather than TDRC. - - convertFrame("TRDC", "TDRC", header); - break; - } - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -void FrameFactory::convertFrame(const char *from, const char *to, - Frame::Header *header) const -{ - if(header->frameID() != from) - return; - - // debug("ID3v2.4 no longer supports the frame type " + String(from) + " It has" + - // "been converted to the type " + String(to) + "."); - - header->setFrameID(to); -} - -void FrameFactory::updateGenre(TextIdentificationFrame *frame) const -{ - StringList fields = frame->fieldList(); - StringList newfields; - - for(StringList::Iterator it = fields.begin(); it != fields.end(); ++it) { - String s = *it; - int end = s.find(")"); - - if(s.startsWith("(") && end > 0) { - // "(12)Genre" - String text = s.substr(end + 1); - bool ok; - int number = s.substr(1, end - 1).toInt(&ok); - if(ok && number >= 0 && number <= 255 && !(ID3v1::genre(number) == text)) - newfields.append(s.substr(1, end - 1)); - if(!text.isEmpty()) - newfields.append(text); - } - else { - // "Genre" or "12" - newfields.append(s); - } - } - - if(newfields.isEmpty()) - fields.append(String::null); - - frame->setText(newfields); - -} diff --git a/taglib/taglib/mpeg/id3v2/id3v2framefactory.h b/taglib/taglib/mpeg/id3v2/id3v2framefactory.h deleted file mode 100644 index 762d7eb..0000000 --- a/taglib/taglib/mpeg/id3v2/id3v2framefactory.h +++ /dev/null @@ -1,166 +0,0 @@ - /*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_ID3V2FRAMEFACTORY_H -#define TAGLIB_ID3V2FRAMEFACTORY_H - -#include "taglib_export.h" -#include "tbytevector.h" -#include "id3v2frame.h" -#include "id3v2header.h" - -namespace TagLib { - - namespace ID3v2 { - - class TextIdentificationFrame; - - //! A factory for creating ID3v2 frames during parsing - - /*! - * This factory abstracts away the frame creation process and instantiates - * the appropriate ID3v2::Frame subclasses based on the contents of the - * data. - * - * Reimplementing this factory is the key to adding support for frame types - * not directly supported by TagLib to your application. To do so you would - * subclass this factory reimplement createFrame(). Then by setting your - * factory to be the default factory in ID3v2::Tag constructor or with - * MPEG::File::setID3v2FrameFactory() you can implement behavior that will - * allow for new ID3v2::Frame subclasses (also provided by you) to be used. - * - * This implements both <i>abstract factory</i> and <i>singleton</i> patterns - * of which more information is available on the web and in software design - * textbooks (Notably <i>Design Patters</i>). - * - * \note You do not need to use this factory to create new frames to add to - * an ID3v2::Tag. You can instantiate frame subclasses directly (with new) - * and add them to a tag using ID3v2::Tag::addFrame() - * - * \see ID3v2::Tag::addFrame() - */ - - class TAGLIB_EXPORT FrameFactory - { - public: - static FrameFactory *instance(); - /*! - * Create a frame based on \a data. \a synchSafeInts should only be set - * false if we are parsing an old tag (v2.3 or older) that does not support - * synchsafe ints. - * - * \deprecated Please use the method below that accepts a ID3v2::Header - * instance in new code. - */ - Frame *createFrame(const ByteVector &data, bool synchSafeInts) const; - - /*! - * Create a frame based on \a data. \a version should indicate the ID3v2 - * version of the tag. As ID3v2.4 is the most current version of the - * standard 4 is the default. - * - * \deprecated Please use the method below that accepts a ID3v2::Header - * instance in new code. - */ - Frame *createFrame(const ByteVector &data, uint version = 4) const; - - /*! - * Create a frame based on \a data. \a tagHeader should be a valid - * ID3v2::Header instance. - */ - // BIC: make virtual - Frame *createFrame(const ByteVector &data, Header *tagHeader) const; - - /*! - * Returns the default text encoding for text frames. If setTextEncoding() - * has not been explicitly called this will only be used for new text - * frames. However, if this value has been set explicitly all frames will be - * converted to this type (unless it's explitly set differently for the - * individual frame) when being rendered. - * - * \see setDefaultTextEncoding() - */ - String::Type defaultTextEncoding() const; - - /*! - * Set the default text encoding for all text frames that are created to - * \a encoding. If no value is set the frames with either default to the - * encoding type that was parsed and new frames default to Latin1. - * - * Valid string types for ID3v2 tags are Latin1, UTF8, UTF16 and UTF16BE. - * - * \see defaultTextEncoding() - */ - void setDefaultTextEncoding(String::Type encoding); - - protected: - /*! - * Constructs a frame factory. Because this is a singleton this method is - * protected, but may be used for subclasses. - */ - FrameFactory(); - - /*! - * Destroys the frame factory. - */ - virtual ~FrameFactory(); - - /*! - * This method checks for compliance to the current ID3v2 standard (2.4) - * and does nothing in the common case. However if a frame is found that - * is not compatible with the current standard, this method either updates - * the frame or indicates that it should be discarded. - * - * This method with return true (with or without changes to the frame) if - * this frame should be kept or false if it should be discarded. - * - * See the id3v2.4.0-changes.txt document for further information. - */ - virtual bool updateFrame(Frame::Header *header) const; - - private: - FrameFactory(const FrameFactory &); - FrameFactory &operator=(const FrameFactory &); - - /*! - * This method is used internally to convert a frame from ID \a from to ID - * \a to. If the frame matches the \a from pattern and converts the frame - * ID in the \a header or simply does nothing if the frame ID does not match. - */ - void convertFrame(const char *from, const char *to, - Frame::Header *header) const; - - void updateGenre(TextIdentificationFrame *frame) const; - - static FrameFactory factory; - - class FrameFactoryPrivate; - FrameFactoryPrivate *d; - }; - - } -} - -#endif diff --git a/taglib/taglib/mpeg/id3v2/id3v2header.cpp b/taglib/taglib/mpeg/id3v2/id3v2header.cpp deleted file mode 100644 index ad6b3aa..0000000 --- a/taglib/taglib/mpeg/id3v2/id3v2header.cpp +++ /dev/null @@ -1,243 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <iostream> -#include <bitset> - -#include <tstring.h> -#include <tdebug.h> - -#include "id3v2header.h" -#include "id3v2footer.h" -#include "id3v2synchdata.h" - -using namespace TagLib; -using namespace ID3v2; - -class Header::HeaderPrivate -{ -public: - HeaderPrivate() : majorVersion(4), - revisionNumber(0), - unsynchronisation(false), - extendedHeader(false), - experimentalIndicator(false), - footerPresent(false), - tagSize(0) {} - - ~HeaderPrivate() {} - - uint majorVersion; - uint revisionNumber; - - bool unsynchronisation; - bool extendedHeader; - bool experimentalIndicator; - bool footerPresent; - - uint tagSize; - - static const uint size = 10; -}; - -//////////////////////////////////////////////////////////////////////////////// -// static members -//////////////////////////////////////////////////////////////////////////////// - -TagLib::uint Header::size() -{ - return HeaderPrivate::size; -} - -ByteVector Header::fileIdentifier() -{ - return ByteVector::fromCString("ID3"); -} - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -Header::Header() -{ - d = new HeaderPrivate; -} - -Header::Header(const ByteVector &data) -{ - d = new HeaderPrivate; - parse(data); -} - -Header::~Header() -{ - delete d; -} - -TagLib::uint Header::majorVersion() const -{ - return d->majorVersion; -} - -void Header::setMajorVersion(TagLib::uint version) -{ - d->majorVersion = version; -} - -TagLib::uint Header::revisionNumber() const -{ - return d->revisionNumber; -} - -bool Header::unsynchronisation() const -{ - return d->unsynchronisation; -} - -bool Header::extendedHeader() const -{ - return d->extendedHeader; -} - -bool Header::experimentalIndicator() const -{ - return d->experimentalIndicator; -} - -bool Header::footerPresent() const -{ - return d->footerPresent; -} - -TagLib::uint Header::tagSize() const -{ - return d->tagSize; -} - -TagLib::uint Header::completeTagSize() const -{ - if(d->footerPresent) - return d->tagSize + d->size + Footer::size(); - else - return d->tagSize + d->size; -} - -void Header::setTagSize(uint s) -{ - d->tagSize = s; -} - -void Header::setData(const ByteVector &data) -{ - parse(data); -} - -ByteVector Header::render() const -{ - ByteVector v; - - // add the file identifier -- "ID3" - v.append(fileIdentifier()); - - // add the version number -- we always render a 2.4.0 tag regardless of what - // the tag originally was. - - v.append(char(majorVersion())); - v.append(char(0)); - - // Currently we don't actually support writing extended headers, footers or - // unsynchronized tags, make sure that the flags are set accordingly. - - d->extendedHeader = false; - d->footerPresent = false; - d->unsynchronisation = false; - - // render and add the flags - std::bitset<8> flags; - - flags[7] = d->unsynchronisation; - flags[6] = d->extendedHeader; - flags[5] = d->experimentalIndicator; - flags[4] = d->footerPresent; - - v.append(char(flags.to_ulong())); - - // add the size - v.append(SynchData::fromUInt(d->tagSize)); - - return v; -} - -//////////////////////////////////////////////////////////////////////////////// -// protected members -//////////////////////////////////////////////////////////////////////////////// - -void Header::parse(const ByteVector &data) -{ - if(data.size() < size()) - return; - - - // do some sanity checking -- even in ID3v2.3.0 and less the tag size is a - // synch-safe integer, so all bytes must be less than 128. If this is not - // true then this is an invalid tag. - - // note that we're doing things a little out of order here -- the size is - // later in the bytestream than the version - - ByteVector sizeData = data.mid(6, 4); - - if(sizeData.size() != 4) { - d->tagSize = 0; - debug("TagLib::ID3v2::Header::parse() - The tag size as read was 0 bytes!"); - return; - } - - for(ByteVector::Iterator it = sizeData.begin(); it != sizeData.end(); it++) { - if(uchar(*it) >= 128) { - d->tagSize = 0; - debug("TagLib::ID3v2::Header::parse() - One of the size bytes in the id3v2 header was greater than the allowed 128."); - return; - } - } - - // The first three bytes, data[0..2], are the File Identifier, "ID3". (structure 3.1 "file identifier") - - // Read the version number from the fourth and fifth bytes. - d->majorVersion = data[3]; // (structure 3.1 "major version") - d->revisionNumber = data[4]; // (structure 3.1 "revision number") - - // Read the flags, the first four bits of the sixth byte. - std::bitset<8> flags(data[5]); - - d->unsynchronisation = flags[7]; // (structure 3.1.a) - d->extendedHeader = flags[6]; // (structure 3.1.b) - d->experimentalIndicator = flags[5]; // (structure 3.1.c) - d->footerPresent = flags[4]; // (structure 3.1.d) - - // Get the size from the remaining four bytes (read above) - - d->tagSize = SynchData::toUInt(sizeData); // (structure 3.1 "size") -} diff --git a/taglib/taglib/mpeg/id3v2/id3v2header.h b/taglib/taglib/mpeg/id3v2/id3v2header.h deleted file mode 100644 index 307ba96..0000000 --- a/taglib/taglib/mpeg/id3v2/id3v2header.h +++ /dev/null @@ -1,175 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_ID3V2HEADER_H -#define TAGLIB_ID3V2HEADER_H - -#include "tbytevector.h" -#include "taglib_export.h" - -namespace TagLib { - - namespace ID3v2 { - - //! An implementation of ID3v2 headers - - /*! - * This class implements ID3v2 headers. It attempts to follow, both - * semantically and programatically, the structure specified in - * the ID3v2 standard. The API is based on the properties of ID3v2 headers - * specified there. If any of the terms used in this documentation are - * unclear please check the specification in the linked section. - * (Structure, <a href="id3v2-structure.html#3.1">3.1</a>) - */ - - class TAGLIB_EXPORT Header - { - public: - /*! - * Constructs an empty ID3v2 header. - */ - Header(); - - /*! - * Constructs an ID3v2 header based on \a data. parse() is called - * immediately. - */ - Header(const ByteVector &data); - - /*! - * Destroys the header. - */ - virtual ~Header(); - - /*! - * Returns the major version number. (Note: This is the 4, not the 2 in - * ID3v2.4.0. The 2 is implied.) - */ - uint majorVersion() const; - - /*! - * Set the the major version number to \a version. (Note: This is - * the 4, not the 2 in ID3v2.4.0. The 2 is implied.) - * \see majorVersion() - * - * \note This is used by the internal parser; this will not change the - * version which is written and in general should not be called by API - * users. - */ - void setMajorVersion(uint version); - - /*! - * Returns the revision number. (Note: This is the 0, not the 4 in - * ID3v2.4.0. The 2 is implied.) - */ - uint revisionNumber() const; - - /*! - * Returns true if unsynchronisation has been applied to all frames. - */ - bool unsynchronisation() const; - - /*! - * Returns true if an extended header is present in the tag. - */ - bool extendedHeader() const; - - /*! - * Returns true if the experimental indicator flag is set. - */ - bool experimentalIndicator() const; - - /*! - * Returns true if a footer is present in the tag. - */ - bool footerPresent() const; - /*! - * Returns the tag size in bytes. This is the size of the frame content. - * The size of the \e entire tag will be this plus the header size (10 - * bytes) and, if present, the footer size (potentially another 10 bytes). - * - * \note This is the value as read from the header to which TagLib attempts - * to provide an API to; it was not a design decision on the part of TagLib - * to not include the mentioned portions of the tag in the \e size. - * - * \see completeTagSize() - */ - uint tagSize() const; - - /*! - * Returns the tag size, including the header and, if present, the footer - * size. - * - * \see tagSize() - */ - uint completeTagSize() const; - - /*! - * Set the tag size to \a s. - * \see tagSize() - */ - void setTagSize(uint s); - - /*! - * Returns the size of the header. Presently this is always 10 bytes. - */ - static uint size(); - - /*! - * Returns the string used to identify and ID3v2 tag inside of a file. - * Presently this is always "ID3". - */ - static ByteVector fileIdentifier(); - - /*! - * Sets the data that will be used as the header. 10 bytes, starting from - * the beginning of \a data are used. - */ - void setData(const ByteVector &data); - - /*! - * Renders the Header back to binary format. - */ - ByteVector render() const; - - protected: - /*! - * Called by setData() to parse the header data. It makes this information - * available through the public API. - */ - void parse(const ByteVector &data); - - private: - Header(const Header &); - Header &operator=(const Header &); - - class HeaderPrivate; - HeaderPrivate *d; - }; - - } -} - -#endif diff --git a/taglib/taglib/mpeg/id3v2/id3v2synchdata.cpp b/taglib/taglib/mpeg/id3v2/id3v2synchdata.cpp deleted file mode 100644 index 4acfd91..0000000 --- a/taglib/taglib/mpeg/id3v2/id3v2synchdata.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <iostream> - -#include "id3v2synchdata.h" - -using namespace TagLib; -using namespace ID3v2; - -TagLib::uint SynchData::toUInt(const ByteVector &data) -{ - uint sum = 0; - bool notSynchSafe = false; - int last = data.size() > 4 ? 3 : data.size() - 1; - - for(int i = 0; i <= last; i++) { - if(data[i] & 0x80) { - notSynchSafe = true; - break; - } - - sum |= (data[i] & 0x7f) << ((last - i) * 7); - } - - if(notSynchSafe) { - // 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. - if(data.size() >= 4) { - sum = data.toUInt(0, true); - } - else { - ByteVector tmp(data); - tmp.resize(4); - sum = tmp.toUInt(0, true); - } - } - - return sum; -} - -ByteVector SynchData::fromUInt(uint value) -{ - ByteVector v(4, 0); - - for(int i = 0; i < 4; i++) - v[i] = uchar(value >> ((3 - i) * 7) & 0x7f); - - return v; -} - -ByteVector SynchData::decode(const ByteVector &data) -{ - ByteVector result = data; - - ByteVector pattern(2, char(0)); - pattern[0] = '\xFF'; - pattern[1] = '\x00'; - - return result.replace(pattern, '\xFF'); -} diff --git a/taglib/taglib/mpeg/id3v2/id3v2synchdata.h b/taglib/taglib/mpeg/id3v2/id3v2synchdata.h deleted file mode 100644 index 4a1f596..0000000 --- a/taglib/taglib/mpeg/id3v2/id3v2synchdata.h +++ /dev/null @@ -1,70 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_ID3V2SYNCHDATA_H -#define TAGLIB_ID3V2SYNCHDATA_H - -#include "tbytevector.h" -#include "taglib.h" - -namespace TagLib { - - namespace ID3v2 { - - //! A few functions for ID3v2 synch safe integer conversion - - /*! - * In the ID3v2.4 standard most integer values are encoded as "synch safe" - * integers which are encoded in such a way that they will not give false - * MPEG syncs and confuse MPEG decoders. This namespace provides some - * methods for converting to and from these values to ByteVectors for - * things rendering and parsing ID3v2 data. - */ - - namespace SynchData - { - /*! - * This returns the unsigned integer value of \a data where \a data is a - * ByteVector that contains a \e synchsafe integer (Structure, - * <a href="id3v2-structure.html#6.2">6.2</a>). The default \a length of - * 4 is used if another value is not specified. - */ - TAGLIB_EXPORT uint toUInt(const ByteVector &data); - - /*! - * Returns a 4 byte (32 bit) synchsafe integer based on \a value. - */ - TAGLIB_EXPORT ByteVector fromUInt(uint value); - - /*! - * Convert the data from unsynchronized data to its original format. - */ - TAGLIB_EXPORT ByteVector decode(const ByteVector &input); - } - - } -} - -#endif diff --git a/taglib/taglib/mpeg/id3v2/id3v2tag.cpp b/taglib/taglib/mpeg/id3v2/id3v2tag.cpp deleted file mode 100644 index 57637a3..0000000 --- a/taglib/taglib/mpeg/id3v2/id3v2tag.cpp +++ /dev/null @@ -1,732 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <tfile.h> - -#include "id3v2tag.h" -#include "id3v2header.h" -#include "id3v2extendedheader.h" -#include "id3v2footer.h" -#include "id3v2synchdata.h" -#include "tbytevector.h" -#include "id3v1genres.h" -#include "tpropertymap.h" -#include <tdebug.h> - -#include "frames/textidentificationframe.h" -#include "frames/commentsframe.h" -#include "frames/urllinkframe.h" -#include "frames/uniquefileidentifierframe.h" -#include "frames/unsynchronizedlyricsframe.h" -#include "frames/unknownframe.h" - -using namespace TagLib; -using namespace ID3v2; - -class ID3v2::Tag::TagPrivate -{ -public: - TagPrivate() : file(0), tagOffset(-1), extendedHeader(0), footer(0), paddingSize(0) - { - frameList.setAutoDelete(true); - } - ~TagPrivate() - { - delete extendedHeader; - delete footer; - } - - File *file; - long tagOffset; - const FrameFactory *factory; - - Header header; - ExtendedHeader *extendedHeader; - Footer *footer; - - int paddingSize; - - 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 -//////////////////////////////////////////////////////////////////////////////// - -ID3v2::Tag::Tag() : TagLib::Tag() -{ - d = new TagPrivate; - d->factory = FrameFactory::instance(); -} - -ID3v2::Tag::Tag(File *file, long tagOffset, const FrameFactory *factory) : - TagLib::Tag() -{ - d = new TagPrivate; - - d->file = file; - d->tagOffset = tagOffset; - d->factory = factory; - - read(); -} - -ID3v2::Tag::~Tag() -{ - delete d; -} - - -String ID3v2::Tag::title() const -{ - if(!d->frameListMap["TIT2"].isEmpty()) - return d->frameListMap["TIT2"].front()->toString(); - return String::null; -} - -String ID3v2::Tag::artist() const -{ - if(!d->frameListMap["TPE1"].isEmpty()) - return d->frameListMap["TPE1"].front()->toString(); - return String::null; -} - -String ID3v2::Tag::album() const -{ - if(!d->frameListMap["TALB"].isEmpty()) - return d->frameListMap["TALB"].front()->toString(); - return String::null; -} - -String ID3v2::Tag::comment() const -{ - const FrameList &comments = d->frameListMap["COMM"]; - - if(comments.isEmpty()) - return String::null; - - for(FrameList::ConstIterator it = comments.begin(); it != comments.end(); ++it) - { - CommentsFrame *frame = dynamic_cast<CommentsFrame *>(*it); - - if(frame && frame->description().isEmpty()) - return (*it)->toString(); - } - - return comments.front()->toString(); -} - -String ID3v2::Tag::genre() const -{ - // TODO: In the next major version (TagLib 2.0) a list of multiple genres - // should be separated by " / " instead of " ". For the moment to keep - // the behavior the same as released versions it is being left with " ". - - if(d->frameListMap["TCON"].isEmpty() || - !dynamic_cast<TextIdentificationFrame *>(d->frameListMap["TCON"].front())) - { - return String::null; - } - - // ID3v2.4 lists genres as the fields in its frames field list. If the field - // is simply a number it can be assumed that it is an ID3v1 genre number. - // Here was assume that if an ID3v1 string is present that it should be - // appended to the genre string. Multiple fields will be appended as the - // string is built. - - TextIdentificationFrame *f = static_cast<TextIdentificationFrame *>( - d->frameListMap["TCON"].front()); - - StringList fields = f->fieldList(); - - StringList genres; - - for(StringList::Iterator it = fields.begin(); it != fields.end(); ++it) { - - if((*it).isEmpty()) - continue; - - bool ok; - int number = (*it).toInt(&ok); - if(ok && number >= 0 && number <= 255) { - *it = ID3v1::genre(number); - } - - if(std::find(genres.begin(), genres.end(), *it) == genres.end()) - genres.append(*it); - } - - return genres.toString(); -} - -TagLib::uint ID3v2::Tag::year() const -{ - if(!d->frameListMap["TDRC"].isEmpty()) - return d->frameListMap["TDRC"].front()->toString().substr(0, 4).toInt(); - return 0; -} - -TagLib::uint ID3v2::Tag::track() const -{ - if(!d->frameListMap["TRCK"].isEmpty()) - return d->frameListMap["TRCK"].front()->toString().toInt(); - return 0; -} - -void ID3v2::Tag::setTitle(const String &s) -{ - setTextFrame("TIT2", s); -} - -void ID3v2::Tag::setArtist(const String &s) -{ - setTextFrame("TPE1", s); -} - -void ID3v2::Tag::setAlbum(const String &s) -{ - setTextFrame("TALB", s); -} - -void ID3v2::Tag::setComment(const String &s) -{ - if(s.isEmpty()) { - removeFrames("COMM"); - return; - } - - if(!d->frameListMap["COMM"].isEmpty()) - d->frameListMap["COMM"].front()->setText(s); - else { - CommentsFrame *f = new CommentsFrame(d->factory->defaultTextEncoding()); - addFrame(f); - f->setText(s); - } -} - -void ID3v2::Tag::setGenre(const String &s) -{ - if(s.isEmpty()) { - removeFrames("TCON"); - return; - } - - // iTunes can't handle correctly encoded ID3v2.4 numerical genres. Just use - // strings until iTunes sucks less. - -#ifdef NO_ITUNES_HACKS - - int index = ID3v1::genreIndex(s); - - if(index != 255) - setTextFrame("TCON", String::number(index)); - else - setTextFrame("TCON", s); - -#else - - setTextFrame("TCON", s); - -#endif -} - -void ID3v2::Tag::setYear(uint i) -{ - if(i <= 0) { - removeFrames("TDRC"); - return; - } - setTextFrame("TDRC", String::number(i)); -} - -void ID3v2::Tag::setTrack(uint i) -{ - if(i <= 0) { - removeFrames("TRCK"); - return; - } - setTextFrame("TRCK", String::number(i)); -} - -bool ID3v2::Tag::isEmpty() const -{ - return d->frameList.isEmpty(); -} - -Header *ID3v2::Tag::header() const -{ - return &(d->header); -} - -ExtendedHeader *ID3v2::Tag::extendedHeader() const -{ - return d->extendedHeader; -} - -Footer *ID3v2::Tag::footer() const -{ - return d->footer; -} - -const FrameListMap &ID3v2::Tag::frameListMap() const -{ - return d->frameListMap; -} - -const FrameList &ID3v2::Tag::frameList() const -{ - return d->frameList; -} - -const FrameList &ID3v2::Tag::frameList(const ByteVector &frameID) const -{ - return d->frameListMap[frameID]; -} - -void ID3v2::Tag::addFrame(Frame *frame) -{ - d->frameList.append(frame); - d->frameListMap[frame->frameID()].append(frame); -} - -void ID3v2::Tag::removeFrame(Frame *frame, bool del) -{ - // remove the frame from the frame list - FrameList::Iterator it = d->frameList.find(frame); - d->frameList.erase(it); - - // ...and from the frame list map - it = d->frameListMap[frame->frameID()].find(frame); - d->frameListMap[frame->frameID()].erase(it); - - // ...and delete as desired - if(del) - delete frame; -} - -void ID3v2::Tag::removeFrames(const ByteVector &id) -{ - FrameList l = d->frameListMap[id]; - for(FrameList::Iterator it = l.begin(); it != l.end(); ++it) - removeFrame(*it, true); -} - -PropertyMap ID3v2::Tag::properties() const -{ - PropertyMap properties; - for(FrameList::ConstIterator it = frameList().begin(); it != frameList().end(); ++it) { - PropertyMap props = (*it)->asProperties(); - properties.merge(props); - } - return properties; -} - -void ID3v2::Tag::removeUnsupportedProperties(const StringList &properties) -{ - for(StringList::ConstIterator it = properties.begin(); it != properties.end(); ++it){ - if(it->startsWith("UNKNOWN/")) { - String frameID = it->substr(String("UNKNOWN/").size()); - if(frameID.size() != 4) - continue; // invalid specification - ByteVector id = frameID.data(String::Latin1); - // delete all unknown frames of given type - FrameList l = frameList(id); - for(FrameList::ConstIterator fit = l.begin(); fit != l.end(); fit++) - if (dynamic_cast<const UnknownFrame *>(*fit) != 0) - removeFrame(*fit); - } - else if(it->size() == 4){ - ByteVector id = it->data(String::Latin1); - removeFrames(id); - } - else { - ByteVector id = it->substr(0,4).data(String::Latin1); - if(it->size() <= 5) - continue; // invalid specification - String description = it->substr(5); - Frame *frame = 0; - if(id == "TXXX") - frame = UserTextIdentificationFrame::find(this, description); - else if(id == "WXXX") - frame = UserUrlLinkFrame::find(this, description); - else if(id == "COMM") - 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); - } - } -} - -PropertyMap ID3v2::Tag::setProperties(const PropertyMap &origProps) -{ - FrameList framesToDelete; - // we split up the PropertyMap into the "normal" keys and the "complicated" ones, - // which are those according to TIPL or TMCL frames. - PropertyMap properties; - PropertyMap tiplProperties; - PropertyMap tmclProperties; - Frame::splitProperties(origProps, properties, tiplProperties, tmclProperties); - for(FrameListMap::ConstIterator it = frameListMap().begin(); it != frameListMap().end(); ++it){ - for(FrameList::ConstIterator lit = it->second.begin(); lit != it->second.end(); ++lit){ - PropertyMap frameProperties = (*lit)->asProperties(); - if(it->first == "TIPL") { - if (tiplProperties != frameProperties) - framesToDelete.append(*lit); - else - tiplProperties.erase(frameProperties); - } else if(it->first == "TMCL") { - if (tmclProperties != frameProperties) - framesToDelete.append(*lit); - else - tmclProperties.erase(frameProperties); - } else if(!properties.contains(frameProperties)) - framesToDelete.append(*lit); - else - properties.erase(frameProperties); - } - } - for(FrameList::ConstIterator it = framesToDelete.begin(); it != framesToDelete.end(); ++it) - removeFrame(*it); - - // now create remaining frames: - // start with the involved people list (TIPL) - if(!tiplProperties.isEmpty()) - addFrame(TextIdentificationFrame::createTIPLFrame(tiplProperties)); - // proceed with the musician credit list (TMCL) - if(!tmclProperties.isEmpty()) - addFrame(TextIdentificationFrame::createTMCLFrame(tmclProperties)); - // now create the "one key per frame" frames - for(PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it) - addFrame(Frame::createTextualFrame(it->first, it->second)); - return PropertyMap(); // ID3 implements the complete PropertyMap interface, so an empty map is returned -} - -ByteVector ID3v2::Tag::render() const -{ - return render(4); -} - -void ID3v2::Tag::downgradeFrames(FrameList *frames, FrameList *newFrames) const -{ - const char *unsupportedFrames[] = { - "ASPI", "EQU2", "RVA2", "SEEK", "SIGN", "TDRL", "TDTG", - "TMOO", "TPRO", "TSOA", "TSOT", "TSST", "TSOP", 0 - }; - ID3v2::TextIdentificationFrame *frameTDOR = 0; - ID3v2::TextIdentificationFrame *frameTDRC = 0; - ID3v2::TextIdentificationFrame *frameTIPL = 0; - ID3v2::TextIdentificationFrame *frameTMCL = 0; - for(FrameList::Iterator it = d->frameList.begin(); it != d->frameList.end(); it++) { - ID3v2::Frame *frame = *it; - ByteVector frameID = frame->header()->frameID(); - for(int i = 0; unsupportedFrames[i]; i++) { - if(frameID == unsupportedFrames[i]) { - debug("A frame that is not supported in ID3v2.3 \'" - + String(frameID) + "\' has been discarded"); - frame = 0; - break; - } - } - if(frame && frameID == "TDOR") { - frameTDOR = dynamic_cast<ID3v2::TextIdentificationFrame *>(frame); - frame = 0; - } - if(frame && frameID == "TDRC") { - frameTDRC = dynamic_cast<ID3v2::TextIdentificationFrame *>(frame); - frame = 0; - } - if(frame && frameID == "TIPL") { - frameTIPL = dynamic_cast<ID3v2::TextIdentificationFrame *>(frame); - frame = 0; - } - if(frame && frameID == "TMCL") { - frameTMCL = dynamic_cast<ID3v2::TextIdentificationFrame *>(frame); - frame = 0; - } - if(frame) { - frames->append(frame); - } - } - if(frameTDOR) { - String content = frameTDOR->toString(); - if(content.size() >= 4) { - ID3v2::TextIdentificationFrame *frameTORY = new ID3v2::TextIdentificationFrame("TORY", String::Latin1); - frameTORY->setText(content.substr(0, 4)); - frames->append(frameTORY); - newFrames->append(frameTORY); - } - } - if(frameTDRC) { - String content = frameTDRC->toString(); - if(content.size() >= 4) { - ID3v2::TextIdentificationFrame *frameTYER = new ID3v2::TextIdentificationFrame("TYER", String::Latin1); - frameTYER->setText(content.substr(0, 4)); - frames->append(frameTYER); - newFrames->append(frameTYER); - if(content.size() >= 10 && content[4] == '-' && content[7] == '-') { - ID3v2::TextIdentificationFrame *frameTDAT = new ID3v2::TextIdentificationFrame("TDAT", String::Latin1); - frameTDAT->setText(content.substr(8, 2) + content.substr(5, 2)); - frames->append(frameTDAT); - newFrames->append(frameTDAT); - if(content.size() >= 16 && content[10] == 'T' && content[13] == ':') { - ID3v2::TextIdentificationFrame *frameTIME = new ID3v2::TextIdentificationFrame("TIME", String::Latin1); - frameTIME->setText(content.substr(11, 2) + content.substr(14, 2)); - frames->append(frameTIME); - newFrames->append(frameTIME); - } - } - } - } - if(frameTIPL || frameTMCL) { - ID3v2::TextIdentificationFrame *frameIPLS = new ID3v2::TextIdentificationFrame("IPLS", String::Latin1); - StringList people; - if(frameTMCL) { - StringList v24People = frameTMCL->fieldList(); - for(uint i = 0; i + 1 < v24People.size(); i += 2) { - people.append(v24People[i]); - people.append(v24People[i+1]); - } - } - if(frameTIPL) { - StringList v24People = frameTIPL->fieldList(); - for(uint i = 0; i + 1 < v24People.size(); i += 2) { - people.append(v24People[i]); - people.append(v24People[i+1]); - } - } - frameIPLS->setText(people); - frames->append(frameIPLS); - newFrames->append(frameIPLS); - } -} - - -ByteVector ID3v2::Tag::render(int version) const -{ - // We need to render the "tag data" first so that we have to correct size to - // render in the tag's header. The "tag data" -- everything that is included - // in ID3v2::Header::tagSize() -- includes the extended header, frames and - // padding, but does not include the tag's header or footer. - - ByteVector tagData; - - if(version != 3 && version != 4) { - debug("Unknown ID3v2 version, using ID3v2.4"); - version = 4; - } - - // TODO: Render the extended header. - - // Loop through the frames rendering them and adding them to the tagData. - - FrameList newFrames; - newFrames.setAutoDelete(true); - - FrameList frameList; - if(version == 4) { - frameList = d->frameList; - } - else { - downgradeFrames(&frameList, &newFrames); - } - - for(FrameList::Iterator it = frameList.begin(); it != frameList.end(); it++) { - (*it)->header()->setVersion(version); - if((*it)->header()->frameID().size() != 4) { - debug("A frame of unsupported or unknown type \'" - + String((*it)->header()->frameID()) + "\' has been discarded"); - continue; - } - if(!(*it)->header()->tagAlterPreservation()) - tagData.append((*it)->render()); - } - - // Compute the amount of padding, and append that to tagData. - - uint paddingSize = 0; - uint originalSize = d->header.tagSize(); - - if(tagData.size() < originalSize) - paddingSize = originalSize - tagData.size(); - else - paddingSize = 1024; - - tagData.append(ByteVector(paddingSize, char(0))); - - // Set the version and data size. - d->header.setMajorVersion(version); - d->header.setTagSize(tagData.size()); - - // TODO: This should eventually include d->footer->render(). - 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 -//////////////////////////////////////////////////////////////////////////////// - -void ID3v2::Tag::read() -{ - if(d->file && d->file->isOpen()) { - - d->file->seek(d->tagOffset); - d->header.setData(d->file->readBlock(Header::size())); - - // if the tag size is 0, then this is an invalid tag (tags must contain at - // least one frame) - - if(d->header.tagSize() == 0) - return; - - parse(d->file->readBlock(d->header.tagSize())); - } -} - -void ID3v2::Tag::parse(const ByteVector &origData) -{ - ByteVector data = origData; - - if(d->header.unsynchronisation() && d->header.majorVersion() <= 3) - data = SynchData::decode(data); - - uint frameDataPosition = 0; - uint frameDataLength = data.size(); - - // check for extended header - - if(d->header.extendedHeader()) { - if(!d->extendedHeader) - d->extendedHeader = new ExtendedHeader; - d->extendedHeader->setData(data); - if(d->extendedHeader->size() <= data.size()) { - frameDataPosition += d->extendedHeader->size(); - frameDataLength -= d->extendedHeader->size(); - } - } - - // check for footer -- we don't actually need to parse it, as it *must* - // contain the same data as the header, but we do need to account for its - // size. - - if(d->header.footerPresent() && Footer::size() <= frameDataLength) - frameDataLength -= Footer::size(); - - // parse frames - - // Make sure that there is at least enough room in the remaining frame data for - // a frame header. - - while(frameDataPosition < frameDataLength - Frame::headerSize(d->header.majorVersion())) { - - // If the next data is position is 0, assume that we've hit the padding - // portion of the frame data. - - if(data.at(frameDataPosition) == 0) { - if(d->header.footerPresent()) { - debug("Padding *and* a footer found. This is not allowed by the spec."); - } - - d->paddingSize = frameDataLength - frameDataPosition; - return; - } - - Frame *frame = d->factory->createFrame(data.mid(frameDataPosition), - &d->header); - - if(!frame) - return; - - // Checks to make sure that frame parsed correctly. - - if(frame->size() <= 0) { - delete frame; - return; - } - - frameDataPosition += frame->size() + Frame::headerSize(d->header.majorVersion()); - addFrame(frame); - } -} - -void ID3v2::Tag::setTextFrame(const ByteVector &id, const String &value) -{ - if(value.isEmpty()) { - removeFrames(id); - return; - } - - if(!d->frameListMap[id].isEmpty()) - d->frameListMap[id].front()->setText(value); - else { - const String::Type encoding = d->factory->defaultTextEncoding(); - TextIdentificationFrame *f = new TextIdentificationFrame(id, encoding); - addFrame(f); - f->setText(value); - } -} diff --git a/taglib/taglib/mpeg/id3v2/id3v2tag.h b/taglib/taglib/mpeg/id3v2/id3v2tag.h deleted file mode 100644 index 5fd5c1f..0000000 --- a/taglib/taglib/mpeg/id3v2/id3v2tag.h +++ /dev/null @@ -1,412 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_ID3V2TAG_H -#define TAGLIB_ID3V2TAG_H - -#include "tag.h" -#include "tbytevector.h" -#include "tstring.h" -#include "tlist.h" -#include "tmap.h" -#include "taglib_export.h" - -#include "id3v2framefactory.h" - -namespace TagLib { - - class File; - - //! An ID3v2 implementation - - /*! - * This is a relatively complete and flexible framework for working with ID3v2 - * tags. - * - * \see ID3v2::Tag - */ - - namespace ID3v2 { - - class Header; - class ExtendedHeader; - class Footer; - - 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 - - /*! - * This is the main class in the ID3v2 implementation. It serves two - * functions. This first, as is obvious from the public API, is to provide a - * container for the other ID3v2 related classes. In addition, through the - * read() and parse() protected methods, it provides the most basic level of - * parsing. In these methods the ID3v2 tag is extracted from the file and - * split into data components. - * - * ID3v2 tags have several parts, TagLib attempts to provide an interface - * for them all. header(), footer() and extendedHeader() corespond to those - * data structures in the ID3v2 standard and the APIs for the classes that - * they return attempt to reflect this. - * - * Also ID3v2 tags are built up from a list of frames, which are in turn - * have a header and a list of fields. TagLib provides two ways of accessing - * the list of frames that are in a given ID3v2 tag. The first is simply - * via the frameList() method. This is just a list of pointers to the frames. - * The second is a map from the frame type -- i.e. "COMM" for comments -- and - * a list of frames of that type. (In some cases ID3v2 allows for multiple - * frames of the same type, hence this being a map to a list rather than just - * a map to an individual frame.) - * - * More information on the structure of frames can be found in the ID3v2::Frame - * class. - * - * read() and parse() pass binary data to the other ID3v2 class structures, - * they do not handle parsing of flags or fields, for instace. Those are - * handled by similar functions within those classes. - * - * \note All pointers to data structures within the tag will become invalid - * when the tag is destroyed. - * - * \warning Dealing with the nasty details of ID3v2 is not for the faint of - * heart and should not be done without much meditation on the spec. It's - * rather long, but if you're planning on messing with this class and others - * that deal with the details of ID3v2 (rather than the nice, safe, abstract - * TagLib::Tag and friends), it's worth your time to familiarize yourself - * with said spec (which is distrubuted with the TagLib sources). TagLib - * tries to do most of the work, but with a little luck, you can still - * convince it to generate invalid ID3v2 tags. The APIs for ID3v2 assume a - * working knowledge of ID3v2 structure. You're been warned. - */ - - class TAGLIB_EXPORT Tag : public TagLib::Tag - { - public: - /*! - * Constructs an empty ID3v2 tag. - * - * \note You must create at least one frame for this tag to be valid. - */ - Tag(); - - /*! - * Constructs an ID3v2 tag read from \a file starting at \a tagOffset. - * \a factory specifies which FrameFactory will be used for the - * construction of new frames. - * - * \note You should be able to ignore the \a factory parameter in almost - * all situations. You would want to specify your own FrameFactory - * subclass in the case that you are extending TagLib to support additional - * frame types, which would be incorperated into your factory. - * - * \see FrameFactory - */ - Tag(File *file, long tagOffset, - const FrameFactory *factory = FrameFactory::instance()); - - /*! - * Destroys this Tag instance. - */ - virtual ~Tag(); - - // Reimplementations. - - virtual String title() const; - virtual String artist() const; - virtual String album() const; - virtual String comment() const; - virtual String genre() const; - virtual uint year() const; - virtual 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 bool isEmpty() const; - - /*! - * Returns a pointer to the tag's header. - */ - Header *header() const; - - /*! - * Returns a pointer to the tag's extended header or null if there is no - * extended header. - */ - ExtendedHeader *extendedHeader() const; - - /*! - * Returns a pointer to the tag's footer or null if there is no footer. - * - * \deprecated I don't see any reason to keep this around since there's - * nothing useful to be retrieved from the footer, but well, again, I'm - * prone to change my mind, so this gets to stay around until near a - * release. - */ - Footer *footer() const; - - /*! - * Returns a reference to the frame list map. This is an FrameListMap of - * all of the frames in the tag. - * - * This is the most convenient structure for accessing the tag's frames. - * Many frame types allow multiple instances of the same frame type so this - * is a map of lists. In most cases however there will only be a single - * frame of a certain type. - * - * Let's say for instance that you wanted to access the frame for total - * beats per minute -- the TBPM frame. - * - * \code - * TagLib::MPEG::File f("foo.mp3"); - * - * // Check to make sure that it has an ID3v2 tag - * - * if(f.ID3v2Tag()) { - * - * // Get the list of frames for a specific frame type - * - * TagLib::ID3v2::FrameList l = f.ID3v2Tag()->frameListMap()["TBPM"]; - * - * if(!l.isEmpty()) - * std::cout << l.front()->toString() << std::endl; - * } - * - * \endcode - * - * \warning You should not modify this data structure directly, instead - * use addFrame() and removeFrame(). - * - * \see frameList() - */ - const FrameListMap &frameListMap() const; - - /*! - * Returns a reference to the frame list. This is an FrameList of all of - * the frames in the tag in the order that they were parsed. - * - * This can be useful if for example you want iterate over the tag's frames - * in the order that they occur in the tag. - * - * \warning You should not modify this data structure directly, instead - * use addFrame() and removeFrame(). - */ - const FrameList &frameList() const; - - /*! - * Returns the frame list for frames with the id \a frameID or an empty - * list if there are no frames of that type. This is just a convenience - * and is equivalent to: - * - * \code - * frameListMap()[frameID]; - * \endcode - * - * \see frameListMap() - */ - const FrameList &frameList(const ByteVector &frameID) const; - - /*! - * Add a frame to the tag. At this point the tag takes ownership of - * the frame and will handle freeing its memory. - * - * \note Using this method will invalidate any pointers on the list - * returned by frameList() - */ - void addFrame(Frame *frame); - - /*! - * Remove a frame from the tag. If \a del is true the frame's memory - * will be freed; if it is false, it must be deleted by the user. - * - * \note Using this method will invalidate any pointers on the list - * returned by frameList() - */ - void removeFrame(Frame *frame, bool del = true); - - /*! - * Remove all frames of type \a id from the tag and free their memory. - * - * \note Using this method will invalidate any pointers on the list - * returned by frameList() - */ - void removeFrames(const ByteVector &id); - - /*! - * Implements the unified property interface -- export function. - * This function does some work to translate the hard-specified ID3v2 - * frame types into a free-form string-to-stringlist PropertyMap: - * - if ID3v2 frame ID is known by Frame::frameIDToKey(), the returned - * key is used - * - if the frame ID is "TXXX" (user text frame), the description() is - * used as key - * - if the frame ID is "WXXX" (user url frame), - * - if the description is empty or "URL", the key "URL" is used - * - otherwise, the key "URL:<description>" is used; - * - if the frame ID is "COMM" (comments frame), - * - if the description is empty or "COMMENT", the key "COMMENT" - * is used - * - otherwise, the key "COMMENT:<description>" is used; - * - if the frame ID is "USLT" (unsynchronized lyrics), - * - if the description is empty or "LYRICS", the key "LYRICS" is used - * - otherwise, the key "LYRICS:<description>" is used; - * - if the frame ID is "TIPL" (involved peoples list), and if all the - * roles defined in the frame are known in TextIdentificationFrame::involvedPeopleMap(), - * then "<role>=<name>" will be contained in the returned obejct for each - * - if the frame ID is "TMCL" (musician credit list), then - * "PERFORMER:<instrument>=<name>" will be contained in the returned - * PropertyMap for each defined musician - * In any other case, the unsupportedData() of the returned object will contain - * the frame's ID and, in case of a frame ID which is allowed to appear more than - * once, the description, separated by a "/". - * - */ - PropertyMap properties() const; - - /*! - * Removes unsupported frames given by \a properties. The elements of - * \a properties must be taken from properties().unsupportedData(); they - * are of one of the following forms: - * - a four-character frame ID, if the ID3 specification allows only one - * frame with that ID (thus, the frame is uniquely determined) - * - frameID + "/" + description(), when the ID is one of "TXXX", "WXXX", - * "COMM", or "USLT", - * - "UNKNOWN/" + frameID, for frames that could not be parsed by TagLib. - * In that case, *all* unknown frames with the given ID will be removed. - */ - void removeUnsupportedProperties(const StringList &properties); - - /*! - * Implements the unified property interface -- import function. - * See the comments in properties(). - */ - PropertyMap setProperties(const PropertyMap &); - - /*! - * Render the tag back to binary data, suitable to be written to disk. - */ - ByteVector render() const; - - /*! - * Render the tag back to binary data, suitable to be written to disk. - * - * The \a version parameter specifies the version of the rendered - * ID3v2 tag. It can be either 4 or 3. - */ - // 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: - /*! - * Reads data from the file specified in the constructor. It does basic - * parsing of the data in the largest chunks. It partitions the tag into - * the Header, the body of the tag (which contains the ExtendedHeader and - * frames) and Footer. - */ - void read(); - - /*! - * This is called by read to parse the body of the tag. It determines if an - * extended header exists and adds frames to the FrameListMap. - */ - void parse(const ByteVector &data); - - /*! - * Sets the value of the text frame with the Frame ID \a id to \a value. - * If the frame does not exist, it is created. - */ - void setTextFrame(const ByteVector &id, const String &value); - - void downgradeFrames(FrameList *existingFrames, FrameList *newFrames) const; - - private: - Tag(const Tag &); - Tag &operator=(const Tag &); - - class TagPrivate; - TagPrivate *d; - }; - - } -} - -#endif diff --git a/taglib/taglib/mpeg/mpegfile.cpp b/taglib/taglib/mpeg/mpegfile.cpp deleted file mode 100644 index f765bef..0000000 --- a/taglib/taglib/mpeg/mpegfile.cpp +++ /dev/null @@ -1,663 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <tagunion.h> -#include <id3v2tag.h> -#include <id3v2header.h> -#include <id3v1tag.h> -#include <apefooter.h> -#include <apetag.h> -#include <tdebug.h> - -#include <bitset> - -#include "mpegfile.h" -#include "mpegheader.h" -#include "tpropertymap.h" - -using namespace TagLib; - -namespace -{ - enum { ID3v2Index = 0, APEIndex = 1, ID3v1Index = 2 }; -} - -class MPEG::File::FilePrivate -{ -public: - FilePrivate(ID3v2::FrameFactory *frameFactory = ID3v2::FrameFactory::instance()) : - ID3v2FrameFactory(frameFactory), - ID3v2Location(-1), - ID3v2OriginalSize(0), - APELocation(-1), - APEFooterLocation(-1), - APEOriginalSize(0), - ID3v1Location(-1), - hasID3v2(false), - hasID3v1(false), - hasAPE(false), - properties(0) - { - - } - - ~FilePrivate() - { - delete properties; - } - - const ID3v2::FrameFactory *ID3v2FrameFactory; - - long ID3v2Location; - uint ID3v2OriginalSize; - - long APELocation; - long APEFooterLocation; - uint APEOriginalSize; - - long ID3v1Location; - - TagUnion tag; - - // These indicate whether the file *on disk* has these tags, not if - // this data structure does. This is used in computing offsets. - - bool hasID3v2; - bool hasID3v1; - bool hasAPE; - - Properties *properties; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -MPEG::File::File(FileName file, bool readProperties, - Properties::ReadStyle propertiesStyle) : TagLib::File(file) -{ - d = new FilePrivate; - - if(isOpen()) - read(readProperties, propertiesStyle); -} - -MPEG::File::File(FileName file, ID3v2::FrameFactory *frameFactory, - bool readProperties, Properties::ReadStyle propertiesStyle) : - TagLib::File(file) -{ - d = new FilePrivate(frameFactory); - - if(isOpen()) - read(readProperties, propertiesStyle); -} - -MPEG::File::File(IOStream *stream, ID3v2::FrameFactory *frameFactory, - bool readProperties, Properties::ReadStyle propertiesStyle) : - TagLib::File(stream) -{ - d = new FilePrivate(frameFactory); - - if(isOpen()) - read(readProperties, propertiesStyle); -} - -MPEG::File::~File() -{ - delete d; -} - -TagLib::Tag *MPEG::File::tag() const -{ - return &d->tag; -} - -PropertyMap MPEG::File::properties() const -{ - // once Tag::properties() is virtual, this case distinction could actually be done - // within TagUnion. - if(d->hasID3v2) - return d->tag.access<ID3v2::Tag>(ID3v2Index, false)->properties(); - if(d->hasAPE) - return d->tag.access<APE::Tag>(APEIndex, false)->properties(); - if(d->hasID3v1) - return d->tag.access<ID3v1::Tag>(ID3v1Index, false)->properties(); - return PropertyMap(); -} - -void MPEG::File::removeUnsupportedProperties(const StringList &properties) -{ - if(d->hasID3v2) - d->tag.access<ID3v2::Tag>(ID3v2Index, false)->removeUnsupportedProperties(properties); - else if(d->hasAPE) - d->tag.access<APE::Tag>(APEIndex, false)->removeUnsupportedProperties(properties); - else if(d->hasID3v1) - d->tag.access<ID3v1::Tag>(ID3v1Index, false)->removeUnsupportedProperties(properties); -} - -PropertyMap MPEG::File::setProperties(const PropertyMap &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 -{ - return d->properties; -} - -bool MPEG::File::save() -{ - return save(AllTags); -} - -bool MPEG::File::save(int tags) -{ - return save(tags, true); -} - -bool MPEG::File::save(int tags, bool stripOthers) -{ - return save(tags, stripOthers, 4); -} - -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); - - if(!ID3v2Tag() && !ID3v1Tag() && !APETag()) { - - if((d->hasID3v1 || d->hasID3v2 || d->hasAPE) && stripOthers) - return strip(AllTags); - - return true; - } - - if(readOnly()) { - debug("MPEG::File::save() -- File is read only."); - return false; - } - - // Create the tags if we've been asked to. - - if (duplicateTags) { - - // 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; - - if(ID3v2 & tags) { - - if(ID3v2Tag() && !ID3v2Tag()->isEmpty()) { - - if(!d->hasID3v2) - d->ID3v2Location = 0; - - insert(ID3v2Tag()->render(id3v2Version), d->ID3v2Location, d->ID3v2OriginalSize); - - d->hasID3v2 = true; - - // v1 tag location has changed, update if it exists - - if(ID3v1Tag()) - d->ID3v1Location = findID3v1(); - - // APE tag location has changed, update if it exists - - if(APETag()) - findAPE(); - } - else if(stripOthers) - success = strip(ID3v2, false) && success; - } - else if(d->hasID3v2 && stripOthers) - success = strip(ID3v2) && success; - - if(ID3v1 & tags) { - if(ID3v1Tag() && !ID3v1Tag()->isEmpty()) { - int offset = d->hasID3v1 ? -128 : 0; - seek(offset, End); - writeBlock(ID3v1Tag()->render()); - d->hasID3v1 = true; - d->ID3v1Location = findID3v1(); - } - else if(stripOthers) - success = strip(ID3v1) && success; - } - else if(d->hasID3v1 && stripOthers) - success = strip(ID3v1, false) && success; - - // Dont save an APE-tag unless one has been created - - if((APE & tags) && APETag()) { - if(d->hasAPE) - insert(APETag()->render(), d->APELocation, d->APEOriginalSize); - else { - if(d->hasID3v1) { - insert(APETag()->render(), d->ID3v1Location, 0); - d->APEOriginalSize = APETag()->footer()->completeTagSize(); - d->hasAPE = true; - d->APELocation = d->ID3v1Location; - d->ID3v1Location += d->APEOriginalSize; - } - else { - seek(0, End); - d->APELocation = tell(); - APE::Tag *apeTag = d->tag.access<APE::Tag>(APEIndex, false); - d->APEFooterLocation = d->APELocation - + apeTag->footer()->completeTagSize() - - APE::Footer::size(); - writeBlock(APETag()->render()); - d->APEOriginalSize = APETag()->footer()->completeTagSize(); - d->hasAPE = true; - } - } - } - else if(d->hasAPE && stripOthers) - success = strip(APE, false) && success; - - return success; -} - -ID3v2::Tag *MPEG::File::ID3v2Tag(bool create) -{ - return d->tag.access<ID3v2::Tag>(ID3v2Index, create); -} - -ID3v1::Tag *MPEG::File::ID3v1Tag(bool create) -{ - return d->tag.access<ID3v1::Tag>(ID3v1Index, create); -} - -APE::Tag *MPEG::File::APETag(bool create) -{ - return d->tag.access<APE::Tag>(APEIndex, create); -} - -bool MPEG::File::strip(int tags) -{ - return strip(tags, true); -} - -bool MPEG::File::strip(int tags, bool freeMemory) -{ - if(readOnly()) { - debug("MPEG::File::strip() - Cannot strip tags from a read only file."); - return false; - } - - if((tags & ID3v2) && d->hasID3v2) { - removeBlock(d->ID3v2Location, d->ID3v2OriginalSize); - d->ID3v2Location = -1; - d->ID3v2OriginalSize = 0; - d->hasID3v2 = false; - - if(freeMemory) - d->tag.set(ID3v2Index, 0); - - // v1 tag location has changed, update if it exists - - if(ID3v1Tag()) - d->ID3v1Location = findID3v1(); - - // APE tag location has changed, update if it exists - - if(APETag()) - findAPE(); - } - - if((tags & ID3v1) && d->hasID3v1) { - truncate(d->ID3v1Location); - d->ID3v1Location = -1; - d->hasID3v1 = false; - - if(freeMemory) - d->tag.set(ID3v1Index, 0); - } - - if((tags & APE) && d->hasAPE) { - removeBlock(d->APELocation, d->APEOriginalSize); - d->APELocation = -1; - d->APEFooterLocation = -1; - d->hasAPE = false; - if(d->hasID3v1) { - if(d->ID3v1Location > d->APELocation) - d->ID3v1Location -= d->APEOriginalSize; - } - - if(freeMemory) - d->tag.set(APEIndex, 0); - } - - return true; -} - -void MPEG::File::setID3v2FrameFactory(const ID3v2::FrameFactory *factory) -{ - d->ID3v2FrameFactory = factory; -} - -long MPEG::File::nextFrameOffset(long position) -{ - bool foundLastSyncPattern = false; - - ByteVector buffer; - - while(true) { - seek(position); - buffer = readBlock(bufferSize()); - - if(buffer.size() <= 0) - return -1; - - if(foundLastSyncPattern && secondSynchByte(buffer[0])) - return position - 1; - - for(uint i = 0; i < buffer.size() - 1; i++) { - if(uchar(buffer[i]) == 0xff && secondSynchByte(buffer[i + 1])) - return position + i; - } - - foundLastSyncPattern = uchar(buffer[buffer.size() - 1]) == 0xff; - position += buffer.size(); - } -} - -long MPEG::File::previousFrameOffset(long position) -{ - bool foundFirstSyncPattern = false; - ByteVector buffer; - - while (position > 0) { - long size = ulong(position) < bufferSize() ? position : bufferSize(); - position -= size; - - seek(position); - buffer = readBlock(size); - - if(buffer.size() <= 0) - break; - - if(foundFirstSyncPattern && uchar(buffer[buffer.size() - 1]) == 0xff) - return position + buffer.size() - 1; - - for(int i = buffer.size() - 2; i >= 0; i--) { - if(uchar(buffer[i]) == 0xff && secondSynchByte(buffer[i + 1])) - return position + i; - } - - foundFirstSyncPattern = secondSynchByte(buffer[0]); - } - return -1; -} - -long MPEG::File::firstFrameOffset() -{ - long position = 0; - - if(ID3v2Tag()) - position = d->ID3v2Location + ID3v2Tag()->header()->completeTagSize(); - - return nextFrameOffset(position); -} - -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 -//////////////////////////////////////////////////////////////////////////////// - -void MPEG::File::read(bool readProperties, Properties::ReadStyle propertiesStyle) -{ - // Look for an ID3v2 tag - - d->ID3v2Location = findID3v2(); - - if(d->ID3v2Location >= 0) { - - d->tag.set(ID3v2Index, new ID3v2::Tag(this, d->ID3v2Location, d->ID3v2FrameFactory)); - - d->ID3v2OriginalSize = ID3v2Tag()->header()->completeTagSize(); - - if(ID3v2Tag()->header()->tagSize() <= 0) - d->tag.set(ID3v2Index, 0); - else - d->hasID3v2 = true; - } - - // Look for an ID3v1 tag - - d->ID3v1Location = findID3v1(); - - if(d->ID3v1Location >= 0) { - d->tag.set(ID3v1Index, new ID3v1::Tag(this, d->ID3v1Location)); - d->hasID3v1 = true; - } - - // Look for an APE tag - - findAPE(); - - if(d->APELocation >= 0) { - - d->tag.set(APEIndex, new APE::Tag(this, d->APEFooterLocation)); - d->APEOriginalSize = APETag()->footer()->completeTagSize(); - d->hasAPE = true; - } - - if(readProperties) - d->properties = new Properties(this, propertiesStyle); - - // Make sure that we have our default tag types available. - - ID3v2Tag(true); - ID3v1Tag(true); -} - -long MPEG::File::findID3v2() -{ - // This method is based on the contents of TagLib::File::find(), but because - // of some subtlteies -- specifically the need to look for the bit pattern of - // an MPEG sync, it has been modified for use here. - - if(isValid() && ID3v2::Header::fileIdentifier().size() <= bufferSize()) { - - // The position in the file that the current buffer starts at. - - long bufferOffset = 0; - ByteVector buffer; - - // These variables are used to keep track of a partial match that happens at - // the end of a buffer. - - int previousPartialMatch = -1; - bool previousPartialSynchMatch = false; - - // Save the location of the current read pointer. We will restore the - // position using seek() before all returns. - - long originalPosition = tell(); - - // Start the search at the beginning of the file. - - seek(0); - - // This loop is the crux of the find method. There are three cases that we - // want to account for: - // (1) The previously searched buffer contained a partial match of the search - // pattern and we want to see if the next one starts with the remainder of - // that pattern. - // - // (2) The search pattern is wholly contained within the current buffer. - // - // (3) The current buffer ends with a partial match of the pattern. We will - // note this for use in the next itteration, where we will check for the rest - // of the pattern. - - for(buffer = readBlock(bufferSize()); buffer.size() > 0; buffer = readBlock(bufferSize())) { - - // (1) previous partial match - - if(previousPartialSynchMatch && secondSynchByte(buffer[0])) - return -1; - - if(previousPartialMatch >= 0 && int(bufferSize()) > previousPartialMatch) { - const int patternOffset = (bufferSize() - previousPartialMatch); - if(buffer.containsAt(ID3v2::Header::fileIdentifier(), 0, patternOffset)) { - seek(originalPosition); - return bufferOffset - bufferSize() + previousPartialMatch; - } - } - - // (2) pattern contained in current buffer - - long location = buffer.find(ID3v2::Header::fileIdentifier()); - if(location >= 0) { - seek(originalPosition); - return bufferOffset + location; - } - - int firstSynchByte = buffer.find(char(uchar(255))); - - // Here we have to loop because there could be several of the first - // (11111111) byte, and we want to check all such instances until we find - // a full match (11111111 111) or hit the end of the buffer. - - while(firstSynchByte >= 0) { - - // if this *is not* at the end of the buffer - - if(firstSynchByte < int(buffer.size()) - 1) { - if(secondSynchByte(buffer[firstSynchByte + 1])) { - // We've found the frame synch pattern. - seek(originalPosition); - return -1; - } - else { - - // We found 11111111 at the end of the current buffer indicating a - // partial match of the synch pattern. The find() below should - // return -1 and break out of the loop. - - previousPartialSynchMatch = true; - } - } - - // Check in the rest of the buffer. - - firstSynchByte = buffer.find(char(uchar(255)), firstSynchByte + 1); - } - - // (3) partial match - - previousPartialMatch = buffer.endsWithPartialMatch(ID3v2::Header::fileIdentifier()); - - bufferOffset += bufferSize(); - } - - // Since we hit the end of the file, reset the status before continuing. - - clear(); - - seek(originalPosition); - } - - return -1; -} - -long MPEG::File::findID3v1() -{ - if(isValid()) { - seek(-128, End); - long p = tell(); - - if(readBlock(3) == ID3v1::Tag::fileIdentifier()) - return p; - } - return -1; -} - -void MPEG::File::findAPE() -{ - if(isValid()) { - seek(d->hasID3v1 ? -160 : -32, End); - - long p = tell(); - - if(readBlock(8) == APE::Tag::fileIdentifier()) { - d->APEFooterLocation = p; - seek(d->APEFooterLocation); - APE::Footer footer(readBlock(APE::Footer::size())); - d->APELocation = d->APEFooterLocation - footer.completeTagSize() - + APE::Footer::size(); - return; - } - } - - d->APELocation = -1; - d->APEFooterLocation = -1; -} - -bool MPEG::File::secondSynchByte(char byte) -{ - std::bitset<8> b(byte); - - // check to see if the byte matches 111xxxxx - return b.test(7) && b.test(6) && b.test(5); -} diff --git a/taglib/taglib/mpeg/mpegfile.h b/taglib/taglib/mpeg/mpegfile.h deleted file mode 100644 index 3fc01e6..0000000 --- a/taglib/taglib/mpeg/mpegfile.h +++ /dev/null @@ -1,390 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_MPEGFILE_H -#define TAGLIB_MPEGFILE_H - -#include "taglib_export.h" -#include "tfile.h" -#include "tag.h" - -#include "mpegproperties.h" - -namespace TagLib { - - namespace ID3v2 { class Tag; class FrameFactory; } - namespace ID3v1 { class Tag; } - namespace APE { class Tag; } - - //! An implementation of TagLib::File with MPEG (MP3) specific methods - - namespace MPEG { - - //! An MPEG file class with some useful methods specific to MPEG - - /*! - * This implements the generic TagLib::File API and additionally provides - * access to properties that are distinct to MPEG files, notably access - * to the different ID3 tags. - */ - - class TAGLIB_EXPORT File : public TagLib::File - { - public: - /*! - * This set of flags is used for various operations and is suitable for - * being OR-ed together. - */ - enum TagTypes { - //! Empty set. Matches no tag types. - NoTags = 0x0000, - //! Matches ID3v1 tags. - ID3v1 = 0x0001, - //! Matches ID3v2 tags. - ID3v2 = 0x0002, - //! Matches APE tags. - APE = 0x0004, - //! Matches all tag types. - AllTags = 0xffff - }; - - /*! - * 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. - */ - File(FileName file, bool readProperties = true, - Properties::ReadStyle propertiesStyle = Properties::Average); - - /*! - * 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. - * - * \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); - - /*! - * 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. - */ - File(IOStream *stream, ID3v2::FrameFactory *frameFactory, - bool readProperties = true, - Properties::ReadStyle propertiesStyle = Properties::Average); - - /*! - * Destroys this instance of the File. - */ - virtual ~File(); - - /*! - * Returns a pointer to a tag that is the union of the ID3v2 and ID3v1 - * tags. The ID3v2 tag is given priority in reading the information -- if - * requested information exists in both the ID3v2 tag and the ID3v1 tag, - * the information from the ID3v2 tag will be returned. - * - * If you would like more granular control over the content of the tags, - * with the concession of generality, use the tag-type specific calls. - * - * \note As this tag is not implemented as an ID3v2 tag or an ID3v1 tag, - * but a union of the two this pointer may not be cast to the specific - * tag types. - * - * \see ID3v1Tag() - * \see ID3v2Tag() - * \see APETag() - */ - virtual Tag *tag() const; - - /*! - * 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. - */ - PropertyMap properties() const; - - void removeUnsupportedProperties(const StringList &properties); - - /*! - * 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 &); - - /*! - * Returns the MPEG::Properties for this file. If no audio properties - * were read then this will return a null pointer. - */ - virtual Properties *audioProperties() const; - - /*! - * Save the file. If at least one tag -- ID3v1 or ID3v2 -- exists this - * will duplicate its content into the other tag. This returns true - * if saving was successful. - * - * If neither exists or if both tags are empty, this will strip the tags - * from the file. - * - * This is the same as calling save(AllTags); - * - * If you would like more granular control over the content of the tags, - * with the concession of generality, use paramaterized save call below. - * - * \see save(int tags) - */ - virtual bool save(); - - /*! - * Save the file. This will attempt to save all of the tag types that are - * specified by OR-ing together TagTypes values. The save() method above - * uses AllTags. This returns true if saving was successful. - * - * This strips all tags not included in the mask, but does not modify them - * in memory, so later calls to save() which make use of these tags will - * remain valid. This also strips empty tags. - */ - bool save(int tags); - - /*! - * 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. - */ - // BIC: combine with the above method - bool save(int tags, bool stripOthers); - - /*! - * 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. - */ - // 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. - * - * 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. - * - * 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 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 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); - - /*! - * This will strip the tags that match the OR-ed together TagTypes from the - * file. By default it strips all tags. It returns true if the tags are - * successfully stripped. - * - * This is equivalent to strip(tags, true) - * - * \note This will also invalidate pointers to the ID3 and APE tags - * as their memory will be freed. - */ - bool strip(int tags = AllTags); - - /*! - * This will strip the tags that match the OR-ed together TagTypes from the - * file. By default it strips all tags. It returns true if the tags are - * successfully stripped. - * - * If \a freeMemory is true the ID3 and APE tags will be deleted and - * pointers to them will be invalidated. - */ - // BIC: merge with the method above - bool strip(int tags, bool freeMemory); - - /*! - * Set the ID3v2::FrameFactory to something other than the default. - * - * \see ID3v2FrameFactory - */ - void setID3v2FrameFactory(const ID3v2::FrameFactory *factory); - - /*! - * Returns the position in the file of the first MPEG frame. - */ - long firstFrameOffset(); - - /*! - * Returns the position in the file of the next MPEG frame, - * using the current position as start - */ - long nextFrameOffset(long position); - - /*! - * Returns the position in the file of the previous MPEG frame, - * using the current position as start - */ - long previousFrameOffset(long position); - - /*! - * Returns the position in the file of the last MPEG frame. - */ - 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 &); - - void read(bool readProperties, Properties::ReadStyle propertiesStyle); - long findID3v2(); - long findID3v1(); - void findAPE(); - - /*! - * MPEG frames can be recognized by the bit pattern 11111111 111, so the - * first byte is easy to check for, however checking to see if the second byte - * starts with \e 111 is a bit more tricky, hence this member function. - */ - static bool secondSynchByte(char byte); - - class FilePrivate; - FilePrivate *d; - }; - } -} - -#endif diff --git a/taglib/taglib/mpeg/mpegheader.cpp b/taglib/taglib/mpeg/mpegheader.cpp deleted file mode 100644 index a582f75..0000000 --- a/taglib/taglib/mpeg/mpegheader.cpp +++ /dev/null @@ -1,277 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <bitset> - -#include <tbytevector.h> -#include <tstring.h> -#include <tdebug.h> -#include "trefcounter.h" - -#include "mpegheader.h" - -using namespace TagLib; - -class MPEG::Header::HeaderPrivate : public RefCounter -{ -public: - HeaderPrivate() : - isValid(false), - version(Version1), - layer(0), - protectionEnabled(false), - sampleRate(0), - isPadded(false), - channelMode(Stereo), - isCopyrighted(false), - isOriginal(false), - frameLength(0), - samplesPerFrame(0) {} - - bool isValid; - Version version; - int layer; - bool protectionEnabled; - int bitrate; - int sampleRate; - bool isPadded; - ChannelMode channelMode; - bool isCopyrighted; - bool isOriginal; - int frameLength; - int samplesPerFrame; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -MPEG::Header::Header(const ByteVector &data) -{ - d = new HeaderPrivate; - parse(data); -} - -MPEG::Header::Header(const Header &h) : d(h.d) -{ - d->ref(); -} - -MPEG::Header::~Header() -{ - if (d->deref()) - delete d; -} - -bool MPEG::Header::isValid() const -{ - return d->isValid; -} - -MPEG::Header::Version MPEG::Header::version() const -{ - return d->version; -} - -int MPEG::Header::layer() const -{ - return d->layer; -} - -bool MPEG::Header::protectionEnabled() const -{ - return d->protectionEnabled; -} - -int MPEG::Header::bitrate() const -{ - return d->bitrate; -} - -int MPEG::Header::sampleRate() const -{ - return d->sampleRate; -} - -bool MPEG::Header::isPadded() const -{ - return d->isPadded; -} - -MPEG::Header::ChannelMode MPEG::Header::channelMode() const -{ - return d->channelMode; -} - -bool MPEG::Header::isCopyrighted() const -{ - return d->isCopyrighted; -} - -bool MPEG::Header::isOriginal() const -{ - return d->isOriginal; -} - -int MPEG::Header::frameLength() const -{ - return d->frameLength; -} - -int MPEG::Header::samplesPerFrame() const -{ - return d->samplesPerFrame; -} - -MPEG::Header &MPEG::Header::operator=(const Header &h) -{ - if(&h == this) - return *this; - - if(d->deref()) - delete d; - - d = h.d; - d->ref(); - return *this; -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -void MPEG::Header::parse(const ByteVector &data) -{ - if(data.size() < 4 || uchar(data[0]) != 0xff) { - debug("MPEG::Header::parse() -- First byte did not match MPEG synch."); - return; - } - - std::bitset<32> flags(TAGLIB_CONSTRUCT_BITSET(data.toUInt())); - - // Check for the second byte's part of the MPEG synch - - if(!flags[23] || !flags[22] || !flags[21]) { - debug("MPEG::Header::parse() -- Second byte did not match MPEG synch."); - return; - } - - // Set the MPEG version - - if(!flags[20] && !flags[19]) - d->version = Version2_5; - else if(flags[20] && !flags[19]) - d->version = Version2; - else if(flags[20] && flags[19]) - d->version = Version1; - - // Set the MPEG layer - - if(!flags[18] && flags[17]) - d->layer = 3; - else if(flags[18] && !flags[17]) - d->layer = 2; - else if(flags[18] && flags[17]) - d->layer = 1; - - d->protectionEnabled = !flags[16]; - - // Set the bitrate - - static const int bitrates[2][3][16] = { - { // Version 1 - { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0 }, // layer 1 - { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0 }, // layer 2 - { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0 } // layer 3 - }, - { // Version 2 or 2.5 - { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0 }, // layer 1 - { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 }, // layer 2 - { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 } // layer 3 - } - }; - - const int versionIndex = d->version == Version1 ? 0 : 1; - const int layerIndex = d->layer > 0 ? d->layer - 1 : 0; - - // The bitrate index is encoded as the first 4 bits of the 3rd byte, - // i.e. 1111xxxx - - int i = uchar(data[2]) >> 4; - - d->bitrate = bitrates[versionIndex][layerIndex][i]; - - // Set the sample rate - - static const int sampleRates[3][4] = { - { 44100, 48000, 32000, 0 }, // Version 1 - { 22050, 24000, 16000, 0 }, // Version 2 - { 11025, 12000, 8000, 0 } // Version 2.5 - }; - - // The sample rate index is encoded as two bits in the 3nd byte, i.e. xxxx11xx - - i = uchar(data[2]) >> 2 & 0x03; - - d->sampleRate = sampleRates[d->version][i]; - - if(d->sampleRate == 0) { - debug("MPEG::Header::parse() -- Invalid sample rate."); - return; - } - - // The channel mode is encoded as a 2 bit value at the end of the 3nd byte, - // i.e. xxxxxx11 - - d->channelMode = ChannelMode((uchar(data[3]) & 0xC0) >> 6); - - // TODO: Add mode extension for completeness - - d->isOriginal = flags[2]; - d->isCopyrighted = flags[3]; - d->isPadded = flags[9]; - - // Calculate the frame length - - if(d->layer == 1) - d->frameLength = 24000 * 2 * d->bitrate / d->sampleRate + int(d->isPadded); - else - d->frameLength = 72000 * d->bitrate / d->sampleRate + int(d->isPadded); - - // Samples per frame - - static const int samplesPerFrame[3][2] = { - // MPEG1, 2/2.5 - { 384, 384 }, // Layer I - { 1152, 1152 }, // Layer II - { 1152, 576 } // Layer III - }; - - d->samplesPerFrame = samplesPerFrame[layerIndex][versionIndex]; - - // Now that we're done parsing, set this to be a valid frame. - - d->isValid = true; -} diff --git a/taglib/taglib/mpeg/mpegheader.h b/taglib/taglib/mpeg/mpegheader.h deleted file mode 100644 index 020ebd0..0000000 --- a/taglib/taglib/mpeg/mpegheader.h +++ /dev/null @@ -1,166 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_MPEGHEADER_H -#define TAGLIB_MPEGHEADER_H - -#include "taglib_export.h" - -namespace TagLib { - - class ByteVector; - - namespace MPEG { - - //! An implementation of MP3 frame headers - - /*! - * This is an implementation of MPEG Layer III headers. The API follows more - * or less the binary format of these headers. I've used - * <a href="http://www.mp3-tech.org/programmer/frame_header.html">this</a> - * document as a reference. - */ - - class TAGLIB_EXPORT Header - { - public: - /*! - * Parses an MPEG header based on \a data. - */ - Header(const ByteVector &data); - - /*! - * Does a shallow copy of \a h. - */ - Header(const Header &h); - - /*! - * Destroys this Header instance. - */ - virtual ~Header(); - - /*! - * Returns true if the frame is at least an appropriate size and has - * legal values. - */ - bool isValid() const; - - /*! - * The MPEG Version. - */ - enum Version { - //! MPEG Version 1 - Version1 = 0, - //! MPEG Version 2 - Version2 = 1, - //! MPEG Version 2.5 - Version2_5 = 2 - }; - - /*! - * Returns the MPEG Version of the header. - */ - Version version() const; - - /*! - * Returns the layer version. This will be between the values 1-3. - */ - int layer() const; - - /*! - * Returns true if the MPEG protection bit is enabled. - */ - bool protectionEnabled() const; - - /*! - * Returns the bitrate encoded in the header. - */ - int bitrate() const; - - /*! - * Returns the sample rate in Hz. - */ - int sampleRate() const; - - /*! - * Returns true if the frame is padded. - */ - bool isPadded() const; - - /*! - * There are a few combinations or one or two channel audio that are - * possible: - */ - enum ChannelMode { - //! Stereo - Stereo = 0, - //! Stereo - JointStereo = 1, - //! Dual Mono - DualChannel = 2, - //! Mono - SingleChannel = 3 - }; - - /*! - * Returns the channel mode for this frame. - */ - ChannelMode channelMode() const; - - /*! - * Returns true if the copyrighted bit is set. - */ - bool isCopyrighted() const; - - /*! - * Returns true if the "original" bit is set. - */ - bool isOriginal() const; - - /*! - * Returns the frame length. - */ - int frameLength() const; - - /*! - * Returns the number of frames per sample. - */ - int samplesPerFrame() const; - - /*! - * Makes a shallow copy of the header. - */ - Header &operator=(const Header &h); - - private: - void parse(const ByteVector &data); - - class HeaderPrivate; - HeaderPrivate *d; - }; - } -} - -#endif diff --git a/taglib/taglib/mpeg/mpegproperties.cpp b/taglib/taglib/mpeg/mpegproperties.cpp deleted file mode 100644 index 3af9566..0000000 --- a/taglib/taglib/mpeg/mpegproperties.cpp +++ /dev/null @@ -1,254 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <tdebug.h> -#include <tstring.h> - -#include "mpegproperties.h" -#include "mpegfile.h" -#include "xingheader.h" - -using namespace TagLib; - -class MPEG::Properties::PropertiesPrivate -{ -public: - PropertiesPrivate(File *f, ReadStyle s) : - file(f), - xingHeader(0), - style(s), - length(0), - bitrate(0), - sampleRate(0), - channels(0), - layer(0), - version(Header::Version1), - channelMode(Header::Stereo), - protectionEnabled(false), - isCopyrighted(false), - isOriginal(false) {} - - ~PropertiesPrivate() - { - delete xingHeader; - } - - File *file; - XingHeader *xingHeader; - ReadStyle style; - int length; - int bitrate; - int sampleRate; - int channels; - int layer; - Header::Version version; - Header::ChannelMode channelMode; - bool protectionEnabled; - bool isCopyrighted; - bool isOriginal; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -MPEG::Properties::Properties(File *file, ReadStyle style) : AudioProperties(style) -{ - d = new PropertiesPrivate(file, style); - - if(file && file->isOpen()) - read(); -} - -MPEG::Properties::~Properties() -{ - delete d; -} - -int MPEG::Properties::length() const -{ - return d->length; -} - -int MPEG::Properties::bitrate() const -{ - return d->bitrate; -} - -int MPEG::Properties::sampleRate() const -{ - return d->sampleRate; -} - -int MPEG::Properties::channels() const -{ - return d->channels; -} - -const MPEG::XingHeader *MPEG::Properties::xingHeader() const -{ - return d->xingHeader; -} - -MPEG::Header::Version MPEG::Properties::version() const -{ - return d->version; -} - -int MPEG::Properties::layer() const -{ - return d->layer; -} - -bool MPEG::Properties::protectionEnabled() const -{ - return d->protectionEnabled; -} - -MPEG::Header::ChannelMode MPEG::Properties::channelMode() const -{ - return d->channelMode; -} - -bool MPEG::Properties::isCopyrighted() const -{ - return d->isCopyrighted; -} - -bool MPEG::Properties::isOriginal() const -{ - return d->isOriginal; -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -void MPEG::Properties::read() -{ - // Since we've likely just looked for the ID3v1 tag, start at the end of the - // file where we're least likely to have to have to move the disk head. - - long last = d->file->lastFrameOffset(); - - if(last < 0) { - debug("MPEG::Properties::read() -- Could not find a valid last MPEG frame in the stream."); - return; - } - - d->file->seek(last); - Header lastHeader(d->file->readBlock(4)); - - long first = d->file->firstFrameOffset(); - - if(first < 0) { - debug("MPEG::Properties::read() -- Could not find a valid first MPEG frame in the stream."); - return; - } - - if(!lastHeader.isValid()) { - - long pos = last; - - while(pos > first) { - - pos = d->file->previousFrameOffset(pos); - - if(pos < 0) - break; - - d->file->seek(pos); - Header header(d->file->readBlock(4)); - - if(header.isValid()) { - lastHeader = header; - last = pos; - break; - } - } - } - - // Now jump back to the front of the file and read what we need from there. - - d->file->seek(first); - Header firstHeader(d->file->readBlock(4)); - - if(!firstHeader.isValid() || !lastHeader.isValid()) { - debug("MPEG::Properties::read() -- Page headers were invalid."); - return; - } - - // Check for a Xing header that will help us in gathering information about a - // VBR stream. - - int xingHeaderOffset = MPEG::XingHeader::xingHeaderOffset(firstHeader.version(), - firstHeader.channelMode()); - - d->file->seek(first + xingHeaderOffset); - d->xingHeader = new XingHeader(d->file->readBlock(16)); - - // Read the length and the bitrate from the Xing header. - - if(d->xingHeader->isValid() && - firstHeader.sampleRate() > 0 && - d->xingHeader->totalFrames() > 0) - { - double timePerFrame = - double(firstHeader.samplesPerFrame()) / firstHeader.sampleRate(); - - double length = timePerFrame * d->xingHeader->totalFrames(); - - d->length = int(length); - 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 - // bitrate file. - - delete d->xingHeader; - d->xingHeader = 0; - - // TODO: Make this more robust with audio property detection for VBR without a - // Xing header. - - if(firstHeader.frameLength() > 0 && firstHeader.bitrate() > 0) { - int frames = (last - first) / firstHeader.frameLength() + 1; - - d->length = int(float(firstHeader.frameLength() * frames) / - float(firstHeader.bitrate() * 125) + 0.5); - d->bitrate = firstHeader.bitrate(); - } - } - - - d->sampleRate = firstHeader.sampleRate(); - d->channels = firstHeader.channelMode() == Header::SingleChannel ? 1 : 2; - d->version = firstHeader.version(); - d->layer = firstHeader.layer(); - d->protectionEnabled = firstHeader.protectionEnabled(); - d->channelMode = firstHeader.channelMode(); - d->isCopyrighted = firstHeader.isCopyrighted(); - d->isOriginal = firstHeader.isOriginal(); -} diff --git a/taglib/taglib/mpeg/mpegproperties.h b/taglib/taglib/mpeg/mpegproperties.h deleted file mode 100644 index 72e594f..0000000 --- a/taglib/taglib/mpeg/mpegproperties.h +++ /dev/null @@ -1,118 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_MPEGPROPERTIES_H -#define TAGLIB_MPEGPROPERTIES_H - -#include "taglib_export.h" -#include "audioproperties.h" - -#include "mpegheader.h" - -namespace TagLib { - - namespace MPEG { - - class File; - class XingHeader; - - //! An implementation of audio property reading for MP3 - - /*! - * This reads the data from an MPEG Layer III stream found in the - * AudioProperties API. - */ - - class TAGLIB_EXPORT Properties : public AudioProperties - { - public: - /*! - * Create an instance of MPEG::Properties with the data read from the - * MPEG::File \a file. - */ - Properties(File *file, ReadStyle style = Average); - - /*! - * Destroys this MPEG Properties instance. - */ - virtual ~Properties(); - - // Reimplementations. - - virtual int length() const; - virtual int bitrate() const; - virtual int sampleRate() const; - virtual int channels() const; - - /*! - * Returns a pointer to the XingHeader if one exists or null if no - * XingHeader was found. - */ - - const XingHeader *xingHeader() const; - - /*! - * Returns the MPEG Version of the file. - */ - Header::Version version() const; - - /*! - * Returns the layer version. This will be between the values 1-3. - */ - int layer() const; - - /*! - * Returns true if the MPEG protection bit is enabled. - */ - bool protectionEnabled() const; - - /*! - * Returns the channel mode for this frame. - */ - Header::ChannelMode channelMode() const; - - /*! - * Returns true if the copyrighted bit is set. - */ - bool isCopyrighted() const; - - /*! - * Returns true if the "original" bit is set. - */ - bool isOriginal() const; - - private: - Properties(const Properties &); - Properties &operator=(const Properties &); - - void read(); - - class PropertiesPrivate; - PropertiesPrivate *d; - }; - } -} - -#endif diff --git a/taglib/taglib/mpeg/xingheader.cpp b/taglib/taglib/mpeg/xingheader.cpp deleted file mode 100644 index 9e20127..0000000 --- a/taglib/taglib/mpeg/xingheader.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/*************************************************************************** - copyright : (C) 2003 by Ismael Orenstein - email : orenstein@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <tbytevector.h> -#include <tstring.h> -#include <tdebug.h> - -#include "xingheader.h" - -using namespace TagLib; - -class MPEG::XingHeader::XingHeaderPrivate -{ -public: - XingHeaderPrivate() : - frames(0), - size(0), - valid(false) - {} - - uint frames; - uint size; - bool valid; -}; - -MPEG::XingHeader::XingHeader(const ByteVector &data) -{ - d = new XingHeaderPrivate; - parse(data); -} - -MPEG::XingHeader::~XingHeader() -{ - delete d; -} - -bool MPEG::XingHeader::isValid() const -{ - return d->valid; -} - -TagLib::uint MPEG::XingHeader::totalFrames() const -{ - return d->frames; -} - -TagLib::uint MPEG::XingHeader::totalSize() const -{ - return d->size; -} - -int MPEG::XingHeader::xingHeaderOffset(TagLib::MPEG::Header::Version v, - TagLib::MPEG::Header::ChannelMode c) -{ - if(v == MPEG::Header::Version1) { - if(c == MPEG::Header::SingleChannel) - return 0x15; - else - return 0x24; - } - else { - if(c == MPEG::Header::SingleChannel) - return 0x0D; - else - return 0x15; - } -} - -void MPEG::XingHeader::parse(const ByteVector &data) -{ - // Check to see if a valid Xing header is available. - - if(!data.startsWith("Xing") && !data.startsWith("Info")) - return; - - // If the XingHeader doesn't contain the number of frames and the total stream - // info it's invalid. - - if(!(data[7] & 0x01)) { - debug("MPEG::XingHeader::parse() -- Xing header doesn't contain the total number of frames."); - return; - } - - if(!(data[7] & 0x02)) { - debug("MPEG::XingHeader::parse() -- Xing header doesn't contain the total stream size."); - return; - } - - d->frames = data.toUInt(8U); - d->size = data.toUInt(12U); - - d->valid = true; -} diff --git a/taglib/taglib/mpeg/xingheader.h b/taglib/taglib/mpeg/xingheader.h deleted file mode 100644 index ffe7494..0000000 --- a/taglib/taglib/mpeg/xingheader.h +++ /dev/null @@ -1,100 +0,0 @@ -/*************************************************************************** - copyright : (C) 2003 by Ismael Orenstein - email : orenstein@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_XINGHEADER_H -#define TAGLIB_XINGHEADER_H - -#include "mpegheader.h" -#include "taglib_export.h" - -namespace TagLib { - - class ByteVector; - - namespace MPEG { - - //! An implementation of the Xing VBR headers - - /*! - * This is a minimalistic implementation of the Xing VBR headers. Xing - * headers are often added to VBR (variable bit rate) MP3 streams to make it - * easy to compute the length and quality of a VBR stream. Our implementation - * is only concerned with the total size of the stream (so that we can - * calculate the total playing time and the average bitrate). It uses - * <a href="http://home.pcisys.net/~melanson/codecs/mp3extensions.txt">this text</a> - * and the XMMS sources as references. - */ - - class TAGLIB_EXPORT XingHeader - { - public: - /*! - * Parses a Xing header based on \a data. The data must be at least 16 - * bytes long (anything longer than this is discarded). - */ - XingHeader(const ByteVector &data); - - /*! - * Destroy this XingHeader instance. - */ - virtual ~XingHeader(); - - /*! - * Returns true if the data was parsed properly and if there is a valid - * Xing header present. - */ - bool isValid() const; - - /*! - * Returns the total number of frames. - */ - uint totalFrames() const; - - /*! - * Returns the total size of stream in bytes. - */ - uint totalSize() const; - - /*! - * Returns the offset for the start of this Xing header, given the - * version and channels of the frame - */ - // BIC: rename to offset() - static int xingHeaderOffset(TagLib::MPEG::Header::Version v, - TagLib::MPEG::Header::ChannelMode c); - - private: - XingHeader(const XingHeader &); - XingHeader &operator=(const XingHeader &); - - void parse(const ByteVector &data); - - class XingHeaderPrivate; - XingHeaderPrivate *d; - }; - } -} - -#endif diff --git a/taglib/taglib/ogg/flac/oggflacfile.cpp b/taglib/taglib/ogg/flac/oggflacfile.cpp deleted file mode 100644 index bdf8245..0000000 --- a/taglib/taglib/ogg/flac/oggflacfile.cpp +++ /dev/null @@ -1,294 +0,0 @@ -/*************************************************************************** - copyright : (C) 2004-2005 by Allan Sandfeld Jensen - email : kde@carewolf.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <tbytevector.h> -#include <tstring.h> -#include <tdebug.h> -#include <tpropertymap.h> - -#include <xiphcomment.h> -#include "oggflacfile.h" - -using namespace TagLib; -using TagLib::FLAC::Properties; - -class Ogg::FLAC::File::FilePrivate -{ -public: - FilePrivate() : - comment(0), - properties(0), - streamStart(0), - streamLength(0), - scanned(false), - hasXiphComment(false), - commentPacket(0) {} - - ~FilePrivate() - { - delete comment; - delete properties; - } - - Ogg::XiphComment *comment; - - Properties *properties; - ByteVector streamInfoData; - ByteVector xiphCommentData; - long streamStart; - long streamLength; - bool scanned; - - bool hasXiphComment; - int commentPacket; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -Ogg::FLAC::File::File(FileName file, bool readProperties, - Properties::ReadStyle propertiesStyle) : Ogg::File(file) -{ - d = new FilePrivate; - if(isOpen()) - read(readProperties, propertiesStyle); -} - -Ogg::FLAC::File::File(IOStream *stream, bool readProperties, - Properties::ReadStyle propertiesStyle) : Ogg::File(stream) -{ - d = new FilePrivate; - if(isOpen()) - read(readProperties, propertiesStyle); -} - -Ogg::FLAC::File::~File() -{ - delete d; -} - -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; -} - - -bool Ogg::FLAC::File::save() -{ - d->xiphCommentData = d->comment->render(false); - - // Create FLAC metadata-block: - - // Put the size in the first 32 bit (I assume no more than 24 bit are used) - - ByteVector v = ByteVector::fromUInt(d->xiphCommentData.size()); - - // Set the type of the metadata-block to be a Xiph / Vorbis comment - - v[0] = 4; - - // Append the comment-data after the 32 bit header - - v.append(d->xiphCommentData); - - // Save the packet at the old spot - // FIXME: Use padding if size is increasing - - setPacket(d->commentPacket, v); - - return Ogg::File::save(); -} - -bool Ogg::FLAC::File::hasXiphComment() const -{ - return d->hasXiphComment; -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -void Ogg::FLAC::File::read(bool readProperties, Properties::ReadStyle propertiesStyle) -{ - // Sanity: Check if we really have an Ogg/FLAC file - -/* - ByteVector oggHeader = packet(0); - - if (oggHeader.mid(28,4) != "fLaC") { - debug("Ogg::FLAC::File::read() -- Not an Ogg/FLAC file"); - setValid(false); - return; - }*/ - - // Look for FLAC metadata, including vorbis comments - - scan(); - - if (!d->scanned) { - setValid(false); - return; - } - - - if(d->hasXiphComment) - d->comment = new Ogg::XiphComment(xiphCommentData()); - else - d->comment = new Ogg::XiphComment; - - - if(readProperties) - d->properties = new Properties(streamInfoData(), streamLength(), propertiesStyle); -} - -ByteVector Ogg::FLAC::File::streamInfoData() -{ - scan(); - return d->streamInfoData; -} - -ByteVector Ogg::FLAC::File::xiphCommentData() -{ - scan(); - return d->xiphCommentData; -} - -long Ogg::FLAC::File::streamLength() -{ - scan(); - return d->streamLength; -} - -void Ogg::FLAC::File::scan() -{ - // Scan the metadata pages - - if(d->scanned) - return; - - if(!isValid()) - return; - - int ipacket = 0; - long overhead = 0; - - ByteVector metadataHeader = packet(ipacket); - if(metadataHeader.isNull()) - return; - - ByteVector header; - - if (!metadataHeader.startsWith("fLaC")) { - // FLAC 1.1.2+ - if (metadataHeader.mid(1,4) != "FLAC") return; - - if (metadataHeader[5] != 1) return; // not version 1 - - metadataHeader = metadataHeader.mid(13); - } - else { - // FLAC 1.1.0 & 1.1.1 - metadataHeader = packet(++ipacket); - - if(metadataHeader.isNull()) - return; - - } - - header = metadataHeader.mid(0,4); - // Header format (from spec): - // <1> Last-metadata-block flag - // <7> BLOCK_TYPE - // 0 : STREAMINFO - // 1 : PADDING - // .. - // 4 : VORBIS_COMMENT - // .. - // <24> Length of metadata to follow - - char blockType = header[0] & 0x7f; - bool lastBlock = (header[0] & 0x80) != 0; - uint length = header.toUInt(1, 3, true); - overhead += length; - - // Sanity: First block should be the stream_info metadata - - if(blockType != 0) { - debug("Ogg::FLAC::File::scan() -- Invalid Ogg/FLAC stream"); - return; - } - - d->streamInfoData = metadataHeader.mid(4, length); - - // Search through the remaining metadata - - while(!lastBlock) { - metadataHeader = packet(++ipacket); - - if(metadataHeader.isNull()) - return; - - header = metadataHeader.mid(0, 4); - blockType = header[0] & 0x7f; - lastBlock = (header[0] & 0x80) != 0; - length = header.toUInt(1, 3, true); - overhead += length; - - if(blockType == 1) { - // debug("Ogg::FLAC::File::scan() -- Padding found"); - } - else if(blockType == 4) { - // debug("Ogg::FLAC::File::scan() -- Vorbis-comments found"); - d->xiphCommentData = metadataHeader.mid(4, length); - d->hasXiphComment = true; - d->commentPacket = ipacket; - } - else if(blockType > 5) { - debug("Ogg::FLAC::File::scan() -- Unknown metadata block"); - } - } - - // End of metadata, now comes the datastream - d->streamStart = overhead; - d->streamLength = File::length() - d->streamStart; - - d->scanned = true; -} diff --git a/taglib/taglib/ogg/flac/oggflacfile.h b/taglib/taglib/ogg/flac/oggflacfile.h deleted file mode 100644 index 8d87e48..0000000 --- a/taglib/taglib/ogg/flac/oggflacfile.h +++ /dev/null @@ -1,162 +0,0 @@ -/*************************************************************************** - copyright : (C) 2004 by Allan Sandfeld Jensen - email : kde@carewolf.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_OGGFLACFILE_H -#define TAGLIB_OGGFLACFILE_H - -#include "taglib_export.h" -#include "oggfile.h" -#include "xiphcomment.h" - -#include "flacproperties.h" - -namespace TagLib { - - class Tag; - - namespace Ogg { - - //! An implementation of Ogg FLAC metadata - - /*! - * This is implementation of FLAC metadata for Ogg FLAC files. For "pure" - * FLAC files look under the FLAC hiearchy. - * - * Unlike "pure" FLAC-files, Ogg FLAC only supports Xiph-comments, - * while the audio-properties are the same. - */ - namespace FLAC { - - using TagLib::FLAC::Properties; - - //! An implementation of TagLib::File with Ogg/FLAC specific methods - - /*! - * This implements and provides an interface for Ogg/FLAC 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 Ogg FLAC files. - */ - - class TAGLIB_EXPORT File : public Ogg::File - { - public: - /*! - * 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); - - /*! - * 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); - - /*! - * Destroys this instance of the File. - */ - virtual ~File(); - - /*! - * 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; - - /*! - * Returns the FLAC::Properties for this file. If no audio properties - * were read then this will return a null pointer. - */ - 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. - */ - virtual bool save(); - - /*! - * Returns the length of the audio-stream, used by FLAC::Properties for - * calculating the bitrate. - */ - 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 &); - - void read(bool readProperties, Properties::ReadStyle propertiesStyle); - void scan(); - ByteVector streamInfoData(); - ByteVector xiphCommentData(); - - class FilePrivate; - FilePrivate *d; - }; - } // namespace FLAC - } // namespace Ogg -} // namespace TagLib - -#endif diff --git a/taglib/taglib/ogg/oggfile.cpp b/taglib/taglib/ogg/oggfile.cpp deleted file mode 100644 index cc30f9c..0000000 --- a/taglib/taglib/ogg/oggfile.cpp +++ /dev/null @@ -1,432 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <tbytevectorlist.h> -#include <tmap.h> -#include <tstring.h> -#include <tdebug.h> - -#include "oggfile.h" -#include "oggpage.h" -#include "oggpageheader.h" - -using namespace TagLib; - -class Ogg::File::FilePrivate -{ -public: - FilePrivate() : - streamSerialNumber(0), - firstPageHeader(0), - lastPageHeader(0), - currentPage(0), - currentPacketPage(0) - { - pages.setAutoDelete(true); - } - - ~FilePrivate() - { - delete firstPageHeader; - delete lastPageHeader; - } - - uint streamSerialNumber; - List<Page *> pages; - PageHeader *firstPageHeader; - PageHeader *lastPageHeader; - std::vector< List<int> > packetToPageMap; - Map<int, ByteVector> dirtyPackets; - List<int> dirtyPages; - - //! The current page for the reader -- used by nextPage() - Page *currentPage; - //! The current page for the packet parser -- used by packet() - Page *currentPacketPage; - //! The packets for the currentPacketPage -- used by packet() - ByteVectorList currentPackets; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -Ogg::File::~File() -{ - delete d; -} - -ByteVector Ogg::File::packet(uint i) -{ - // Check to see if we're called setPacket() for this packet since the last - // save: - - if(d->dirtyPackets.contains(i)) - return d->dirtyPackets[i]; - - // If we haven't indexed the page where the packet we're interested in starts, - // begin reading pages until we have. - - while(d->packetToPageMap.size() <= i) { - if(!nextPage()) { - debug("Ogg::File::packet() -- Could not find the requested packet."); - return ByteVector::null; - } - } - - // Start reading at the first page that contains part (or all) of this packet. - // If the last read stopped at the packet that we're interested in, don't - // reread its packet list. (This should make sequential packet reads fast.) - - uint pageIndex = d->packetToPageMap[i].front(); - if(d->currentPacketPage != d->pages[pageIndex]) { - d->currentPacketPage = d->pages[pageIndex]; - d->currentPackets = d->currentPacketPage->packets(); - } - - // If the packet is completely contained in the first page that it's in, then - // just return it now. - - if(d->currentPacketPage->containsPacket(i) & Page::CompletePacket) - return d->currentPackets[i - d->currentPacketPage->firstPacketIndex()]; - - // If the packet is *not* completely contained in the first page that it's a - // part of then that packet trails off the end of the page. Continue appending - // the pages' packet data until we hit a page that either does not end with the - // packet that we're fetching or where the last packet is complete. - - ByteVector packet = d->currentPackets.back(); - while(d->currentPacketPage->containsPacket(i) & Page::EndsWithPacket && - !d->currentPacketPage->header()->lastPacketCompleted()) - { - pageIndex++; - if(pageIndex == d->pages.size()) { - if(!nextPage()) { - debug("Ogg::File::packet() -- Could not find the requested packet."); - return ByteVector::null; - } - } - d->currentPacketPage = d->pages[pageIndex]; - d->currentPackets = d->currentPacketPage->packets(); - packet.append(d->currentPackets.front()); - } - - return packet; -} - -void Ogg::File::setPacket(uint i, const ByteVector &p) -{ - while(d->packetToPageMap.size() <= i) { - if(!nextPage()) { - debug("Ogg::File::setPacket() -- Could not set the requested packet."); - return; - } - } - - List<int>::ConstIterator it = d->packetToPageMap[i].begin(); - for(; it != d->packetToPageMap[i].end(); ++it) - d->dirtyPages.sortedInsert(*it, true); - - d->dirtyPackets.insert(i, p); -} - -const Ogg::PageHeader *Ogg::File::firstPageHeader() -{ - if(d->firstPageHeader) - return d->firstPageHeader->isValid() ? d->firstPageHeader : 0; - - long firstPageHeaderOffset = find("OggS"); - - if(firstPageHeaderOffset < 0) - return 0; - - d->firstPageHeader = new PageHeader(this, firstPageHeaderOffset); - return d->firstPageHeader->isValid() ? d->firstPageHeader : 0; -} - -const Ogg::PageHeader *Ogg::File::lastPageHeader() -{ - if(d->lastPageHeader) - return d->lastPageHeader->isValid() ? d->lastPageHeader : 0; - - long lastPageHeaderOffset = rfind("OggS"); - - if(lastPageHeaderOffset < 0) - return 0; - - d->lastPageHeader = new PageHeader(this, lastPageHeaderOffset); - return d->lastPageHeader->isValid() ? d->lastPageHeader : 0; -} - -bool Ogg::File::save() -{ - if(readOnly()) { - debug("Ogg::File::save() - Cannot save to a read only file."); - return false; - } - - List<int> pageGroup; - - for(List<int>::ConstIterator it = d->dirtyPages.begin(); it != d->dirtyPages.end(); ++it) { - if(!pageGroup.isEmpty() && pageGroup.back() + 1 != *it) { - writePageGroup(pageGroup); - pageGroup.clear(); - } - else - pageGroup.append(*it); - } - writePageGroup(pageGroup); - d->dirtyPages.clear(); - d->dirtyPackets.clear(); - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// protected members -//////////////////////////////////////////////////////////////////////////////// - -Ogg::File::File(FileName file) : TagLib::File(file) -{ - d = new FilePrivate; -} - -Ogg::File::File(IOStream *stream) : TagLib::File(stream) -{ - d = new FilePrivate; -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -bool Ogg::File::nextPage() -{ - long nextPageOffset; - int currentPacket; - - if(d->pages.isEmpty()) { - currentPacket = 0; - nextPageOffset = find("OggS"); - if(nextPageOffset < 0) - return false; - } - else { - if(d->currentPage->header()->lastPageOfStream()) - return false; - - if(d->currentPage->header()->lastPacketCompleted()) - currentPacket = d->currentPage->firstPacketIndex() + d->currentPage->packetCount(); - else - currentPacket = d->currentPage->firstPacketIndex() + d->currentPage->packetCount() - 1; - - nextPageOffset = d->currentPage->fileOffset() + d->currentPage->size(); - } - - // Read the next page and add it to the page list. - - d->currentPage = new Page(this, nextPageOffset); - - if(!d->currentPage->header()->isValid()) { - delete d->currentPage; - d->currentPage = 0; - return false; - } - - d->currentPage->setFirstPacketIndex(currentPacket); - - if(d->pages.isEmpty()) - d->streamSerialNumber = d->currentPage->header()->streamSerialNumber(); - - d->pages.append(d->currentPage); - - // Loop through the packets in the page that we just read appending the - // current page number to the packet to page map for each packet. - - for(uint i = 0; i < d->currentPage->packetCount(); i++) { - uint currentPacket = d->currentPage->firstPacketIndex() + i; - if(d->packetToPageMap.size() <= currentPacket) - d->packetToPageMap.push_back(List<int>()); - d->packetToPageMap[currentPacket].append(d->pages.size() - 1); - } - - return true; -} - -void Ogg::File::writePageGroup(const List<int> &thePageGroup) -{ - if(thePageGroup.isEmpty()) - return; - - - // pages in the pageGroup and packets must be equivalent - // (originalSize and size of packets would not work together), - // therefore we sometimes have to add pages to the group - List<int> pageGroup(thePageGroup); - while (!d->pages[pageGroup.back()]->header()->lastPacketCompleted()) { - if (d->currentPage->header()->pageSequenceNumber() == pageGroup.back()) { - if (nextPage() == false) { - debug("broken ogg file"); - return; - } - pageGroup.append(d->currentPage->header()->pageSequenceNumber()); - } else { - pageGroup.append(pageGroup.back() + 1); - } - } - - ByteVectorList packets; - - // If the first page of the group isn't dirty, append its partial content here. - - if(!d->dirtyPages.contains(d->pages[pageGroup.front()]->firstPacketIndex())) - packets.append(d->pages[pageGroup.front()]->packets().front()); - - int previousPacket = -1; - int originalSize = 0; - - for(List<int>::ConstIterator it = pageGroup.begin(); it != pageGroup.end(); ++it) { - uint firstPacket = d->pages[*it]->firstPacketIndex(); - uint lastPacket = firstPacket + d->pages[*it]->packetCount() - 1; - - List<int>::ConstIterator last = --pageGroup.end(); - - for(uint i = firstPacket; i <= lastPacket; i++) { - - if(it == last && i == lastPacket && !d->dirtyPages.contains(i)) - packets.append(d->pages[*it]->packets().back()); - else if(int(i) != previousPacket) { - previousPacket = i; - packets.append(packet(i)); - } - } - originalSize += d->pages[*it]->size(); - } - - const bool continued = d->pages[pageGroup.front()]->header()->firstPacketContinued(); - const bool completed = d->pages[pageGroup.back()]->header()->lastPacketCompleted(); - - // TODO: This pagination method isn't accurate for what's being done here. - // This should account for real possibilities like non-aligned packets and such. - - List<Page *> pages = Page::paginate(packets, Page::SinglePagePerGroup, - d->streamSerialNumber, pageGroup.front(), - continued, completed); - - List<Page *> renumberedPages; - - // Correct the page numbering of following pages - - if (pages.back()->header()->pageSequenceNumber() != pageGroup.back()) { - - // TODO: change the internal data structure so that we don't need to hold the - // complete file in memory (is unavoidable at the moment) - - // read the complete stream - while(!d->currentPage->header()->lastPageOfStream()) { - if(nextPage() == false) { - debug("broken ogg file"); - break; - } - } - - // create a gap for the new pages - int numberOfNewPages = pages.back()->header()->pageSequenceNumber() - pageGroup.back(); - List<Page *>::Iterator pageIter = d->pages.begin(); - for(int i = 0; i < pageGroup.back(); i++) { - if(pageIter != d->pages.end()) { - ++pageIter; - } - else { - debug("Ogg::File::writePageGroup() -- Page sequence is broken in original file."); - break; - } - } - - ++pageIter; - for(; pageIter != d->pages.end(); ++pageIter) { - Ogg::Page *newPage = - (*pageIter)->getCopyWithNewPageSequenceNumber( - (*pageIter)->header()->pageSequenceNumber() + numberOfNewPages); - - ByteVector data; - data.append(newPage->render()); - insert(data, newPage->fileOffset(), data.size()); - - renumberedPages.append(newPage); - } - } - - // insert the new data - - ByteVector data; - for(List<Page *>::ConstIterator it = pages.begin(); it != pages.end(); ++it) - data.append((*it)->render()); - - // The insertion algorithms could also be improve to queue and prioritize data - // on the way out. Currently it requires rewriting the file for every page - // group rather than just once; however, for tagging applications there will - // generally only be one page group, so it's not worth the time for the - // optimization at the moment. - - insert(data, d->pages[pageGroup.front()]->fileOffset(), originalSize); - - // Update the page index to include the pages we just created and to delete the - // old pages. - - // First step: Pages that contain the comment data - - for(List<Page *>::ConstIterator it = pages.begin(); it != pages.end(); ++it) { - const unsigned int index = (*it)->header()->pageSequenceNumber(); - if(index < d->pages.size()) { - delete d->pages[index]; - d->pages[index] = *it; - } - else if(index == d->pages.size()) { - d->pages.append(*it); - } - else { - // oops - there's a hole in the sequence - debug("Ogg::File::writePageGroup() -- Page sequence is broken."); - } - } - - // Second step: the renumbered pages - - for(List<Page *>::ConstIterator it = renumberedPages.begin(); it != renumberedPages.end(); ++it) { - const unsigned int index = (*it)->header()->pageSequenceNumber(); - if(index < d->pages.size()) { - delete d->pages[index]; - d->pages[index] = *it; - } - else if(index == d->pages.size()) { - d->pages.append(*it); - } - else { - // oops - there's a hole in the sequence - debug("Ogg::File::writePageGroup() -- Page sequence is broken."); - } - } -} diff --git a/taglib/taglib/ogg/oggfile.h b/taglib/taglib/ogg/oggfile.h deleted file mode 100644 index 8fed4ba..0000000 --- a/taglib/taglib/ogg/oggfile.h +++ /dev/null @@ -1,122 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include "taglib_export.h" -#include "tfile.h" -#include "tbytevectorlist.h" - -#ifndef TAGLIB_OGGFILE_H -#define TAGLIB_OGGFILE_H - -namespace TagLib { - - //! A namespace for the classes used by Ogg-based metadata files - - namespace Ogg { - - class PageHeader; - - //! An implementation of TagLib::File with some helpers for Ogg based formats - - /*! - * This is an implementation of Ogg file page and packet rendering and is of - * use to Ogg based formats. While the API is small this handles the - * non-trivial details of breaking up an Ogg stream into packets and makes - * these available (via subclassing) to the codec meta data implementations. - */ - - class TAGLIB_EXPORT File : public TagLib::File - { - public: - virtual ~File(); - - /*! - * Returns the packet contents for the i-th packet (starting from zero) - * in the Ogg bitstream. - * - * \warning The requires reading at least the packet header for every page - * up to the requested page. - */ - ByteVector packet(uint i); - - /*! - * Sets the packet with index \a i to the value \a p. - */ - void setPacket(uint i, const ByteVector &p); - - /*! - * Returns a pointer to the PageHeader for the first page in the stream or - * null if the page could not be found. - */ - const PageHeader *firstPageHeader(); - - /*! - * Returns a pointer to the PageHeader for the last page in the stream or - * null if the page could not be found. - */ - const PageHeader *lastPageHeader(); - - virtual bool save(); - - protected: - /*! - * 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 - * specific subclasses. - */ - File(FileName file); - - /*! - * 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); - - private: - File(const File &); - File &operator=(const File &); - - /*! - * Reads the next page and updates the internal "current page" pointer. - */ - bool nextPage(); - void writePageGroup(const List<int> &group); - - class FilePrivate; - FilePrivate *d; - }; - - } -} - -#endif diff --git a/taglib/taglib/ogg/oggpage.cpp b/taglib/taglib/ogg/oggpage.cpp deleted file mode 100644 index e5f767e..0000000 --- a/taglib/taglib/ogg/oggpage.cpp +++ /dev/null @@ -1,340 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <tstring.h> -#include <tdebug.h> - -#include "oggpage.h" -#include "oggpageheader.h" -#include "oggfile.h" - -using namespace TagLib; - -class Ogg::Page::PagePrivate -{ -public: - PagePrivate(File *f = 0, long pageOffset = -1) : - file(f), - fileOffset(pageOffset), - packetOffset(0), - header(f, pageOffset), - firstPacketIndex(-1) - { - if(file) { - packetOffset = fileOffset + header.size(); - packetSizes = header.packetSizes(); - dataSize = header.dataSize(); - } - } - - File *file; - long fileOffset; - long packetOffset; - int dataSize; - List<int> packetSizes; - PageHeader header; - int firstPacketIndex; - ByteVectorList packets; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -Ogg::Page::Page(Ogg::File *file, long pageOffset) -{ - d = new PagePrivate(file, pageOffset); -} - -Ogg::Page::~Page() -{ - delete d; -} - -long Ogg::Page::fileOffset() const -{ - return d->fileOffset; -} - -const Ogg::PageHeader *Ogg::Page::header() const -{ - return &d->header; -} - -int Ogg::Page::firstPacketIndex() const -{ - return d->firstPacketIndex; -} - -void Ogg::Page::setFirstPacketIndex(int index) -{ - d->firstPacketIndex = index; -} - -Ogg::Page::ContainsPacketFlags Ogg::Page::containsPacket(int index) const -{ - int lastPacketIndex = d->firstPacketIndex + packetCount() - 1; - if(index < d->firstPacketIndex || index > lastPacketIndex) - return DoesNotContainPacket; - - ContainsPacketFlags flags = DoesNotContainPacket; - - if(index == d->firstPacketIndex) - flags = ContainsPacketFlags(flags | BeginsWithPacket); - - if(index == lastPacketIndex) - flags = ContainsPacketFlags(flags | EndsWithPacket); - - // If there's only one page and it's complete: - - if(packetCount() == 1 && - !d->header.firstPacketContinued() && - d->header.lastPacketCompleted()) - { - flags = ContainsPacketFlags(flags | CompletePacket); - } - - // Or if there is more than one page and the page is - // (a) the first page and it's complete or - // (b) the last page and it's complete or - // (c) a page in the middle. - else if(packetCount() > 1 && - ((flags & BeginsWithPacket && !d->header.firstPacketContinued()) || - (flags & EndsWithPacket && d->header.lastPacketCompleted()) || - (!(flags & BeginsWithPacket) && !(flags & EndsWithPacket)))) - { - flags = ContainsPacketFlags(flags | CompletePacket); - } - - return flags; -} - -TagLib::uint Ogg::Page::packetCount() const -{ - return d->header.packetSizes().size(); -} - -ByteVectorList Ogg::Page::packets() const -{ - if(!d->packets.isEmpty()) - return d->packets; - - ByteVectorList l; - - if(d->file && d->header.isValid()) { - - d->file->seek(d->packetOffset); - - List<int> packetSizes = d->header.packetSizes(); - - List<int>::ConstIterator it = packetSizes.begin(); - for(; it != packetSizes.end(); ++it) - l.append(d->file->readBlock(*it)); - } - else - debug("Ogg::Page::packets() -- attempting to read packets from an invalid page."); - - return l; -} - -int Ogg::Page::size() const -{ - return d->header.size() + d->header.dataSize(); -} - -ByteVector Ogg::Page::render() const -{ - ByteVector data; - - data.append(d->header.render()); - - if(d->packets.isEmpty()) { - if(d->file) { - d->file->seek(d->packetOffset); - data.append(d->file->readBlock(d->dataSize)); - } - else - debug("Ogg::Page::render() -- this page is empty!"); - } - else { - ByteVectorList::ConstIterator it = d->packets.begin(); - for(; it != d->packets.end(); ++it) - data.append(*it); - } - - // Compute and set the checksum for the Ogg page. The checksum is taken over - // the entire page with the 4 bytes reserved for the checksum zeroed and then - // inserted in bytes 22-25 of the page header. - - ByteVector checksum = ByteVector::fromUInt(data.checksum(), false); - for(int i = 0; i < 4; i++) - data[i + 22] = checksum[i]; - - return data; -} - -List<Ogg::Page *> Ogg::Page::paginate(const ByteVectorList &packets, - PaginationStrategy strategy, - uint streamSerialNumber, - int firstPage, - bool firstPacketContinued, - bool lastPacketCompleted, - bool containsLastPacket) -{ - List<Page *> l; - - int totalSize = 0; - - for(ByteVectorList::ConstIterator it = packets.begin(); it != packets.end(); ++it) - totalSize += (*it).size(); - - // Handle creation of multiple pages with appropriate pagination. - if(strategy == Repaginate || totalSize + packets.size() > 255 * 255) { - - // SPLITSIZE must be a multiple of 255 in order to get the lacing values right - // create pages of about 8KB each -#define SPLITSIZE (32*255) - - int pageIndex = 0; - - for(ByteVectorList::ConstIterator it = packets.begin(); it != packets.end(); ++it) { - bool continued = false; - - // mark very first packet? - if(firstPacketContinued && it==packets.begin()) { - continued = true; - } - - // append to buf - ByteVector packetBuf; - packetBuf.append(*it); - - while(packetBuf.size() > SPLITSIZE) { - // output a Page - ByteVector packetForOnePage; - packetForOnePage.resize(SPLITSIZE); - std::copy(packetBuf.begin(), packetBuf.begin() + SPLITSIZE, packetForOnePage.begin()); - - ByteVectorList packetList; - packetList.append(packetForOnePage); - Page *p = new Page(packetList, streamSerialNumber, firstPage+pageIndex, continued, false, false); - l.append(p); - - pageIndex++; - continued = true; - packetBuf = packetBuf.mid(SPLITSIZE); - } - - ByteVectorList::ConstIterator jt = it; - ++jt; - bool lastPacketInList = (jt == packets.end()); - - // output a page for the rest (we output one packet per page, so this one should be completed) - ByteVectorList packetList; - packetList.append(packetBuf); - - bool isVeryLastPacket = false; - if(containsLastPacket) { - // mark the very last output page as last of stream - ByteVectorList::ConstIterator jt = it; - ++jt; - if(jt == packets.end()) { - isVeryLastPacket = true; - } - } - - Page *p = new Page(packetList, streamSerialNumber, firstPage+pageIndex, continued, - lastPacketInList ? lastPacketCompleted : true, - isVeryLastPacket); - pageIndex++; - - l.append(p); - } - } - else { - Page *p = new Page(packets, streamSerialNumber, firstPage, firstPacketContinued, - lastPacketCompleted, containsLastPacket); - l.append(p); - } - - return l; -} - -Ogg::Page* Ogg::Page::getCopyWithNewPageSequenceNumber(int sequenceNumber) -{ - Page *pResultPage = NULL; - - // TODO: a copy constructor would be helpful - - if(d->file == 0) { - pResultPage = new Page( - d->packets, - d->header.streamSerialNumber(), - sequenceNumber, - d->header.firstPacketContinued(), - d->header.lastPacketCompleted(), - d->header.lastPageOfStream()); - } - else - { - pResultPage = new Page(d->file, d->fileOffset); - pResultPage->d->header.setPageSequenceNumber(sequenceNumber); - } - return pResultPage; -} - -//////////////////////////////////////////////////////////////////////////////// -// protected members -//////////////////////////////////////////////////////////////////////////////// - -Ogg::Page::Page(const ByteVectorList &packets, - uint streamSerialNumber, - int pageNumber, - bool firstPacketContinued, - bool lastPacketCompleted, - bool containsLastPacket) -{ - d = new PagePrivate; - - ByteVector data; - List<int> packetSizes; - - d->header.setFirstPageOfStream(pageNumber == 0 && !firstPacketContinued); - d->header.setLastPageOfStream(containsLastPacket); - d->header.setFirstPacketContinued(firstPacketContinued); - d->header.setLastPacketCompleted(lastPacketCompleted); - d->header.setStreamSerialNumber(streamSerialNumber); - d->header.setPageSequenceNumber(pageNumber); - - // Build a page from the list of packets. - - for(ByteVectorList::ConstIterator it = packets.begin(); it != packets.end(); ++it) { - packetSizes.append((*it).size()); - data.append(*it); - } - d->packets = packets; - d->header.setPacketSizes(packetSizes); -} - diff --git a/taglib/taglib/ogg/oggpage.h b/taglib/taglib/ogg/oggpage.h deleted file mode 100644 index e9f4840..0000000 --- a/taglib/taglib/ogg/oggpage.h +++ /dev/null @@ -1,211 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_OGGPAGE_H -#define TAGLIB_OGGPAGE_H - -#include "taglib_export.h" -#include "tbytevectorlist.h" - -namespace TagLib { - - namespace Ogg { - - class File; - class PageHeader; - - //! An implementation of Ogg pages - - /*! - * This is an implementation of the pages that make up an Ogg stream. - * This handles parsing pages and breaking them down into packets and handles - * the details of packets spanning multiple pages and pages that contiain - * multiple packets. - * - * In most Xiph.org formats the comments are found in the first few packets, - * this however is a reasonably complete implementation of Ogg pages that - * could potentially be useful for non-meta data purposes. - */ - - class TAGLIB_EXPORT Page - { - public: - /*! - * Read an Ogg page from the \a file at the position \a pageOffset. - */ - Page(File *file, long pageOffset); - - virtual ~Page(); - - /*! - * Returns the page's position within the file (in bytes). - */ - long fileOffset() const; - - /*! - * Returns a pointer to the header for this page. This pointer will become - * invalid when the page is deleted. - */ - const PageHeader *header() const; - - /*! - * Returns a copy of the page with \a sequenceNumber set as sequence number. - * - * \see header() - * \see PageHeader::setPageSequenceNumber() - */ - Page* getCopyWithNewPageSequenceNumber(int sequenceNumber); - - /*! - * Returns the index of the first packet wholly or partially contained in - * this page. - * - * \see setFirstPacketIndex() - */ - int firstPacketIndex() const; - - /*! - * Sets the index of the first packet in the page. - * - * \see firstPacketIndex() - */ - void setFirstPacketIndex(int index); - - /*! - * When checking to see if a page contains a given packet this set of flags - * represents the possible values for that packets status in the page. - * - * \see containsPacket() - */ - enum ContainsPacketFlags { - //! No part of the packet is contained in the page - DoesNotContainPacket = 0x0000, - //! The packet is wholly contained in the page - CompletePacket = 0x0001, - //! The page starts with the given packet - BeginsWithPacket = 0x0002, - //! The page ends with the given packet - EndsWithPacket = 0x0004 - }; - - /*! - * Checks to see if the specified \a packet is contained in the current - * page. - * - * \see ContainsPacketFlags - */ - ContainsPacketFlags containsPacket(int index) const; - - /*! - * Returns the number of packets (whole or partial) in this page. - */ - uint packetCount() const; - - /*! - * Returns a list of the packets in this page. - * - * \note Either or both the first and last packets may be only partial. - * \see PageHeader::firstPacketContinued() - */ - ByteVectorList packets() const; - - /*! - * Returns the size of the page in bytes. - */ - int size() const; - - ByteVector render() const; - - /*! - * Defines a strategy for pagination, or grouping pages into Ogg packets, - * for use with pagination methods. - * - * \note Yes, I'm aware that this is not a canonical "Strategy Pattern", - * the term was simply convenient. - */ - enum PaginationStrategy { - /*! - * Attempt to put the specified set of packets into a single Ogg packet. - * If the sum of the packet data is greater than will fit into a single - * Ogg page -- 65280 bytes -- this will fall back to repagination using - * the recommended page sizes. - */ - SinglePagePerGroup, - /*! - * Split the packet or group of packets into pages that conform to the - * sizes recommended in the Ogg standard. - */ - Repaginate - }; - - /*! - * Pack \a packets into Ogg pages using the \a strategy for pagination. - * The page number indicater inside of the rendered packets will start - * with \a firstPage and be incremented for each page rendered. - * \a containsLastPacket should be set to true if \a packets contains the - * last page in the stream and will set the appropriate flag in the last - * rendered Ogg page's header. \a streamSerialNumber should be set to - * the serial number for this stream. - * - * \note The "absolute granule position" is currently always zeroed using - * this method as this suffices for the comment headers. - * - * \warning The pages returned by this method must be deleted by the user. - * You can use List<T>::setAutoDelete(true) to set these pages to be - * automatically deleted when this list passes out of scope. - * - * \see PaginationStrategy - * \see List::setAutoDelete() - */ - static List<Page *> paginate(const ByteVectorList &packets, - PaginationStrategy strategy, - uint streamSerialNumber, - int firstPage, - bool firstPacketContinued = false, - bool lastPacketCompleted = true, - bool containsLastPacket = false); - - protected: - /*! - * Creates an Ogg packet based on the data in \a packets. The page number - * for each page will be set to \a pageNumber. - */ - Page(const ByteVectorList &packets, - uint streamSerialNumber, - int pageNumber, - bool firstPacketContinued = false, - bool lastPacketCompleted = true, - bool containsLastPacket = false); - - private: - Page(const Page &); - Page &operator=(const Page &); - - class PagePrivate; - PagePrivate *d; - }; - } -} -#endif diff --git a/taglib/taglib/ogg/oggpageheader.cpp b/taglib/taglib/ogg/oggpageheader.cpp deleted file mode 100644 index b933313..0000000 --- a/taglib/taglib/ogg/oggpageheader.cpp +++ /dev/null @@ -1,323 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <stdlib.h> - -#include <bitset> - -#include <tstring.h> -#include <tdebug.h> -#include <taglib.h> - -#include "oggpageheader.h" -#include "oggfile.h" - -using namespace TagLib; - -class Ogg::PageHeader::PageHeaderPrivate -{ -public: - PageHeaderPrivate(File *f, long pageOffset) : - file(f), - fileOffset(pageOffset), - isValid(false), - firstPacketContinued(false), - lastPacketCompleted(false), - firstPageOfStream(false), - lastPageOfStream(false), - absoluteGranularPosition(0), - streamSerialNumber(0), - pageSequenceNumber(-1), - size(0), - dataSize(0) - {} - - File *file; - long fileOffset; - bool isValid; - List<int> packetSizes; - bool firstPacketContinued; - bool lastPacketCompleted; - bool firstPageOfStream; - bool lastPageOfStream; - long long absoluteGranularPosition; - uint streamSerialNumber; - int pageSequenceNumber; - int size; - int dataSize; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -Ogg::PageHeader::PageHeader(Ogg::File *file, long pageOffset) -{ - d = new PageHeaderPrivate(file, pageOffset); - if(file && pageOffset >= 0) - read(); -} - -Ogg::PageHeader::~PageHeader() -{ - delete d; -} - -bool Ogg::PageHeader::isValid() const -{ - return d->isValid; -} - -List<int> Ogg::PageHeader::packetSizes() const -{ - return d->packetSizes; -} - -void Ogg::PageHeader::setPacketSizes(const List<int> &sizes) -{ - d->packetSizes = sizes; -} - -bool Ogg::PageHeader::firstPacketContinued() const -{ - return d->firstPacketContinued; -} - -void Ogg::PageHeader::setFirstPacketContinued(bool continued) -{ - d->firstPacketContinued = continued; -} - -bool Ogg::PageHeader::lastPacketCompleted() const -{ - return d->lastPacketCompleted; -} - -void Ogg::PageHeader::setLastPacketCompleted(bool completed) -{ - d->lastPacketCompleted = completed; -} - -bool Ogg::PageHeader::firstPageOfStream() const -{ - return d->firstPageOfStream; -} - -void Ogg::PageHeader::setFirstPageOfStream(bool first) -{ - d->firstPageOfStream = first; -} - -bool Ogg::PageHeader::lastPageOfStream() const -{ - return d->lastPageOfStream; -} - -void Ogg::PageHeader::setLastPageOfStream(bool last) -{ - d->lastPageOfStream = last; -} - -long long Ogg::PageHeader::absoluteGranularPosition() const -{ - return d->absoluteGranularPosition; -} - -void Ogg::PageHeader::setAbsoluteGranularPosition(long long agp) -{ - d->absoluteGranularPosition = agp; -} - -int Ogg::PageHeader::pageSequenceNumber() const -{ - return d->pageSequenceNumber; -} - -void Ogg::PageHeader::setPageSequenceNumber(int sequenceNumber) -{ - d->pageSequenceNumber = sequenceNumber; -} - -TagLib::uint Ogg::PageHeader::streamSerialNumber() const -{ - return d->streamSerialNumber; -} - -void Ogg::PageHeader::setStreamSerialNumber(uint n) -{ - d->streamSerialNumber = n; -} - -int Ogg::PageHeader::size() const -{ - return d->size; -} - -int Ogg::PageHeader::dataSize() const -{ - return d->dataSize; -} - -ByteVector Ogg::PageHeader::render() const -{ - ByteVector data; - - // capture patern - - data.append("OggS"); - - // stream structure version - - data.append(char(0)); - - // header type flag - - std::bitset<8> flags; - flags[0] = d->firstPacketContinued; - flags[1] = d->pageSequenceNumber == 0; - flags[2] = d->lastPageOfStream; - - data.append(char(flags.to_ulong())); - - // absolute granular position - - data.append(ByteVector::fromLongLong(d->absoluteGranularPosition, false)); - - // stream serial number - - data.append(ByteVector::fromUInt(d->streamSerialNumber, false)); - - // page sequence number - - data.append(ByteVector::fromUInt(d->pageSequenceNumber, false)); - - // checksum -- this is left empty and should be filled in by the Ogg::Page - // class - - data.append(ByteVector(4, 0)); - - // page segment count and page segment table - - ByteVector pageSegments = lacingValues(); - - data.append(char(uchar(pageSegments.size()))); - data.append(pageSegments); - - return data; -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -void Ogg::PageHeader::read() -{ - d->file->seek(d->fileOffset); - - // An Ogg page header is at least 27 bytes, so we'll go ahead and read that - // much and then get the rest when we're ready for it. - - ByteVector data = d->file->readBlock(27); - - // Sanity check -- make sure that we were in fact able to read as much data as - // we asked for and that the page begins with "OggS". - - if(data.size() != 27 || !data.startsWith("OggS")) { - debug("Ogg::PageHeader::read() -- error reading page header"); - return; - } - - std::bitset<8> flags(data[5]); - - d->firstPacketContinued = flags.test(0); - d->firstPageOfStream = flags.test(1); - d->lastPageOfStream = flags.test(2); - - 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 - // segments we'll then read in the corresponding data for this count. - - int pageSegmentCount = uchar(data[26]); - - ByteVector pageSegments = d->file->readBlock(pageSegmentCount); - - // Another sanity check. - - if(pageSegmentCount < 1 || int(pageSegments.size()) != pageSegmentCount) - return; - - // The base size of an Ogg page 27 bytes plus the number of lacing values. - - d->size = 27 + pageSegmentCount; - - int packetSize = 0; - - for(int i = 0; i < pageSegmentCount; i++) { - d->dataSize += uchar(pageSegments[i]); - packetSize += uchar(pageSegments[i]); - - if(uchar(pageSegments[i]) < 255) { - d->packetSizes.append(packetSize); - packetSize = 0; - } - } - - if(packetSize > 0) { - d->packetSizes.append(packetSize); - d->lastPacketCompleted = false; - } - else - d->lastPacketCompleted = true; - - d->isValid = true; -} - -ByteVector Ogg::PageHeader::lacingValues() const -{ - ByteVector data; - - List<int> sizes = d->packetSizes; - for(List<int>::ConstIterator it = sizes.begin(); it != sizes.end(); ++it) { - - // The size of a packet in an Ogg page is indicated by a series of "lacing - // values" where the sum of the values is the packet size in bytes. Each of - // these values is a byte. A value of less than 255 (0xff) indicates the end - // of the packet. - - div_t n = div(*it, 255); - - for(int i = 0; i < n.quot; i++) - data.append(char(uchar(255))); - - if(it != --sizes.end() || d->lastPacketCompleted) - data.append(char(uchar(n.rem))); - } - - return data; -} diff --git a/taglib/taglib/ogg/oggpageheader.h b/taglib/taglib/ogg/oggpageheader.h deleted file mode 100644 index 742710a..0000000 --- a/taglib/taglib/ogg/oggpageheader.h +++ /dev/null @@ -1,232 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_OGGPAGEHEADER_H -#define TAGLIB_OGGPAGEHEADER_H - -#include "tlist.h" -#include "tbytevector.h" -#include "taglib_export.h" - -namespace TagLib { - - namespace Ogg { - - class File; - - //! An implementation of the page headers associated with each Ogg::Page - - /*! - * This class implements Ogg page headers which contain the information - * about Ogg pages needed to break them into packets which can be passed on - * to the codecs. - */ - - class TAGLIB_EXPORT PageHeader - { - public: - /*! - * Reads a PageHeader from \a file starting at \a pageOffset. The defaults - * create a page with no (and as such, invalid) data that must be set - * later. - */ - PageHeader(File *file = 0, long pageOffset = -1); - - /*! - * Deletes this instance of the PageHeader. - */ - virtual ~PageHeader(); - - /*! - * Returns true if the header parsed properly and is valid. - */ - bool isValid() const; - - /*! - * Ogg pages contain a list of packets (which are used by the contained - * codecs). The sizes of these pages is encoded in the page header. This - * returns a list of the packet sizes in bytes. - * - * \see setPacketSizes() - */ - List<int> packetSizes() const; - - /*! - * Sets the sizes of the packets in this page to \a sizes. Internally this - * updates the lacing values in the header. - * - * \see packetSizes() - */ - void setPacketSizes(const List<int> &sizes); - - /*! - * Some packets can be <i>continued</i> across multiple pages. If the - * first packet in the current page is a continuation this will return - * true. If this is page starts with a new packet this will return false. - * - * \see lastPacketCompleted() - * \see setFirstPacketContinued() - */ - bool firstPacketContinued() const; - - /*! - * Sets the internal flag indicating if the first packet in this page is - * continued to \a continued. - * - * \see firstPacketContinued() - */ - void setFirstPacketContinued(bool continued); - - /*! - * Returns true if the last packet of this page is completely contained in - * this page. - * - * \see firstPacketContinued() - * \see setLastPacketCompleted() - */ - bool lastPacketCompleted() const; - - /*! - * Sets the internal flag indicating if the last packet in this page is - * complete to \a completed. - * - * \see lastPacketCompleted() - */ - void setLastPacketCompleted(bool completed); - - /*! - * This returns true if this is the first page of the Ogg (logical) stream. - * - * \see setFirstPageOfStream() - */ - bool firstPageOfStream() const; - - /*! - * Marks this page as the first page of the Ogg stream. - * - * \see firstPageOfStream() - */ - void setFirstPageOfStream(bool first); - - /*! - * This returns true if this is the last page of the Ogg (logical) stream. - * - * \see setLastPageOfStream() - */ - bool lastPageOfStream() const; - - /*! - * Marks this page as the last page of the Ogg stream. - * - * \see lastPageOfStream() - */ - void setLastPageOfStream(bool last); - - /*! - * A special value of containing the position of the packet to be - * interpreted by the codec. In the case of Vorbis this contains the PCM - * value and is used to calculate the length of the stream. - * - * \see setAbsoluteGranularPosition() - */ - long long absoluteGranularPosition() const; - - /*! - * A special value of containing the position of the packet to be - * interpreted by the codec. It is only supported here so that it may be - * coppied from one page to another. - * - * \see absoluteGranularPosition() - */ - void setAbsoluteGranularPosition(long long agp); - - /*! - * Every Ogg logical stream is given a random serial number which is common - * to every page in that logical stream. This returns the serial number of - * the stream associated with this packet. - * - * \see setStreamSerialNumber() - */ - uint streamSerialNumber() const; - - /*! - * Every Ogg logical stream is given a random serial number which is common - * to every page in that logical stream. This sets this pages serial - * number. This method should be used when adding new pages to a logical - * stream. - * - * \see streamSerialNumber() - */ - void setStreamSerialNumber(uint n); - - /*! - * Returns the index of the page within the Ogg stream. This helps make it - * possible to determine if pages have been lost. - * - * \see setPageSequenceNumber() - */ - int pageSequenceNumber() const; - - /*! - * Sets the page's position in the stream to \a sequenceNumber. - * - * \see pageSequenceNumber() - */ - void setPageSequenceNumber(int sequenceNumber); - - /*! - * Returns the complete header size. - */ - int size() const; - - /*! - * Returns the size of the data portion of the page -- i.e. the size of the - * page less the header size. - */ - int dataSize() const; - - /*! - * Render the page header to binary data. - * - * \note The checksum -- bytes 22 - 25 -- will be left empty and must be - * filled in when rendering the entire page. - */ - ByteVector render() const; - - private: - PageHeader(const PageHeader &); - PageHeader &operator=(const PageHeader &); - - void read(); - ByteVector lacingValues() const; - - class PageHeaderPrivate; - PageHeaderPrivate *d; - }; - - } -} - -#endif diff --git a/taglib/taglib/ogg/opus/opusfile.cpp b/taglib/taglib/ogg/opus/opusfile.cpp deleted file mode 100644 index cb81a32..0000000 --- a/taglib/taglib/ogg/opus/opusfile.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/*************************************************************************** - 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); -} diff --git a/taglib/taglib/ogg/opus/opusfile.h b/taglib/taglib/ogg/opus/opusfile.h deleted file mode 100644 index 275167e..0000000 --- a/taglib/taglib/ogg/opus/opusfile.h +++ /dev/null @@ -1,124 +0,0 @@ -/*************************************************************************** - 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 diff --git a/taglib/taglib/ogg/opus/opusproperties.cpp b/taglib/taglib/ogg/opus/opusproperties.cpp deleted file mode 100644 index 7bdcd39..0000000 --- a/taglib/taglib/ogg/opus/opusproperties.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/*************************************************************************** - 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."); -} diff --git a/taglib/taglib/ogg/opus/opusproperties.h b/taglib/taglib/ogg/opus/opusproperties.h deleted file mode 100644 index 946f167..0000000 --- a/taglib/taglib/ogg/opus/opusproperties.h +++ /dev/null @@ -1,96 +0,0 @@ -/*************************************************************************** - 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 diff --git a/taglib/taglib/ogg/speex/speexfile.cpp b/taglib/taglib/ogg/speex/speexfile.cpp deleted file mode 100644 index e83f0ad..0000000 --- a/taglib/taglib/ogg/speex/speexfile.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/*************************************************************************** - copyright : (C) 2006 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 "speexfile.h" - -using namespace TagLib; -using namespace TagLib::Ogg; - -class Speex::File::FilePrivate -{ -public: - FilePrivate() : - comment(0), - properties(0) {} - - ~FilePrivate() - { - delete comment; - delete properties; - } - - Ogg::XiphComment *comment; - Properties *properties; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -Speex::File::File(FileName file, bool readProperties, - Properties::ReadStyle propertiesStyle) : Ogg::File(file) -{ - d = new FilePrivate; - if(isOpen()) - read(readProperties, propertiesStyle); -} - -Speex::File::File(IOStream *stream, bool readProperties, - Properties::ReadStyle propertiesStyle) : Ogg::File(stream) -{ - d = new FilePrivate; - if(isOpen()) - read(readProperties, propertiesStyle); -} - -Speex::File::~File() -{ - delete d; -} - -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; -} - -bool Speex::File::save() -{ - if(!d->comment) - d->comment = new Ogg::XiphComment; - - setPacket(1, d->comment->render()); - - return Ogg::File::save(); -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -void Speex::File::read(bool readProperties, Properties::ReadStyle propertiesStyle) -{ - ByteVector speexHeaderData = packet(0); - - if(!speexHeaderData.startsWith("Speex ")) { - debug("Speex::File::read() -- invalid Speex identification header"); - return; - } - - ByteVector commentHeaderData = packet(1); - - d->comment = new Ogg::XiphComment(commentHeaderData); - - if(readProperties) - d->properties = new Properties(this, propertiesStyle); -} diff --git a/taglib/taglib/ogg/speex/speexfile.h b/taglib/taglib/ogg/speex/speexfile.h deleted file mode 100644 index 880e689..0000000 --- a/taglib/taglib/ogg/speex/speexfile.h +++ /dev/null @@ -1,126 +0,0 @@ -/*************************************************************************** - copyright : (C) 2006 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_SPEEXFILE_H -#define TAGLIB_SPEEXFILE_H - -#include "oggfile.h" -#include "xiphcomment.h" - -#include "speexproperties.h" - -namespace TagLib { - - namespace Ogg { - - //! A namespace containing classes for Speex metadata - - namespace Speex { - - //! An implementation of Ogg::File with Speex specific methods - - /*! - * This is the central class in the Ogg Speex 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 Speex specifically. - */ - - class TAGLIB_EXPORT File : public Ogg::File - { - public: - /*! - * 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); - - /*! - * 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); - - /*! - * 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 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: - File(const File &); - File &operator=(const File &); - - void read(bool readProperties, Properties::ReadStyle propertiesStyle); - - class FilePrivate; - FilePrivate *d; - }; - } - } -} - -#endif diff --git a/taglib/taglib/ogg/speex/speexproperties.cpp b/taglib/taglib/ogg/speex/speexproperties.cpp deleted file mode 100644 index 5aaa915..0000000 --- a/taglib/taglib/ogg/speex/speexproperties.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/*************************************************************************** - copyright : (C) 2006 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 "speexproperties.h" -#include "speexfile.h" - -using namespace TagLib; -using namespace TagLib::Ogg; - -class Speex::Properties::PropertiesPrivate -{ -public: - PropertiesPrivate(File *f, ReadStyle s) : - file(f), - style(s), - length(0), - bitrate(0), - sampleRate(0), - channels(0), - speexVersion(0), - vbr(false), - mode(0) {} - - File *file; - ReadStyle style; - int length; - int bitrate; - int sampleRate; - int channels; - int speexVersion; - bool vbr; - int mode; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -Speex::Properties::Properties(File *file, ReadStyle style) : AudioProperties(style) -{ - d = new PropertiesPrivate(file, style); - read(); -} - -Speex::Properties::~Properties() -{ - delete d; -} - -int Speex::Properties::length() const -{ - return d->length; -} - -int Speex::Properties::bitrate() const -{ - return int(float(d->bitrate) / float(1000) + 0.5); -} - -int Speex::Properties::sampleRate() const -{ - return d->sampleRate; -} - -int Speex::Properties::channels() const -{ - return d->channels; -} - -int Speex::Properties::speexVersion() const -{ - return d->speexVersion; -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -void Speex::Properties::read() -{ - // Get the identification header from the Ogg implementation. - - ByteVector data = d->file->packet(0); - - uint pos = 28; - - // speex_version_id; /**< Version for Speex (for checking compatibility) */ - 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.toUInt(pos, false); - pos += 4; - - // mode; /**< Mode used (0 for narrowband, 1 for wideband) */ - 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.toUInt(pos, false); - pos += 4; - - // bitrate; /**< Bit-rate used */ - d->bitrate = data.toUInt(pos, false); - pos += 4; - - // frame_size; /**< Size of frames */ - // unsigned int frameSize = data.mid(pos, 4).toUInt(false); - pos += 4; - - // vbr; /**< 1 for a VBR encoding, 0 otherwise */ - d->vbr = data.toUInt(pos, false) == 1; - pos += 4; - - // frames_per_packet; /**< Number of frames stored per Ogg packet */ - // unsigned int framesPerPacket = data.mid(pos, 4).toUInt(false); - - 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->sampleRate > 0) - d->length = (int) ((end - start) / (long long) d->sampleRate); - else - debug("Speex::Properties::read() -- Either the PCM values for the start or " - "end of this file was incorrect or the sample rate is zero."); - } - else - debug("Speex::Properties::read() -- Could not find valid first and last Ogg pages."); -} diff --git a/taglib/taglib/ogg/speex/speexproperties.h b/taglib/taglib/ogg/speex/speexproperties.h deleted file mode 100644 index 4720bd8..0000000 --- a/taglib/taglib/ogg/speex/speexproperties.h +++ /dev/null @@ -1,89 +0,0 @@ -/*************************************************************************** - copyright : (C) 2006 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_SPEEXPROPERTIES_H -#define TAGLIB_SPEEXPROPERTIES_H - -#include "audioproperties.h" - -namespace TagLib { - - namespace Ogg { - - namespace Speex { - - class File; - - //! An implementation of audio property reading for Ogg Speex - - /*! - * This reads the data from an Ogg Speex stream found in the AudioProperties - * API. - */ - - class TAGLIB_EXPORT Properties : public AudioProperties - { - public: - /*! - * Create an instance of Speex::Properties with the data read from the - * Speex::File \a file. - */ - Properties(File *file, ReadStyle style = Average); - - /*! - * Destroys this Speex::Properties instance. - */ - virtual ~Properties(); - - // Reimplementations. - - virtual int length() const; - virtual int bitrate() const; - virtual int sampleRate() const; - virtual int channels() const; - - /*! - * Returns the Speex version, currently "0" (as specified by the spec). - */ - int speexVersion() const; - - private: - Properties(const Properties &); - Properties &operator=(const Properties &); - - void read(); - - class PropertiesPrivate; - PropertiesPrivate *d; - }; - } - } -} - -#endif diff --git a/taglib/taglib/ogg/vorbis/vorbisfile.cpp b/taglib/taglib/ogg/vorbis/vorbisfile.cpp deleted file mode 100644 index 8298453..0000000 --- a/taglib/taglib/ogg/vorbis/vorbisfile.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <bitset> - -#include <tstring.h> -#include <tdebug.h> -#include <tpropertymap.h> - -#include "vorbisfile.h" - - -using namespace TagLib; - -class Vorbis::File::FilePrivate -{ -public: - FilePrivate() : - comment(0), - properties(0) {} - - ~FilePrivate() - { - delete comment; - delete properties; - } - - Ogg::XiphComment *comment; - Properties *properties; -}; - -namespace TagLib { - /*! - * Vorbis headers can be found with one type ID byte and the string "vorbis" in - * an Ogg stream. 0x03 indicates the comment header. - */ - static const char vorbisCommentHeaderID[] = { 0x03, 'v', 'o', 'r', 'b', 'i', 's', 0 }; -} - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -Vorbis::File::File(FileName file, bool readProperties, - Properties::ReadStyle propertiesStyle) : Ogg::File(file) -{ - d = new FilePrivate; - if(isOpen()) - read(readProperties, propertiesStyle); -} - -Vorbis::File::File(IOStream *stream, bool readProperties, - Properties::ReadStyle propertiesStyle) : Ogg::File(stream) -{ - d = new FilePrivate; - if(isOpen()) - read(readProperties, propertiesStyle); -} - -Vorbis::File::~File() -{ - delete d; -} - -Ogg::XiphComment *Vorbis::File::tag() const -{ - return d->comment; -} - -PropertyMap Vorbis::File::properties() const -{ - return d->comment->properties(); -} - -PropertyMap Vorbis::File::setProperties(const PropertyMap &properties) -{ - return d->comment->setProperties(properties); -} - -Vorbis::Properties *Vorbis::File::audioProperties() const -{ - return d->properties; -} - -bool Vorbis::File::save() -{ - ByteVector v(vorbisCommentHeaderID); - - if(!d->comment) - d->comment = new Ogg::XiphComment; - v.append(d->comment->render()); - - setPacket(1, v); - - return Ogg::File::save(); -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -void Vorbis::File::read(bool readProperties, Properties::ReadStyle propertiesStyle) -{ - ByteVector commentHeaderData = packet(1); - - if(commentHeaderData.mid(0, 7) != vorbisCommentHeaderID) { - debug("Vorbis::File::read() - Could not find the Vorbis comment header."); - setValid(false); - return; - } - - d->comment = new Ogg::XiphComment(commentHeaderData.mid(7)); - - if(readProperties) - d->properties = new Properties(this, propertiesStyle); -} diff --git a/taglib/taglib/ogg/vorbis/vorbisfile.h b/taglib/taglib/ogg/vorbis/vorbisfile.h deleted file mode 100644 index 7735a11..0000000 --- a/taglib/taglib/ogg/vorbis/vorbisfile.h +++ /dev/null @@ -1,144 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_VORBISFILE_H -#define TAGLIB_VORBISFILE_H - -#include "taglib_export.h" -#include "oggfile.h" -#include "xiphcomment.h" - -#include "vorbisproperties.h" - -namespace TagLib { - -/* - * This is just to make this appear to be in the Ogg namespace in the - * documentation. The typedef below will make this work with the current code. - * In the next BIC version of TagLib this will be really moved into the Ogg - * namespace. - */ - -#ifdef DOXYGEN - namespace Ogg { -#endif - - //! A namespace containing classes for Vorbis metadata - - namespace Vorbis { - - - //! An implementation of Ogg::File with Vorbis specific methods - - /*! - * This is the central class in the Ogg Vorbis 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 Vorbis specifically. - */ - - class TAGLIB_EXPORT File : public Ogg::File - { - public: - /*! - * 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); - - /*! - * 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); - - /*! - * 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 Vorbis::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; - }; - } - -/* - * To keep compatibility with the current version put Vorbis in the Ogg namespace - * only in the docs and provide a typedef to make it work. In the next BIC - * version this will be removed and it will only exist in the Ogg namespace. - */ - -#ifdef DOXYGEN - } -#else - namespace Ogg { namespace Vorbis { typedef TagLib::Vorbis::File File; } } -#endif - -} - -#endif diff --git a/taglib/taglib/ogg/vorbis/vorbisproperties.cpp b/taglib/taglib/ogg/vorbis/vorbisproperties.cpp deleted file mode 100644 index b5e88bf..0000000 --- a/taglib/taglib/ogg/vorbis/vorbisproperties.cpp +++ /dev/null @@ -1,183 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <tstring.h> -#include <tdebug.h> - -#include <oggpageheader.h> - -#include "vorbisproperties.h" -#include "vorbisfile.h" - -using namespace TagLib; - -class Vorbis::Properties::PropertiesPrivate -{ -public: - PropertiesPrivate(File *f, ReadStyle s) : - file(f), - style(s), - length(0), - bitrate(0), - sampleRate(0), - channels(0), - vorbisVersion(0), - bitrateMaximum(0), - bitrateNominal(0), - bitrateMinimum(0) {} - - File *file; - ReadStyle style; - int length; - int bitrate; - int sampleRate; - int channels; - int vorbisVersion; - int bitrateMaximum; - int bitrateNominal; - int bitrateMinimum; -}; - -namespace TagLib { - /*! - * Vorbis headers can be found with one type ID byte and the string "vorbis" in - * an Ogg stream. 0x01 indicates the setup header. - */ - static const char vorbisSetupHeaderID[] = { 0x01, 'v', 'o', 'r', 'b', 'i', 's', 0 }; -} - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -Vorbis::Properties::Properties(File *file, ReadStyle style) : AudioProperties(style) -{ - d = new PropertiesPrivate(file, style); - read(); -} - -Vorbis::Properties::~Properties() -{ - delete d; -} - -int Vorbis::Properties::length() const -{ - return d->length; -} - -int Vorbis::Properties::bitrate() const -{ - return int(float(d->bitrate) / float(1000) + 0.5); -} - -int Vorbis::Properties::sampleRate() const -{ - return d->sampleRate; -} - -int Vorbis::Properties::channels() const -{ - return d->channels; -} - -int Vorbis::Properties::vorbisVersion() const -{ - return d->vorbisVersion; -} - -int Vorbis::Properties::bitrateMaximum() const -{ - return d->bitrateMaximum; -} - -int Vorbis::Properties::bitrateNominal() const -{ - return d->bitrateNominal; -} - -int Vorbis::Properties::bitrateMinimum() const -{ - return d->bitrateMinimum; -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -void Vorbis::Properties::read() -{ - // Get the identification header from the Ogg implementation. - - ByteVector data = d->file->packet(0); - - uint pos = 0; - - if(data.mid(pos, 7) != vorbisSetupHeaderID) { - debug("Vorbis::Properties::read() -- invalid Vorbis identification header"); - return; - } - - pos += 7; - - d->vorbisVersion = data.toUInt(pos, false); - pos += 4; - - d->channels = uchar(data[pos]); - pos += 1; - - d->sampleRate = data.toUInt(pos, false); - pos += 4; - - d->bitrateMaximum = data.toUInt(pos, false); - pos += 4; - - d->bitrateNominal = data.toUInt(pos, false); - pos += 4; - - d->bitrateMinimum = data.toUInt(pos, false); - - // TODO: Later this should be only the "fast" mode. - d->bitrate = d->bitrateNominal; - - // Find the length of the file. See http://wiki.xiph.org/VorbisStreamLength/ - // for my notes on the topic. - - 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->sampleRate > 0) - 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."); - } - else - debug("Vorbis::Properties::read() -- Could not find valid first and last Ogg pages."); -} diff --git a/taglib/taglib/ogg/vorbis/vorbisproperties.h b/taglib/taglib/ogg/vorbis/vorbisproperties.h deleted file mode 100644 index de46985..0000000 --- a/taglib/taglib/ogg/vorbis/vorbisproperties.h +++ /dev/null @@ -1,125 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_VORBISPROPERTIES_H -#define TAGLIB_VORBISPROPERTIES_H - -#include "taglib_export.h" -#include "audioproperties.h" - -namespace TagLib { - -/* - * This is just to make this appear to be in the Ogg namespace in the - * documentation. The typedef below will make this work with the current code. - * In the next BIC version of TagLib this will be really moved into the Ogg - * namespace. - */ - -#ifdef DOXYGEN - namespace Ogg { -#endif - - namespace Vorbis { - - class File; - - //! An implementation of audio property reading for Ogg Vorbis - - /*! - * This reads the data from an Ogg Vorbis stream found in the AudioProperties - * API. - */ - - class TAGLIB_EXPORT Properties : public AudioProperties - { - public: - /*! - * Create an instance of Vorbis::Properties with the data read from the - * Vorbis::File \a file. - */ - Properties(File *file, ReadStyle style = Average); - - /*! - * Destroys this VorbisProperties instance. - */ - virtual ~Properties(); - - // Reimplementations. - - virtual int length() const; - virtual int bitrate() const; - virtual int sampleRate() const; - virtual int channels() const; - - /*! - * Returns the Vorbis version, currently "0" (as specified by the spec). - */ - int vorbisVersion() const; - - /*! - * Returns the maximum bitrate as read from the Vorbis identification - * header. - */ - int bitrateMaximum() const; - - /*! - * Returns the nominal bitrate as read from the Vorbis identification - * header. - */ - int bitrateNominal() const; - - /*! - * Returns the minimum bitrate as read from the Vorbis identification - * header. - */ - int bitrateMinimum() const; - - private: - Properties(const Properties &); - Properties &operator=(const Properties &); - - void read(); - - class PropertiesPrivate; - PropertiesPrivate *d; - }; - } - -/* - * To keep compatibility with the current version put Vorbis in the Ogg namespace - * only in the docs and provide a typedef to make it work. In the next BIC - * version this will be removed and it will only exist in the Ogg namespace. - */ - -#ifdef DOXYGEN - } -#else - namespace Ogg { namespace Vorbis { typedef TagLib::AudioProperties AudioProperties; } } -#endif - -} - -#endif diff --git a/taglib/taglib/ogg/xiphcomment.cpp b/taglib/taglib/ogg/xiphcomment.cpp deleted file mode 100644 index 51c2f9f..0000000 --- a/taglib/taglib/ogg/xiphcomment.cpp +++ /dev/null @@ -1,382 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <tbytevector.h> -#include <tdebug.h> - -#include <xiphcomment.h> -#include <tpropertymap.h> - -using namespace TagLib; - -class Ogg::XiphComment::XiphCommentPrivate -{ -public: - FieldListMap fieldListMap; - String vendorID; - String commentField; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -Ogg::XiphComment::XiphComment() : TagLib::Tag() -{ - d = new XiphCommentPrivate; -} - -Ogg::XiphComment::XiphComment(const ByteVector &data) : TagLib::Tag() -{ - d = new XiphCommentPrivate; - parse(data); -} - -Ogg::XiphComment::~XiphComment() -{ - delete d; -} - -String Ogg::XiphComment::title() const -{ - if(d->fieldListMap["TITLE"].isEmpty()) - return String::null; - return d->fieldListMap["TITLE"].front(); -} - -String Ogg::XiphComment::artist() const -{ - if(d->fieldListMap["ARTIST"].isEmpty()) - return String::null; - return d->fieldListMap["ARTIST"].front(); -} - -String Ogg::XiphComment::album() const -{ - if(d->fieldListMap["ALBUM"].isEmpty()) - return String::null; - return d->fieldListMap["ALBUM"].front(); -} - -String Ogg::XiphComment::comment() const -{ - if(!d->fieldListMap["DESCRIPTION"].isEmpty()) { - d->commentField = "DESCRIPTION"; - return d->fieldListMap["DESCRIPTION"].front(); - } - - if(!d->fieldListMap["COMMENT"].isEmpty()) { - d->commentField = "COMMENT"; - return d->fieldListMap["COMMENT"].front(); - } - - return String::null; -} - -String Ogg::XiphComment::genre() const -{ - if(d->fieldListMap["GENRE"].isEmpty()) - return String::null; - return d->fieldListMap["GENRE"].front(); -} - -TagLib::uint Ogg::XiphComment::year() const -{ - if(!d->fieldListMap["DATE"].isEmpty()) - return d->fieldListMap["DATE"].front().toInt(); - if(!d->fieldListMap["YEAR"].isEmpty()) - return d->fieldListMap["YEAR"].front().toInt(); - return 0; -} - -TagLib::uint Ogg::XiphComment::track() const -{ - if(!d->fieldListMap["TRACKNUMBER"].isEmpty()) - return d->fieldListMap["TRACKNUMBER"].front().toInt(); - if(!d->fieldListMap["TRACKNUM"].isEmpty()) - return d->fieldListMap["TRACKNUM"].front().toInt(); - return 0; -} - -void Ogg::XiphComment::setTitle(const String &s) -{ - addField("TITLE", s); -} - -void Ogg::XiphComment::setArtist(const String &s) -{ - addField("ARTIST", s); -} - -void Ogg::XiphComment::setAlbum(const String &s) -{ - addField("ALBUM", s); -} - -void Ogg::XiphComment::setComment(const String &s) -{ - addField(d->commentField.isEmpty() ? "DESCRIPTION" : d->commentField, s); -} - -void Ogg::XiphComment::setGenre(const String &s) -{ - addField("GENRE", s); -} - -void Ogg::XiphComment::setYear(uint i) -{ - removeField("YEAR"); - if(i == 0) - removeField("DATE"); - else - addField("DATE", String::number(i)); -} - -void Ogg::XiphComment::setTrack(uint i) -{ - removeField("TRACKNUM"); - if(i == 0) - removeField("TRACKNUMBER"); - else - addField("TRACKNUMBER", String::number(i)); -} - -bool Ogg::XiphComment::isEmpty() const -{ - FieldListMap::ConstIterator it = d->fieldListMap.begin(); - for(; it != d->fieldListMap.end(); ++it) - if(!(*it).second.isEmpty()) - return false; - - return true; -} - -TagLib::uint Ogg::XiphComment::fieldCount() const -{ - uint count = 0; - - FieldListMap::ConstIterator it = d->fieldListMap.begin(); - for(; it != d->fieldListMap.end(); ++it) - count += (*it).second.size(); - - return count; -} - -const Ogg::FieldListMap &Ogg::XiphComment::fieldListMap() const -{ - return d->fieldListMap; -} - -PropertyMap Ogg::XiphComment::properties() const -{ - return d->fieldListMap; -} - -PropertyMap Ogg::XiphComment::setProperties(const PropertyMap &properties) -{ - // check which keys are to be deleted - StringList toRemove; - for(FieldListMap::ConstIterator it = d->fieldListMap.begin(); it != d->fieldListMap.end(); ++it) - if (!properties.contains(it->first)) - toRemove.append(it->first); - - 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 - PropertyMap invalid; - PropertyMap::ConstIterator it = properties.begin(); - for(; it != properties.end(); ++it) - { - 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 - removeField(it->first); - else { - // replace all strings in the list for the tag - StringList::ConstIterator valueIterator = sl.begin(); - addField(it->first, *valueIterator, true); - ++valueIterator; - for(; valueIterator != sl.end(); ++valueIterator) - addField(it->first, *valueIterator, false); - } - } - } - 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 -{ - return d->vendorID; -} - -void Ogg::XiphComment::addField(const String &key, const String &value, bool replace) -{ - if(replace) - removeField(key.upper()); - - if(!key.isEmpty() && !value.isEmpty()) - d->fieldListMap[key.upper()].append(value); -} - -void Ogg::XiphComment::removeField(const String &key, const String &value) -{ - if(!value.isNull()) { - StringList::Iterator it = d->fieldListMap[key].begin(); - while(it != d->fieldListMap[key].end()) { - if(value == *it) - it = d->fieldListMap[key].erase(it); - else - it++; - } - } - else - d->fieldListMap.erase(key); -} - -bool Ogg::XiphComment::contains(const String &key) const -{ - return d->fieldListMap.contains(key) && !d->fieldListMap[key].isEmpty(); -} - -ByteVector Ogg::XiphComment::render() const -{ - return render(true); -} - -ByteVector Ogg::XiphComment::render(bool addFramingBit) const -{ - ByteVector data; - - // Add the vendor ID length and the vendor ID. It's important to use the - // length of the data(String::UTF8) rather than the length of the the string - // since this is UTF8 text and there may be more characters in the data than - // in the UTF16 string. - - ByteVector vendorData = d->vendorID.data(String::UTF8); - - data.append(ByteVector::fromUInt(vendorData.size(), false)); - data.append(vendorData); - - // Add the number of fields. - - data.append(ByteVector::fromUInt(fieldCount(), false)); - - // Iterate over the the field lists. Our iterator returns a - // std::pair<String, StringList> where the first String is the field name and - // the StringList is the values associated with that field. - - FieldListMap::ConstIterator it = d->fieldListMap.begin(); - for(; it != d->fieldListMap.end(); ++it) { - - // And now iterate over the values of the current list. - - String fieldName = (*it).first; - StringList values = (*it).second; - - StringList::ConstIterator valuesIt = values.begin(); - for(; valuesIt != values.end(); ++valuesIt) { - ByteVector fieldData = fieldName.data(String::UTF8); - fieldData.append('='); - fieldData.append((*valuesIt).data(String::UTF8)); - - data.append(ByteVector::fromUInt(fieldData.size(), false)); - data.append(fieldData); - } - } - - // Append the "framing bit". - - if(addFramingBit) - data.append(char(1)); - - return data; -} - -//////////////////////////////////////////////////////////////////////////////// -// protected members -//////////////////////////////////////////////////////////////////////////////// - -void Ogg::XiphComment::parse(const ByteVector &data) -{ - // The first thing in the comment data is the vendor ID length, followed by a - // UTF8 string with the vendor ID. - - uint pos = 0; - - const uint vendorLength = data.toUInt(0, false); - pos += 4; - - d->vendorID = String(data.mid(pos, vendorLength), String::UTF8); - pos += vendorLength; - - // Next the number of fields in the comment vector. - - const uint commentFields = data.toUInt(pos, false); - pos += 4; - - if(commentFields > (data.size() - 8) / 4) { - return; - } - - for(uint i = 0; i < commentFields; i++) { - - // 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. - - const uint commentLength = data.toUInt(pos, false); - pos += 4; - - String comment = String(data.mid(pos, commentLength), String::UTF8); - pos += commentLength; - if(pos > data.size()) { - break; - } - - int commentSeparatorPosition = comment.find("="); - if(commentSeparatorPosition == -1) { - break; - } - - String key = comment.substr(0, commentSeparatorPosition); - String value = comment.substr(commentSeparatorPosition + 1); - - addField(key, value, false); - } -} diff --git a/taglib/taglib/ogg/xiphcomment.h b/taglib/taglib/ogg/xiphcomment.h deleted file mode 100644 index 54f3070..0000000 --- a/taglib/taglib/ogg/xiphcomment.h +++ /dev/null @@ -1,225 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_VORBISCOMMENT_H -#define TAGLIB_VORBISCOMMENT_H - -#include "tag.h" -#include "tlist.h" -#include "tmap.h" -#include "tstring.h" -#include "tstringlist.h" -#include "tbytevector.h" -#include "taglib_export.h" - -namespace TagLib { - - namespace Ogg { - - /*! - * A mapping between a list of field names, or keys, and a list of values - * associated with that field. - * - * \see XiphComment::fieldListMap() - */ - typedef Map<String, StringList> FieldListMap; - - //! Ogg Vorbis comment implementation - - /*! - * This class is an implementation of the Ogg Vorbis comment specification, - * to be found in section 5 of the Ogg Vorbis specification. Because this - * format is also used in other (currently unsupported) Xiph.org formats, it - * has been made part of a generic implementation rather than being limited - * to strictly Vorbis. - * - * Vorbis comments are a simple vector of keys and values, called fields. - * Multiple values for a given key are supported. - * - * \see fieldListMap() - */ - - class TAGLIB_EXPORT XiphComment : public TagLib::Tag - { - public: - /*! - * Constructs an empty Vorbis comment. - */ - XiphComment(); - - /*! - * Constructs a Vorbis comment from \a data. - */ - XiphComment(const ByteVector &data); - - /*! - * Destroys this instance of the XiphComment. - */ - virtual ~XiphComment(); - - virtual String title() const; - virtual String artist() const; - virtual String album() const; - virtual String comment() const; - virtual String genre() const; - virtual uint year() const; - virtual 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 bool isEmpty() const; - - /*! - * Returns the number of fields present in the comment. - */ - uint fieldCount() const; - - /*! - * Returns a reference to the map of field lists. Because Xiph comments - * support multiple fields with the same key, a pure Map would not work. - * As such this is a Map of string lists, keyed on the comment field name. - * - * The standard set of Xiph/Vorbis fields (which may or may not be - * contained in any specific comment) is: - * - * <ul> - * <li>TITLE</li> - * <li>VERSION</li> - * <li>ALBUM</li> - * <li>ARTIST</li> - * <li>PERFORMER</li> - * <li>COPYRIGHT</li> - * <li>ORGANIZATION</li> - * <li>DESCRIPTION</li> - * <li>GENRE</li> - * <li>DATE</li> - * <li>LOCATION</li> - * <li>CONTACT</li> - * <li>ISRC</li> - * </ul> - * - * For a more detailed description of these fields, please see the Ogg - * Vorbis specification, section 5.2.2.1. - * - * \note The Ogg Vorbis comment specification does allow these key values - * to be either upper or lower case. However, it is conventional for them - * to be upper case. As such, TagLib, when parsing a Xiph/Vorbis comment, - * converts all fields to uppercase. When you are using this data - * structure, you will need to specify the field name in upper case. - * - * \warning You should not modify this data structure directly, instead - * use addField() and removeField(). - */ - const FieldListMap &fieldListMap() const; - - /*! - * Implements the unified property interface -- export function. - * The result is a one-to-one match of the Xiph comment, since it is - * completely compatible with the property interface (in fact, a Xiph - * comment is nothing more than a map from tag names to list of values, - * as is the dict interface). - */ - PropertyMap properties() const; - - /*! - * Implements the unified property interface -- import function. - * 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". - */ - String vendorID() const; - - /*! - * Add the field specified by \a key with the data \a value. If \a replace - * is true, then all of the other fields with the same key will be removed - * first. - * - * If the field value is empty, the field will be removed. - */ - void addField(const String &key, const String &value, bool replace = true); - - /*! - * Remove the field specified by \a key with the data \a value. If - * \a value is null, all of the fields with the given key will be removed. - */ - void removeField(const String &key, const String &value = String::null); - - /*! - * Returns true if the field is contained within the comment. - * - * \note This is safer than checking for membership in the FieldListMap. - */ - bool contains(const String &key) const; - - /*! - * Renders the comment to a ByteVector suitable for inserting into a file. - */ - ByteVector render() const; // BIC: remove and merge with below - - /*! - * Renders the comment to a ByteVector suitable for inserting into a file. - * - * If \a addFramingBit is true the standard Vorbis comment framing bit will - * be appended. However some formats (notably FLAC) do not work with this - * in place. - */ - ByteVector render(bool addFramingBit) const; - - protected: - /*! - * Reads the tag from the file specified in the constructor and fills the - * FieldListMap. - */ - void parse(const ByteVector &data); - - private: - XiphComment(const XiphComment &); - XiphComment &operator=(const XiphComment &); - - class XiphCommentPrivate; - XiphCommentPrivate *d; - }; - } -} - -#endif diff --git a/taglib/taglib/riff/aiff/aifffile.cpp b/taglib/taglib/riff/aiff/aifffile.cpp deleted file mode 100644 index d20c148..0000000 --- a/taglib/taglib/riff/aiff/aifffile.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/*************************************************************************** - copyright : (C) 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <tbytevector.h> -#include <tdebug.h> -#include <id3v2tag.h> -#include <tstringlist.h> -#include <tpropertymap.h> - -#include "aifffile.h" - -using namespace TagLib; - -class RIFF::AIFF::File::FilePrivate -{ -public: - FilePrivate() : - properties(0), - tag(0), - tagChunkID("ID3 ") - { - - } - - ~FilePrivate() - { - delete properties; - delete tag; - } - - Properties *properties; - ID3v2::Tag *tag; - ByteVector tagChunkID; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -RIFF::AIFF::File::File(FileName file, bool readProperties, - Properties::ReadStyle propertiesStyle) : RIFF::File(file, BigEndian) -{ - d = new FilePrivate; - if(isOpen()) - read(readProperties, propertiesStyle); -} - -RIFF::AIFF::File::File(IOStream *stream, bool readProperties, - Properties::ReadStyle propertiesStyle) : RIFF::File(stream, BigEndian) -{ - d = new FilePrivate; - if(isOpen()) - read(readProperties, propertiesStyle); -} - -RIFF::AIFF::File::~File() -{ - delete d; -} - -ID3v2::Tag *RIFF::AIFF::File::tag() const -{ - return d->tag; -} - -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); -} - - -RIFF::AIFF::Properties *RIFF::AIFF::File::audioProperties() const -{ - return d->properties; -} - -bool RIFF::AIFF::File::save() -{ - if(readOnly()) { - debug("RIFF::AIFF::File::save() -- File is read only."); - return false; - } - - if(!isValid()) { - debug("RIFF::AIFF::File::save() -- Trying to save invalid file."); - return false; - } - - setChunkData(d->tagChunkID, d->tag->render()); - - return true; -} - - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -void RIFF::AIFF::File::read(bool readProperties, Properties::ReadStyle propertiesStyle) -{ - for(uint i = 0; i < chunkCount(); i++) { - if(chunkName(i) == "ID3 " || chunkName(i) == "id3 ") { - d->tagChunkID = chunkName(i); - d->tag = new ID3v2::Tag(this, chunkOffset(i)); - } - else if(chunkName(i) == "COMM" && readProperties) - d->properties = new Properties(chunkData(i), propertiesStyle); - } - - if(!d->tag) - d->tag = new ID3v2::Tag; -} diff --git a/taglib/taglib/riff/aiff/aifffile.h b/taglib/taglib/riff/aiff/aifffile.h deleted file mode 100644 index c75b94b..0000000 --- a/taglib/taglib/riff/aiff/aifffile.h +++ /dev/null @@ -1,142 +0,0 @@ -/*************************************************************************** - copyright : (C) 2008 by Scott Wheeler - email : wheeler@kde.org -***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_AIFFFILE_H -#define TAGLIB_AIFFFILE_H - -#include "rifffile.h" -#include "id3v2tag.h" -#include "aiffproperties.h" - -namespace TagLib { - - namespace RIFF { - - //! An implementation of AIFF metadata - - /*! - * This is implementation of AIFF metadata. - * - * This supports an ID3v2 tag as well as reading stream from the ID3 RIFF - * chunk as well as properties from the file. - */ - - namespace AIFF { - - //! An implementation of TagLib::File with AIFF specific methods - - /*! - * This implements and provides an interface for AIFF 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 AIFF files. - */ - - class TAGLIB_EXPORT File : public TagLib::RIFF::File - { - public: - /*! - * 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); - - /*! - * 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); - - /*! - * Destroys this instance of the File. - */ - virtual ~File(); - - /*! - * 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; - - /*! - * Implements the unified property interface -- export function. - * This method forwards to ID3v2::Tag::properties(). - */ - PropertyMap properties() const; - - void removeUnsupportedProperties(const StringList &properties); - - /*! - * Implements the unified property interface -- import function. - * This method forwards to ID3v2::Tag::setProperties(). - */ - PropertyMap setProperties(const PropertyMap &); - - /*! - * Returns the AIFF::Properties for this file. If no audio properties - * were read then this will return a null pointer. - */ - virtual Properties *audioProperties() const; - - /*! - * Saves the file. - */ - 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 &); - - void read(bool readProperties, Properties::ReadStyle propertiesStyle); - - class FilePrivate; - FilePrivate *d; - }; - } - } -} - -#endif diff --git a/taglib/taglib/riff/aiff/aiffproperties.cpp b/taglib/taglib/riff/aiff/aiffproperties.cpp deleted file mode 100644 index 18b973e..0000000 --- a/taglib/taglib/riff/aiff/aiffproperties.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/*************************************************************************** - copyright : (C) 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <tstring.h> -#include <tdebug.h> -#include <cmath> -// ldexp is a c99 function, which might not be defined in <cmath> -// so we pull in math.h too and hope it does the right (wrong) thing -// wrt. c99 functions in C++ -#include <math.h> - -#include "aiffproperties.h" - -//////////////////////////////////////////////////////////////////////////////// -// nasty 80-bit float helpers -//////////////////////////////////////////////////////////////////////////////// - -#define UnsignedToFloat(u) (((double)((long)(u - 2147483647L - 1))) + 2147483648.0) - -static double ConvertFromIeeeExtended(const TagLib::uchar *bytes) -{ - double f; - int expon; - unsigned long hiMant, loMant; - - expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF); - - hiMant = ((unsigned long)(bytes[2] & 0xFF) << 24) | - ((unsigned long)(bytes[3] & 0xFF) << 16) | - ((unsigned long)(bytes[4] & 0xFF) << 8) | - ((unsigned long)(bytes[5] & 0xFF)); - - loMant = ((unsigned long)(bytes[6] & 0xFF) << 24) | - ((unsigned long)(bytes[7] & 0xFF) << 16) | - ((unsigned long)(bytes[8] & 0xFF) << 8) | - ((unsigned long)(bytes[9] & 0xFF)); - - if (expon == 0 && hiMant == 0 && loMant == 0) - f = 0; - else { - if(expon == 0x7FFF) /* Infinity or NaN */ - f = HUGE_VAL; - else { - expon -= 16383; - f = ldexp(UnsignedToFloat(hiMant), expon -= 31); - f += ldexp(UnsignedToFloat(loMant), expon -= 32); - } - } - - if(bytes[0] & 0x80) - return -f; - else - return f; -} - -using namespace TagLib; - -class RIFF::AIFF::Properties::PropertiesPrivate -{ -public: - PropertiesPrivate() : - length(0), - bitrate(0), - sampleRate(0), - channels(0), - sampleWidth(0), - sampleFrames(0) - { - - } - - int length; - int bitrate; - int sampleRate; - int channels; - int sampleWidth; - uint sampleFrames; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -RIFF::AIFF::Properties::Properties(const ByteVector &data, ReadStyle style) : AudioProperties(style) -{ - d = new PropertiesPrivate; - read(data); -} - -RIFF::AIFF::Properties::~Properties() -{ - delete d; -} - -int RIFF::AIFF::Properties::length() const -{ - return d->length; -} - -int RIFF::AIFF::Properties::bitrate() const -{ - return d->bitrate; -} - -int RIFF::AIFF::Properties::sampleRate() const -{ - return d->sampleRate; -} - -int RIFF::AIFF::Properties::channels() const -{ - return d->channels; -} - -int RIFF::AIFF::Properties::sampleWidth() const -{ - return d->sampleWidth; -} - -TagLib::uint RIFF::AIFF::Properties::sampleFrames() const -{ - return d->sampleFrames; -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -void RIFF::AIFF::Properties::read(const ByteVector &data) -{ - 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; -} diff --git a/taglib/taglib/riff/aiff/aiffproperties.h b/taglib/taglib/riff/aiff/aiffproperties.h deleted file mode 100644 index 68e90b7..0000000 --- a/taglib/taglib/riff/aiff/aiffproperties.h +++ /dev/null @@ -1,83 +0,0 @@ -/*************************************************************************** - copyright : (C) 2008 by Scott Wheeler - email : wheeler@kde.org -***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_AIFFPROPERTIES_H -#define TAGLIB_AIFFPROPERTIES_H - -#include "audioproperties.h" - -namespace TagLib { - - namespace RIFF { - - namespace AIFF { - - class File; - - //! An implementation of audio property reading for AIFF - - /*! - * This reads the data from an AIFF stream found in the AudioProperties - * API. - */ - - class TAGLIB_EXPORT Properties : public AudioProperties - { - public: - /*! - * Create an instance of AIFF::Properties with the data read from the - * ByteVector \a data. - */ - Properties(const ByteVector &data, ReadStyle style); - - /*! - * Destroys this AIFF::Properties instance. - */ - virtual ~Properties(); - - // Reimplementations. - - virtual int length() const; - virtual int bitrate() const; - virtual int sampleRate() const; - virtual int channels() const; - - int sampleWidth() const; - uint sampleFrames() const; - - private: - Properties(const Properties &); - Properties &operator=(const Properties &); - - void read(const ByteVector &data); - - class PropertiesPrivate; - PropertiesPrivate *d; - }; - } - } -} - -#endif diff --git a/taglib/taglib/riff/rifffile.cpp b/taglib/taglib/riff/rifffile.cpp deleted file mode 100644 index a39fce6..0000000 --- a/taglib/taglib/riff/rifffile.cpp +++ /dev/null @@ -1,321 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <tbytevector.h> -#include <tdebug.h> -#include <tstring.h> - -#include "rifffile.h" -#include <algorithm> -#include <vector> - -using namespace TagLib; - -struct Chunk -{ - ByteVector name; - TagLib::uint offset; - TagLib::uint size; - char padding; -}; - -class RIFF::File::FilePrivate -{ -public: - FilePrivate() : - endianness(BigEndian), - size(0) - { - - } - Endianness endianness; - ByteVector type; - TagLib::uint size; - ByteVector format; - - std::vector<Chunk> chunks; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -RIFF::File::~File() -{ - delete d; -} - -//////////////////////////////////////////////////////////////////////////////// -// protected members -//////////////////////////////////////////////////////////////////////////////// - -RIFF::File::File(FileName file, Endianness endianness) : TagLib::File(file) -{ - d = new FilePrivate; - d->endianness = endianness; - - if(isOpen()) - read(); -} - -RIFF::File::File(IOStream *stream, Endianness endianness) : TagLib::File(stream) -{ - d = new FilePrivate; - d->endianness = endianness; - - if(isOpen()) - read(); -} - -TagLib::uint RIFF::File::riffSize() const -{ - return d->size; -} - -TagLib::uint RIFF::File::chunkCount() const -{ - return d->chunks.size(); -} - -TagLib::uint RIFF::File::chunkDataSize(uint i) const -{ - return d->chunks[i].size; -} - -TagLib::uint RIFF::File::chunkOffset(uint i) const -{ - return d->chunks[i].offset; -} - -TagLib::uint RIFF::File::chunkPadding(uint i) const -{ - return d->chunks[i].padding; -} - -ByteVector RIFF::File::chunkName(uint i) const -{ - if(i >= chunkCount()) - return ByteVector::null; - - return d->chunks[i].name; -} - -ByteVector RIFF::File::chunkData(uint i) -{ - if(i >= chunkCount()) - return ByteVector::null; - - // Offset for the first subchunk's data - - long begin = 12 + 8; - - for(uint it = 0; it < i; it++) - begin += 8 + d->chunks[it].size + d->chunks[it].padding; - - seek(begin); - - 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; - } - - if(alwaysCreate && name != "LIST") { - debug("RIFF::File::setChunkData - alwaysCreate should be used for only \"LIST\" chunks."); - return; - } - - if(!alwaysCreate) { - for(uint i = 0; i < d->chunks.size(); i++) { - if(d->chunks[i].name == name) { - setChunkData(i, data); - return; - } - } - } - - // Couldn't find an existing chunk, so let's create a new one. - - uint i = d->chunks.size() - 1; - ulong offset = d->chunks[i].offset + d->chunks[i].size; - - // First we update the global size - - d->size += (offset & 1) + data.size() + 8; - insert(ByteVector::fromUInt(d->size, d->endianness == BigEndian), 4, 4); - - // Now add the chunk to the file - - writeChunk(name, data, offset, std::max<long>(0, length() - offset), (offset & 1) ? 1 : 0); - - // And update our internal structure - - if (offset & 1) { - d->chunks[i].padding = 1; - offset++; - } - - Chunk chunk; - chunk.name = name; - chunk.size = data.size(); - chunk.offset = offset + 8; - chunk.padding = (data.size() & 0x01) ? 1 : 0; - - 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 -//////////////////////////////////////////////////////////////////////////////// - -static bool isValidChunkID(const ByteVector &name) -{ - if(name.size() != 4) { - return false; - } - for(int i = 0; i < 4; i++) { - if(name[i] < 32 || name[i] > 127) { - return false; - } - } - return true; -} - -void RIFF::File::read() -{ - bool bigEndian = (d->endianness == BigEndian); - - d->type = readBlock(4); - d->size = readBlock(4).toUInt(bigEndian); - d->format = readBlock(4); - - // + 8: chunk header at least, fix for additional junk bytes - while(tell() + 8 <= length()) { - ByteVector chunkName = readBlock(4); - uint chunkSize = readBlock(4).toUInt(bigEndian); - - if(!isValidChunkID(chunkName)) { - debug("RIFF::File::read() -- Chunk '" + chunkName + "' has invalid ID"); - setValid(false); - break; - } - - if(static_cast<ulonglong>(tell()) + chunkSize > static_cast<ulonglong>(length())) { - debug("RIFF::File::read() -- Chunk '" + chunkName + "' has invalid size (larger than the file size)"); - setValid(false); - break; - } - - Chunk chunk; - chunk.name = chunkName; - chunk.size = chunkSize; - chunk.offset = tell(); - - seek(chunk.size, Current); - - // check padding - chunk.padding = 0; - long uPosNotPadded = tell(); - if((uPosNotPadded & 0x01) != 0) { - ByteVector iByte = readBlock(1); - if((iByte.size() != 1) || (iByte[0] != 0)) { - // not well formed, re-seek - seek(uPosNotPadded, Beginning); - } - else { - chunk.padding = 1; - } - } - d->chunks.push_back(chunk); - - } -} - -void RIFF::File::writeChunk(const ByteVector &name, const ByteVector &data, - ulong offset, ulong replace, uint leadingPadding) -{ - ByteVector combined; - if(leadingPadding) { - combined.append(ByteVector(leadingPadding, '\x00')); - } - combined.append(name); - combined.append(ByteVector::fromUInt(data.size(), d->endianness == BigEndian)); - combined.append(data); - if((data.size() & 0x01) != 0) { - combined.append('\x00'); - } - insert(combined, offset, replace); -} diff --git a/taglib/taglib/riff/rifffile.h b/taglib/taglib/riff/rifffile.h deleted file mode 100644 index 6b8fe19..0000000 --- a/taglib/taglib/riff/rifffile.h +++ /dev/null @@ -1,157 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_RIFFFILE_H -#define TAGLIB_RIFFFILE_H - -#include "taglib_export.h" -#include "tfile.h" - -namespace TagLib { - - //! An implementation of TagLib::File with RIFF specific methods - - namespace RIFF { - - //! An RIFF file class with some useful methods specific to RIFF - - /*! - * This implements the generic TagLib::File API and additionally provides - * access to properties that are distinct to RIFF files, notably access - * to the different ID3 tags. - */ - - class TAGLIB_EXPORT File : public TagLib::File - { - public: - /*! - * Destroys this instance of the File. - */ - virtual ~File(); - - protected: - - enum Endianness { BigEndian, LittleEndian }; - - File(FileName file, Endianness endianness); - File(IOStream *stream, Endianness endianness); - - /*! - * \return The size of the main RIFF chunk. - */ - uint riffSize() const; - - /*! - * \return The number of chunks in the file. - */ - uint chunkCount() const; - - /*! - * \return The offset within the file for the selected chunk number. - */ - uint chunkOffset(uint i) const; - - /*! - * \return The size of the chunk data. - */ - uint chunkDataSize(uint i) const; - - /*! - * \return The size of the padding after the chunk (can be either 0 or 1). - */ - uint chunkPadding(uint i) const; - - /*! - * \return The name of the specified chunk, for instance, "COMM" or "ID3 " - */ - ByteVector chunkName(uint i) const; - - /*! - * Reads the chunk data from the file and returns it. - * - * \note This \e will move the read pointer for the file. - */ - ByteVector chunkData(uint i); - - /*! - * Sets the data for the the specified chunk to \a data. - * - * \warning This will update the file immediately. - */ - void setChunkData(uint i, const ByteVector &data); - - /*! - * Sets the data for the chunk \a name to \a data. If a chunk with the - * given name already exists it will be overwritten, otherwise it will be - * created after the existing chunks. - * - * \warning This will update the file immediately. - */ - void setChunkData(const ByteVector &name, const ByteVector &data); - - /*! - * Sets the data for the chunk \a name to \a data. If a chunk with the - * given name already exists it will be overwritten, otherwise it will be - * created after the existing chunks. - * - * \note If \a alwaysCreate is true, a new chunk is created regardless of - * whether or not the chunk \a name exists. It should only be used for - * "LIST" chunks. - * - * \warning This will update the file immediately. - */ - void setChunkData(const ByteVector &name, const ByteVector &data, bool alwaysCreate); - - /*! - * Removes the specified chunk. - * - * \warning This will update the file immediately. - */ - void removeChunk(uint i); - - /*! - * Removes the chunk \a name. - * - * \warning This will update the file immediately. - * \warning This removes all the chunks with the given name. - */ - void removeChunk(const ByteVector &name); - - private: - File(const File &); - File &operator=(const File &); - - void read(); - void writeChunk(const ByteVector &name, const ByteVector &data, - ulong offset, ulong replace = 0, - uint leadingPadding = 0); - - class FilePrivate; - FilePrivate *d; - }; - } -} - -#endif diff --git a/taglib/taglib/riff/wav/infotag.cpp b/taglib/taglib/riff/wav/infotag.cpp deleted file mode 100644 index 09edfa5..0000000 --- a/taglib/taglib/riff/wav/infotag.cpp +++ /dev/null @@ -1,266 +0,0 @@ -/*************************************************************************** - copyright : (C) 2012 by Tsuda Kageyu - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <tdebug.h> -#include <tfile.h> - -#include "infotag.h" - -using namespace TagLib; -using namespace RIFF::Info; - -namespace { - static bool isValidChunkID(const ByteVector &name) - { - if(name.size() != 4) - return false; - - for(int i = 0; i < 4; i++) { - if(name[i] < 32 || name[i] > 127) - return false; - } - - return true; - } -} - -class RIFF::Info::Tag::TagPrivate -{ -public: - TagPrivate() - {} - - FieldListMap fieldListMap; - - static const StringHandler *stringHandler; -}; - -//////////////////////////////////////////////////////////////////////////////// -// StringHandler implementation -//////////////////////////////////////////////////////////////////////////////// - -StringHandler::StringHandler() -{ -} - -StringHandler::~StringHandler() -{ -} - -String RIFF::Info::StringHandler::parse(const ByteVector &data) const -{ - return String(data, String::UTF8); -} - -ByteVector RIFF::Info::StringHandler::render(const String &s) const -{ - return s.data(String::UTF8); -} - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -static const StringHandler defaultStringHandler; -const RIFF::Info::StringHandler *RIFF::Info::Tag::TagPrivate::stringHandler = &defaultStringHandler; - -RIFF::Info::Tag::Tag(const ByteVector &data) - : TagLib::Tag() - , d(new TagPrivate()) -{ - parse(data); -} - -RIFF::Info::Tag::Tag() - : TagLib::Tag() - , d(new TagPrivate()) -{ -} - -RIFF::Info::Tag::~Tag() -{ - delete d; -} - -String RIFF::Info::Tag::title() const -{ - return fieldText("INAM"); -} - -String RIFF::Info::Tag::artist() const -{ - return fieldText("IART"); -} - -String RIFF::Info::Tag::album() const -{ - return fieldText("IPRD"); -} - -String RIFF::Info::Tag::comment() const -{ - return fieldText("ICMT"); -} - -String RIFF::Info::Tag::genre() const -{ - return fieldText("IGNR"); -} - -TagLib::uint RIFF::Info::Tag::year() const -{ - return fieldText("ICRD").substr(0, 4).toInt(); -} - -TagLib::uint RIFF::Info::Tag::track() const -{ - return fieldText("IPRT").toInt(); -} - -void RIFF::Info::Tag::setTitle(const String &s) -{ - setFieldText("INAM", s); -} - -void RIFF::Info::Tag::setArtist(const String &s) -{ - setFieldText("IART", s); -} - -void RIFF::Info::Tag::setAlbum(const String &s) -{ - setFieldText("IPRD", s); -} - -void RIFF::Info::Tag::setComment(const String &s) -{ - setFieldText("ICMT", s); -} - -void RIFF::Info::Tag::setGenre(const String &s) -{ - setFieldText("IGNR", s); -} - -void RIFF::Info::Tag::setYear(uint i) -{ - if(i != 0) - setFieldText("ICRD", String::number(i)); - else - d->fieldListMap.erase("ICRD"); -} - -void RIFF::Info::Tag::setTrack(uint i) -{ - if(i != 0) - setFieldText("IPRT", String::number(i)); - else - d->fieldListMap.erase("IPRT"); -} - -bool RIFF::Info::Tag::isEmpty() const -{ - return d->fieldListMap.isEmpty(); -} - -FieldListMap RIFF::Info::Tag::fieldListMap() const -{ - return d->fieldListMap; -} - -String RIFF::Info::Tag::fieldText(const ByteVector &id) const -{ - if(d->fieldListMap.contains(id)) - return String(d->fieldListMap[id]); - else - return String(); -} - -void RIFF::Info::Tag::setFieldText(const ByteVector &id, const String &s) -{ - // id must be four-byte long pure ascii string. - if(!isValidChunkID(id)) - return; - - if(!s.isEmpty()) - d->fieldListMap[id] = s; - else - removeField(id); -} - -void RIFF::Info::Tag::removeField(const ByteVector &id) -{ - if(d->fieldListMap.contains(id)) - d->fieldListMap.erase(id); -} - -ByteVector RIFF::Info::Tag::render() const -{ - ByteVector data("INFO"); - - FieldListMap::ConstIterator it = d->fieldListMap.begin(); - for(; it != d->fieldListMap.end(); ++it) { - ByteVector text = TagPrivate::stringHandler->render(it->second); - if(text.isEmpty()) - continue; - - data.append(it->first); - data.append(ByteVector::fromUInt(text.size() + 1, false)); - data.append(text); - - do { - data.append('\0'); - } while(data.size() & 1); - } - - if(data.size() == 4) - return ByteVector(); - else - return data; -} - -void RIFF::Info::Tag::setStringHandler(const StringHandler *handler) -{ - if(handler) - TagPrivate::stringHandler = handler; - else - TagPrivate::stringHandler = &defaultStringHandler; -} - -//////////////////////////////////////////////////////////////////////////////// -// protected members -//////////////////////////////////////////////////////////////////////////////// - -void RIFF::Info::Tag::parse(const ByteVector &data) -{ - uint p = 4; - while(p < data.size()) { - const uint size = data.toUInt(p + 4, false); - d->fieldListMap[data.mid(p, 4)] = TagPrivate::stringHandler->parse(data.mid(p + 8, size)); - - p += ((size + 1) & ~1) + 8; - } -} - diff --git a/taglib/taglib/riff/wav/infotag.h b/taglib/taglib/riff/wav/infotag.h deleted file mode 100644 index 4007ae6..0000000 --- a/taglib/taglib/riff/wav/infotag.h +++ /dev/null @@ -1,192 +0,0 @@ -/*************************************************************************** - copyright : (C) 2012 by Tsuda Kageyu - email : tsuda.kageyu@gmail.com - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_INFOTAG_H -#define TAGLIB_INFOTAG_H - -#include "tag.h" -#include "tmap.h" -#include "tstring.h" -#include "tstringlist.h" -#include "tbytevector.h" -#include "taglib_export.h" - -namespace TagLib { - - class File; - - //! A RIFF Info tag implementation. - namespace RIFF { - namespace Info { - - typedef Map<ByteVector, String> FieldListMap; - - //! A abstraction for the string to data encoding in Info tags. - - /*! - * RIFF Info tag has no clear definitions about character encodings. - * In practice, local encoding of each system is largely used and UTF-8 is - * popular too. - * - * Here is an option to read and write tags in your preferrd encoding - * by subclassing this class, reimplementing parse() and render() and setting - * your reimplementation as the default with Info::Tag::setStringHandler(). - * - * \see ID3v1::Tag::setStringHandler() - */ - - class TAGLIB_EXPORT StringHandler - { - public: - StringHandler(); - ~StringHandler(); - - /*! - * Decode a string from \a data. The default implementation assumes that - * \a data is an UTF-8 character array. - */ - virtual String parse(const ByteVector &data) const; - - /*! - * Encode a ByteVector with the data from \a s. The default implementation - * assumes that \a s is an UTF-8 string. - */ - virtual ByteVector render(const String &s) const; - }; - - //! The main class in the ID3v2 implementation - - /*! - * This is the main class in the INFO tag implementation. RIFF INFO tag is a - * metadata format found in WAV audio and AVI video files. Though it is a part - * of Microsoft/IBM's RIFF specification, the author could not find the official - * documents about it. So, this implementation is referring to unofficial documents - * online and some applications' behaviors especially Windows Explorer. - */ - class TAGLIB_EXPORT Tag : public TagLib::Tag - { - public: - /*! - * Constructs an empty Info tag. - */ - Tag(); - - /*! - * Constructs an Info tag read from \a data which is contents of "LIST" chunk. - */ - Tag(const ByteVector &data); - - virtual ~Tag(); - - // Reimplementations - - virtual String title() const; - virtual String artist() const; - virtual String album() const; - virtual String comment() const; - virtual String genre() const; - virtual uint year() const; - virtual 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 bool isEmpty() const; - - /*! - * Returns a copy of the internal fields of the tag. The returned map directly - * reflects the contents of the "INFO" chunk. - * - * \note Modifying this map does not affect the tag's internal data. - * Use setFieldText() and removeField() instead. - * - * \see setFieldText() - * \see removeField() - */ - FieldListMap fieldListMap() const; - - /* - * Gets the value of the field with the ID \a id. - */ - String fieldText(const ByteVector &id) const; - - /* - * Sets the value of the field with the ID \a id to \a s. - * If the field does not exist, it is created. - * If \s is empty, the field is removed. - * - * \note fieldId must be four-byte long pure ASCII string. This function - * performs nothing if fieldId is invalid. - */ - void setFieldText(const ByteVector &id, const String &s); - - /* - * Removes the field with the ID \a id. - */ - void removeField(const ByteVector &id); - - /*! - * Render the tag back to binary data, suitable to be written to disk. - * - * \note Returns empty ByteVector is the tag contains no fields. - */ - ByteVector render() const; - - /*! - * Sets the string handler that decides how the text data will be - * converted to and from binary data. - * If the parameter \a handler is null, the previous handler is - * released and default UTF-8 handler is restored. - * - * \note The caller is responsible for deleting the previous handler - * as needed after it is released. - * - * \see StringHandler - */ - static void setStringHandler(const StringHandler *handler); - - protected: - /*! - * Pareses the body of the tag in \a data. - */ - void parse(const ByteVector &data); - - - private: - Tag(const Tag &); - Tag &operator=(const Tag &); - - class TagPrivate; - TagPrivate *d; - }; - }} -} - -#endif diff --git a/taglib/taglib/riff/wav/wavfile.cpp b/taglib/taglib/riff/wav/wavfile.cpp deleted file mode 100644 index abecea3..0000000 --- a/taglib/taglib/riff/wav/wavfile.cpp +++ /dev/null @@ -1,244 +0,0 @@ -/*************************************************************************** - copyright : (C) 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include "tbytevector.h" -#include "tdebug.h" -#include "tstringlist.h" -#include "tpropertymap.h" - -#include "wavfile.h" -#include "id3v2tag.h" -#include "infotag.h" -#include "tagunion.h" - -using namespace TagLib; - -namespace -{ - enum { ID3v2Index = 0, InfoIndex = 1 }; -} - -class RIFF::WAV::File::FilePrivate -{ -public: - FilePrivate() : - properties(0), - tagChunkID("ID3 "), - hasID3v2(false), - hasInfo(false) - { - } - - ~FilePrivate() - { - delete properties; - } - - Properties *properties; - - ByteVector tagChunkID; - - TagUnion tag; - - bool hasID3v2; - bool hasInfo; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -RIFF::WAV::File::File(FileName file, bool readProperties, - Properties::ReadStyle propertiesStyle) : RIFF::File(file, LittleEndian) -{ - d = new FilePrivate; - if(isOpen()) - read(readProperties, propertiesStyle); -} - -RIFF::WAV::File::File(IOStream *stream, bool readProperties, - Properties::ReadStyle propertiesStyle) : RIFF::File(stream, LittleEndian) -{ - d = new FilePrivate; - if(isOpen()) - read(readProperties, propertiesStyle); -} - -RIFF::WAV::File::~File() -{ - delete d; -} - -ID3v2::Tag *RIFF::WAV::File::tag() const -{ - return ID3v2Tag(); -} - -ID3v2::Tag *RIFF::WAV::File::ID3v2Tag() const -{ - return d->tag.access<ID3v2::Tag>(ID3v2Index, false); -} - -RIFF::Info::Tag *RIFF::WAV::File::InfoTag() const -{ - return d->tag.access<RIFF::Info::Tag>(InfoIndex, false); -} - -PropertyMap RIFF::WAV::File::properties() const -{ - return tag()->properties(); -} - -void RIFF::WAV::File::removeUnsupportedProperties(const StringList &unsupported) -{ - tag()->removeUnsupportedProperties(unsupported); -} - -PropertyMap RIFF::WAV::File::setProperties(const PropertyMap &properties) -{ - return tag()->setProperties(properties); -} - -RIFF::WAV::Properties *RIFF::WAV::File::audioProperties() const -{ - return d->properties; -} - -bool RIFF::WAV::File::save() -{ - return RIFF::WAV::File::save(AllTags); -} - -bool RIFF::WAV::File::save(TagTypes tags, bool stripOthers, int id3v2Version) -{ - if(readOnly()) { - debug("RIFF::WAV::File::save() -- File is read only."); - return false; - } - - if(!isValid()) { - debug("RIFF::WAV::File::save() -- Trying to save invalid file."); - return false; - } - - if(stripOthers) - strip(static_cast<TagTypes>(AllTags & ~tags)); - - ID3v2::Tag *id3v2tag = d->tag.access<ID3v2::Tag>(ID3v2Index, false); - if(!id3v2tag->isEmpty()) { - if(tags & ID3v2) { - setChunkData(d->tagChunkID, id3v2tag->render(id3v2Version)); - d->hasID3v2 = true; - } - } - - Info::Tag *infotag = d->tag.access<Info::Tag>(InfoIndex, false); - if(!infotag->isEmpty()) { - if(tags & Info) { - int chunkId = findInfoTagChunk(); - if(chunkId != -1) - setChunkData(chunkId, infotag->render()); - else - setChunkData("LIST", infotag->render(), true); - - d->hasInfo = true; - } - } - - return true; -} - -bool RIFF::WAV::File::hasID3v2Tag() const -{ - return d->hasID3v2; -} - -bool RIFF::WAV::File::hasInfoTag() const -{ - return d->hasInfo; -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -void RIFF::WAV::File::read(bool readProperties, Properties::ReadStyle propertiesStyle) -{ - ByteVector formatData; - uint streamLength = 0; - for(uint i = 0; i < chunkCount(); i++) { - String name = chunkName(i); - if(name == "ID3 " || name == "id3 ") { - d->tagChunkID = chunkName(i); - d->tag.set(ID3v2Index, new ID3v2::Tag(this, chunkOffset(i))); - d->hasID3v2 = true; - } - else if(name == "fmt " && readProperties) - formatData = chunkData(i); - else if(name == "data" && readProperties) - streamLength = chunkDataSize(i); - else if(name == "LIST") { - ByteVector data = chunkData(i); - ByteVector type = data.mid(0, 4); - - if(type == "INFO") { - d->tag.set(InfoIndex, new RIFF::Info::Tag(data)); - d->hasInfo = true; - } - } - } - - if (!d->tag[ID3v2Index]) - d->tag.set(ID3v2Index, new ID3v2::Tag); - - if (!d->tag[InfoIndex]) - d->tag.set(InfoIndex, new RIFF::Info::Tag); - - if(!formatData.isEmpty()) - d->properties = new Properties(formatData, streamLength, propertiesStyle); -} - -void RIFF::WAV::File::strip(TagTypes tags) -{ - if(tags & ID3v2) - removeChunk(d->tagChunkID); - - if(tags & Info){ - TagLib::uint chunkId = findInfoTagChunk(); - if(chunkId != TagLib::uint(-1)) - removeChunk(chunkId); - } -} - -TagLib::uint RIFF::WAV::File::findInfoTagChunk() -{ - for(uint i = 0; i < chunkCount(); ++i) { - if(chunkName(i) == "LIST" && chunkData(i).mid(0, 4) == "INFO") { - return i; - } - } - - return TagLib::uint(-1); -} diff --git a/taglib/taglib/riff/wav/wavfile.h b/taglib/taglib/riff/wav/wavfile.h deleted file mode 100644 index 2f83332..0000000 --- a/taglib/taglib/riff/wav/wavfile.h +++ /dev/null @@ -1,189 +0,0 @@ -/*************************************************************************** - copyright : (C) 2008 by Scott Wheeler - email : wheeler@kde.org -***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_WAVFILE_H -#define TAGLIB_WAVFILE_H - -#include "rifffile.h" -#include "id3v2tag.h" -#include "infotag.h" -#include "wavproperties.h" - -namespace TagLib { - - namespace RIFF { - - //! An implementation of WAV metadata - - /*! - * This is implementation of WAV metadata. - * - * This supports an ID3v2 tag as well as reading stream from the ID3 RIFF - * chunk as well as properties from the file. - */ - - namespace WAV { - - //! An implementation of TagLib::File with WAV specific methods - - /*! - * This implements and provides an interface for WAV 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 WAV files. - */ - - class TAGLIB_EXPORT File : public TagLib::RIFF::File - { - public: - enum TagTypes { - //! Empty set. Matches no tag types. - NoTags = 0x0000, - //! Matches ID3v2 tags. - ID3v2 = 0x0001, - //! Matches Info tags. - Info = 0x0002, - //! Matches all tag types. - AllTags = 0xffff - }; - - /*! - * Constructs a WAV 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 a WAV 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 ID3v2 Tag for this file. - * - * \note This method does not return all the tags for this file for - * backward compatibility. Will be fixed in TagLib 2.0. - */ - ID3v2::Tag *tag() const; - - /*! - * Returns the ID3v2 Tag for this file. - * - * \note This always returns a valid pointer regardless of whether or not - * the file on disk has an ID3v2 tag. Use hasID3v2Tag() to check if the - * file on disk actually has an ID3v2 tag. - * - * \see hasID3v2Tag() - */ - ID3v2::Tag *ID3v2Tag() const; - - /*! - * Returns the RIFF INFO Tag for this file. - * - * \note This always returns a valid pointer regardless of whether or not - * the file on disk has a RIFF INFO tag. Use hasInfoTag() to check if the - * file on disk actually has a RIFF INFO tag. - * - * \see hasInfoTag() - */ - Info::Tag *InfoTag() const; - - /*! - * Implements the unified property interface -- export function. - * This method forwards to ID3v2::Tag::properties(). - */ - PropertyMap properties() const; - - void removeUnsupportedProperties(const StringList &properties); - - /*! - * Implements the unified property interface -- import function. - * This method forwards to ID3v2::Tag::setProperties(). - */ - PropertyMap setProperties(const PropertyMap &); - - /*! - * Returns the WAV::Properties for this file. If no audio properties - * were read then this will return a null pointer. - */ - virtual Properties *audioProperties() const; - - /*! - * Saves the file. - */ - virtual bool save(); - - bool save(TagTypes tags, bool stripOthers = true, int id3v2Version = 4); - - /*! - * 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 a RIFF INFO tag. - * - * \see InfoTag() - */ - bool hasInfoTag() const; - - private: - File(const File &); - File &operator=(const File &); - - void read(bool readProperties, Properties::ReadStyle propertiesStyle); - - void strip(TagTypes tags); - - /*! - * Returns the index of the chunk that its name is "LIST" and list type is "INFO". - */ - uint findInfoTagChunk(); - - class FilePrivate; - FilePrivate *d; - }; - } - } -} - -#endif diff --git a/taglib/taglib/riff/wav/wavproperties.cpp b/taglib/taglib/riff/wav/wavproperties.cpp deleted file mode 100644 index 8062df5..0000000 --- a/taglib/taglib/riff/wav/wavproperties.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/*************************************************************************** - copyright : (C) 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include "wavproperties.h" - -#include <tstring.h> -#include <tdebug.h> -#include <cmath> -#include <math.h> - -using namespace TagLib; - -class RIFF::WAV::Properties::PropertiesPrivate -{ -public: - PropertiesPrivate(uint streamLength = 0) : - format(0), - length(0), - bitrate(0), - sampleRate(0), - channels(0), - sampleWidth(0), - sampleFrames(0), - streamLength(streamLength) - { - - } - - short format; - int length; - int bitrate; - int sampleRate; - int channels; - int sampleWidth; - uint sampleFrames; - uint streamLength; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -RIFF::WAV::Properties::Properties(const ByteVector &data, ReadStyle style) : AudioProperties(style) -{ - d = new PropertiesPrivate(); - read(data); -} - -RIFF::WAV::Properties::Properties(const ByteVector &data, uint streamLength, ReadStyle style) : AudioProperties(style) -{ - d = new PropertiesPrivate(streamLength); - read(data); -} - -RIFF::WAV::Properties::~Properties() -{ - delete d; -} - -int RIFF::WAV::Properties::length() const -{ - return d->length; -} - -int RIFF::WAV::Properties::bitrate() const -{ - return d->bitrate; -} - -int RIFF::WAV::Properties::sampleRate() const -{ - return d->sampleRate; -} - -int RIFF::WAV::Properties::channels() const -{ - return d->channels; -} - -int RIFF::WAV::Properties::sampleWidth() const -{ - return d->sampleWidth; -} - -TagLib::uint RIFF::WAV::Properties::sampleFrames() const -{ - return d->sampleFrames; -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -void RIFF::WAV::Properties::read(const ByteVector &data) -{ - d->format = data.toShort(0, false); - d->channels = data.toShort(2, false); - d->sampleRate = data.toUInt(4, false); - d->sampleWidth = data.toShort(14, false); - - const uint byteRate = data.toUInt(8, false); - d->bitrate = byteRate * 8 / 1000; - - d->length = byteRate > 0 ? d->streamLength / byteRate : 0; - if(d->channels > 0 && d->sampleWidth > 0) - d->sampleFrames = d->streamLength / (d->channels * ((d->sampleWidth + 7) / 8)); -} diff --git a/taglib/taglib/riff/wav/wavproperties.h b/taglib/taglib/riff/wav/wavproperties.h deleted file mode 100644 index 2023f53..0000000 --- a/taglib/taglib/riff/wav/wavproperties.h +++ /dev/null @@ -1,92 +0,0 @@ -/*************************************************************************** - copyright : (C) 2008 by Scott Wheeler - email : wheeler@kde.org -***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_WAVPROPERTIES_H -#define TAGLIB_WAVPROPERTIES_H - -#include "taglib.h" -#include "audioproperties.h" - -namespace TagLib { - - class ByteVector; - - namespace RIFF { - - namespace WAV { - - class File; - - //! An implementation of audio property reading for WAV - - /*! - * This reads the data from an WAV stream found in the AudioProperties - * API. - */ - - class TAGLIB_EXPORT Properties : public AudioProperties - { - public: - /*! - * Create an instance of WAV::Properties with the data read from the - * ByteVector \a data. - */ - Properties(const ByteVector &data, ReadStyle style); - - /*! - * Create an instance of WAV::Properties with the data read from the - * ByteVector \a data and the length calculated using \a streamLength. - */ - Properties(const ByteVector &data, uint streamLength, ReadStyle style); - - /*! - * Destroys this WAV::Properties instance. - */ - virtual ~Properties(); - - // Reimplementations. - - virtual int length() const; - virtual int bitrate() const; - virtual int sampleRate() const; - virtual int channels() const; - - int sampleWidth() const; - uint sampleFrames() const; - - private: - Properties(const Properties &); - Properties &operator=(const Properties &); - - void read(const ByteVector &data); - - class PropertiesPrivate; - PropertiesPrivate *d; - }; - } - } -} - -#endif diff --git a/taglib/taglib/s3m/s3mfile.cpp b/taglib/taglib/s3m/s3mfile.cpp deleted file mode 100644 index 371340a..0000000 --- a/taglib/taglib/s3m/s3mfile.cpp +++ /dev/null @@ -1,243 +0,0 @@ -/*************************************************************************** - copyright : (C) 2011 by Mathias Panzenböck - email : grosser.meister.morti@gmx.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * - ***************************************************************************/ - -#include "s3mfile.h" -#include "tstringlist.h" -#include "tdebug.h" -#include "modfileprivate.h" -#include "tpropertymap.h" - -#include <iostream> - -using namespace TagLib; -using namespace S3M; - -class S3M::File::FilePrivate -{ -public: - FilePrivate(AudioProperties::ReadStyle propertiesStyle) - : properties(propertiesStyle) - { - } - - Mod::Tag tag; - S3M::Properties properties; -}; - -S3M::File::File(FileName file, bool readProperties, - AudioProperties::ReadStyle propertiesStyle) : - Mod::FileBase(file), - d(new FilePrivate(propertiesStyle)) -{ - if(isOpen()) - read(readProperties); -} - -S3M::File::File(IOStream *stream, bool readProperties, - AudioProperties::ReadStyle propertiesStyle) : - Mod::FileBase(stream), - d(new FilePrivate(propertiesStyle)) -{ - if(isOpen()) - read(readProperties); -} - -S3M::File::~File() -{ - delete d; -} - -Mod::Tag *S3M::File::tag() const -{ - return &d->tag; -} - -PropertyMap S3M::File::properties() const -{ - return d->tag.properties(); -} - -PropertyMap S3M::File::setProperties(const PropertyMap &properties) -{ - return d->tag.setProperties(properties); -} - -S3M::Properties *S3M::File::audioProperties() const -{ - return &d->properties; -} - -bool S3M::File::save() -{ - if(readOnly()) { - debug("S3M::File::save() - Cannot save to a read only file."); - return false; - } - // note: if title starts with "Extended Module: " - // the file would look like an .xm file - seek(0); - writeString(d->tag.title(), 27); - // string terminating NUL is not optional: - writeByte(0); - - seek(32); - - ushort length = 0; - ushort sampleCount = 0; - - if(!readU16L(length) || !readU16L(sampleCount)) - return false; - - seek(28, Current); - - int channels = 0; - for(int i = 0; i < 32; ++ i) { - uchar setting = 0; - if(!readByte(setting)) - return false; - // or if(setting >= 128)? - // or channels = i + 1;? - // need a better spec! - if(setting != 0xff) ++ channels; - } - - seek(channels, Current); - - StringList lines = d->tag.comment().split("\n"); - // write comment as sample names: - for(ushort i = 0; i < sampleCount; ++ i) { - seek(96L + length + ((long)i << 1)); - - ushort instrumentOffset = 0; - if(!readU16L(instrumentOffset)) - return false; - seek(((long)instrumentOffset << 4) + 48); - - if(i < lines.size()) - writeString(lines[i], 27); - else - writeString(String::null, 27); - // string terminating NUL is not optional: - writeByte(0); - } - return true; -} - -void S3M::File::read(bool) -{ - if(!isOpen()) - return; - - READ_STRING(d->tag.setTitle, 28); - READ_BYTE_AS(mark); - READ_BYTE_AS(type); - - READ_ASSERT(mark == 0x1A && type == 0x10); - - seek(32); - - READ_U16L_AS(length); - READ_U16L_AS(sampleCount); - - d->properties.setSampleCount(sampleCount); - - READ_U16L(d->properties.setPatternCount); - READ_U16L(d->properties.setFlags); - READ_U16L(d->properties.setTrackerVersion); - READ_U16L(d->properties.setFileFormatVersion); - - READ_ASSERT(readBlock(4) == "SCRM"); - - READ_BYTE(d->properties.setGlobalVolume); - READ_BYTE(d->properties.setBpmSpeed); - READ_BYTE(d->properties.setTempo); - - READ_BYTE_AS(masterVolume); - d->properties.setMasterVolume(masterVolume & 0x7f); - d->properties.setStereo((masterVolume & 0x80) != 0); - - // I've seen players who call the next two bytes - // "ultra click" and "use panning values" (if == 0xFC). - // I don't see them in any spec, though. - // Hm, but there is "UltraClick-removal" and some other - // variables in ScreamTracker IIIs GUI. - - seek(12, Current); - - int channels = 0; - for(int i = 0; i < 32; ++ i) { - READ_BYTE_AS(setting); - // or if(setting >= 128)? - // or channels = i + 1;? - // need a better spec! - if(setting != 0xff) ++ channels; - } - d->properties.setChannels(channels); - - seek(96); - ushort realLength = 0; - for(ushort i = 0; i < length; ++ i) { - READ_BYTE_AS(order); - if(order == 255) break; - if(order != 254) ++ realLength; - } - d->properties.setLengthInPatterns(realLength); - - seek(channels, Current); - - // Note: The S3M spec mentions samples and instruments, but in - // the header there are only pointers to instruments. - // However, there I never found instruments (SCRI) but - // instead samples (SCRS). - StringList comment; - for(ushort i = 0; i < sampleCount; ++ i) { - seek(96L + length + ((long)i << 1)); - - READ_U16L_AS(sampleHeaderOffset); - seek((long)sampleHeaderOffset << 4); - - READ_BYTE_AS(sampleType); - READ_STRING_AS(dosFileName, 13); - READ_U16L_AS(sampleDataOffset); - READ_U32L_AS(sampleLength); - READ_U32L_AS(repeatStart); - READ_U32L_AS(repeatStop); - READ_BYTE_AS(sampleVolume); - - seek(1, Current); - - READ_BYTE_AS(packing); - READ_BYTE_AS(sampleFlags); - READ_U32L_AS(baseFrequency); - - seek(12, Current); - - READ_STRING_AS(sampleName, 28); - // The next 4 bytes should be "SCRS", but I've found - // files that are otherwise ok with 4 nils instead. - // READ_ASSERT(readBlock(4) == "SCRS"); - - comment.append(sampleName); - } - - d->tag.setComment(comment.toString("\n")); - d->tag.setTrackerName("ScreamTracker III"); -} diff --git a/taglib/taglib/s3m/s3mfile.h b/taglib/taglib/s3m/s3mfile.h deleted file mode 100644 index 5f45297..0000000 --- a/taglib/taglib/s3m/s3mfile.h +++ /dev/null @@ -1,108 +0,0 @@ -/*************************************************************************** - copyright : (C) 2011 by Mathias Panzenböck - email : grosser.meister.morti@gmx.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef TAGLIB_S3MFILE_H -#define TAGLIB_S3MFILE_H - -#include "tfile.h" -#include "audioproperties.h" -#include "taglib_export.h" -#include "modfilebase.h" -#include "modtag.h" -#include "s3mproperties.h" - -namespace TagLib { - - namespace S3M { - - class TAGLIB_EXPORT File : public Mod::FileBase { - public: - /*! - * Constructs a ScreamTracker III 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); - - /*! - * Constructs a ScreamTracker III file from \a stream. - * - * \note In the current implementation, both \a readProperties and - * \a propertiesStyle are ignored. The audio properties are always - * read. - * - * \note TagLib will *not* take ownership of the stream, the caller is - * responsible for deleting it after the File object. - */ - File(IOStream *stream, bool readProperties = true, - AudioProperties::ReadStyle propertiesStyle = - AudioProperties::Average); - - /*! - * Destroys this instance of the File. - */ - virtual ~File(); - - Mod::Tag *tag() const; - - /*! - * Implements the unified property interface -- export function. - * Forwards to Mod::Tag::properties(). - */ - PropertyMap properties() const; - - /*! - * Implements the unified property interface -- import function. - * Forwards to Mod::Tag::setProperties(). - */ - PropertyMap setProperties(const PropertyMap &); - - /*! - * Returns the S3M::Properties for this file. If no audio properties - * were read then this will return a null pointer. - */ - S3M::Properties *audioProperties() const; - - /*! - * Save the file. - * This is the same as calling save(AllTags); - * - * \note Saving ScreamTracker III tags is not supported. - */ - bool save(); - - private: - File(const File &); - File &operator=(const File &); - - void read(bool readProperties); - - class FilePrivate; - FilePrivate *d; - }; - } -} - -#endif diff --git a/taglib/taglib/s3m/s3mproperties.cpp b/taglib/taglib/s3m/s3mproperties.cpp deleted file mode 100644 index a1a010a..0000000 --- a/taglib/taglib/s3m/s3mproperties.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/*************************************************************************** - copyright : (C) 2011 by Mathias Panzenböck - email : grosser.meister.morti@gmx.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * - ***************************************************************************/ - -#include "s3mproperties.h" - -using namespace TagLib; -using namespace S3M; - -class S3M::Properties::PropertiesPrivate -{ -public: - PropertiesPrivate() : - lengthInPatterns(0), - channels(0), - stereo(false), - sampleCount(0), - patternCount(0), - flags(0), - trackerVersion(0), - fileFormatVersion(0), - globalVolume(0), - masterVolume(0), - tempo(0), - bpmSpeed(0) - { - } - - ushort lengthInPatterns; - int channels; - bool stereo; - ushort sampleCount; - ushort patternCount; - ushort flags; - ushort trackerVersion; - ushort fileFormatVersion; - uchar globalVolume; - uchar masterVolume; - uchar tempo; - uchar bpmSpeed; -}; - -S3M::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) : - AudioProperties(propertiesStyle), - d(new PropertiesPrivate) -{ -} - -S3M::Properties::~Properties() -{ - delete d; -} - -int S3M::Properties::length() const -{ - return 0; -} - -int S3M::Properties::bitrate() const -{ - return 0; -} - -int S3M::Properties::sampleRate() const -{ - return 0; -} - -int S3M::Properties::channels() const -{ - return d->channels; -} - -TagLib::ushort S3M::Properties::lengthInPatterns() const -{ - return d->lengthInPatterns; -} - -bool S3M::Properties::stereo() const -{ - return d->stereo; -} - -TagLib::ushort S3M::Properties::sampleCount() const -{ - return d->sampleCount; -} - -TagLib::ushort S3M::Properties::patternCount() const -{ - return d->patternCount; -} - -TagLib::ushort S3M::Properties::flags() const -{ - return d->flags; -} - -TagLib::ushort S3M::Properties::trackerVersion() const -{ - return d->trackerVersion; -} - -TagLib::ushort S3M::Properties::fileFormatVersion() const -{ - return d->fileFormatVersion; -} - -uchar S3M::Properties::globalVolume() const -{ - return d->globalVolume; -} - -uchar S3M::Properties::masterVolume() const -{ - return d->masterVolume; -} - -uchar S3M::Properties::tempo() const -{ - return d->tempo; -} - -uchar S3M::Properties::bpmSpeed() const -{ - return d->bpmSpeed; -} - -void S3M::Properties::setLengthInPatterns(ushort lengthInPatterns) -{ - d->lengthInPatterns = lengthInPatterns; -} - -void S3M::Properties::setChannels(int channels) -{ - d->channels = channels; -} - -void S3M::Properties::setStereo(bool stereo) -{ - d->stereo = stereo; -} - -void S3M::Properties::setSampleCount(ushort sampleCount) -{ - d->sampleCount = sampleCount; -} - -void S3M::Properties::setPatternCount(ushort patternCount) -{ - d->patternCount = patternCount; -} - -void S3M::Properties::setFlags(ushort flags) -{ - d->flags = flags; -} - -void S3M::Properties::setTrackerVersion(ushort trackerVersion) -{ - d->trackerVersion = trackerVersion; -} - -void S3M::Properties::setFileFormatVersion(ushort fileFormatVersion) -{ - d->fileFormatVersion = fileFormatVersion; -} - -void S3M::Properties::setGlobalVolume(uchar globalVolume) -{ - d->globalVolume = globalVolume; -} - -void S3M::Properties::setMasterVolume(uchar masterVolume) -{ - d->masterVolume = masterVolume; -} - -void S3M::Properties::setTempo(uchar tempo) -{ - d->tempo = tempo; -} - -void S3M::Properties::setBpmSpeed(uchar bpmSpeed) -{ - d->bpmSpeed = bpmSpeed; -} diff --git a/taglib/taglib/s3m/s3mproperties.h b/taglib/taglib/s3m/s3mproperties.h deleted file mode 100644 index 6e9f1d2..0000000 --- a/taglib/taglib/s3m/s3mproperties.h +++ /dev/null @@ -1,88 +0,0 @@ -/*************************************************************************** - copyright : (C) 2011 by Mathias Panzenböck - email : grosser.meister.morti@gmx.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef TAGLIB_S3MPROPERTIES_H -#define TAGLIB_S3MPROPERTIES_H - -#include "taglib.h" -#include "audioproperties.h" - -namespace TagLib { - namespace S3M { - class TAGLIB_EXPORT Properties : public AudioProperties { - friend class File; - public: - /*! Flag bits. */ - enum { - ST2Vibrato = 1, - ST2Tempo = 2, - AmigaSlides = 4, - Vol0MixOptimizations = 8, - AmigaLimits = 16, - EnableFilter = 32, - CustomData = 128 - }; - - Properties(AudioProperties::ReadStyle propertiesStyle); - virtual ~Properties(); - - int length() const; - int bitrate() const; - int sampleRate() const; - int channels() const; - - ushort lengthInPatterns() const; - bool stereo() const; - ushort sampleCount() const; - ushort patternCount() const; - ushort flags() const; - ushort trackerVersion() const; - ushort fileFormatVersion() const; - uchar globalVolume() const; - uchar masterVolume() const; - uchar tempo() const; - uchar bpmSpeed() const; - - void setChannels(int channels); - - void setLengthInPatterns (ushort lengthInPatterns); - void setStereo (bool stereo); - void setSampleCount (ushort sampleCount); - void setPatternCount (ushort patternCount); - void setFlags (ushort flags); - void setTrackerVersion (ushort trackerVersion); - void setFileFormatVersion(ushort fileFormatVersion); - void setGlobalVolume (uchar globalVolume); - void setMasterVolume (uchar masterVolume); - void setTempo (uchar tempo); - void setBpmSpeed (uchar bpmSpeed); - - private: - Properties(const Properties&); - Properties &operator=(const Properties&); - - class PropertiesPrivate; - PropertiesPrivate *d; - }; - } -} - -#endif diff --git a/taglib/taglib/tag.cpp b/taglib/taglib/tag.cpp deleted file mode 100644 index 6763408..0000000 --- a/taglib/taglib/tag.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include "tag.h" -#include "tstringlist.h" -#include "tpropertymap.h" - -using namespace TagLib; - -class Tag::TagPrivate -{ - -}; - -Tag::Tag() -{ - -} - -Tag::~Tag() -{ - -} - -bool Tag::isEmpty() const -{ - return (title().isEmpty() && - artist().isEmpty() && - album().isEmpty() && - comment().isEmpty() && - genre().isEmpty() && - year() == 0 && - track() == 0); -} - -PropertyMap Tag::properties() const -{ - PropertyMap map; - if(!(title().isNull())) - map["TITLE"].append(title()); - if(!(artist().isNull())) - map["ARTIST"].append(artist()); - if(!(album().isNull())) - map["ALBUM"].append(album()); - if(!(comment().isNull())) - map["COMMENT"].append(comment()); - if(!(genre().isNull())) - map["GENRE"].append(genre()); - if(!(year() == 0)) - map["DATE"].append(String::number(year())); - if(!(track() == 0)) - map["TRACKNUMBER"].append(String::number(track())); - return map; -} - -void Tag::removeUnsupportedProperties(const StringList&) -{ -} - -PropertyMap Tag::setProperties(const PropertyMap &origProps) -{ - PropertyMap properties(origProps); - properties.removeEmpty(); - StringList oneValueSet; - // can this be simplified by using some preprocessor defines / function pointers? - if(properties.contains("TITLE")) { - setTitle(properties["TITLE"].front()); - oneValueSet.append("TITLE"); - } else - setTitle(String::null); - - if(properties.contains("ARTIST")) { - setArtist(properties["ARTIST"].front()); - oneValueSet.append("ARTIST"); - } else - setArtist(String::null); - - if(properties.contains("ALBUM")) { - setAlbum(properties["ALBUM"].front()); - oneValueSet.append("ALBUM"); - } else - setAlbum(String::null); - - if(properties.contains("COMMENT")) { - setComment(properties["COMMENT"].front()); - oneValueSet.append("COMMENT"); - } else - setComment(String::null); - - if(properties.contains("GENRE")) { - setGenre(properties["GENRE"].front()); - oneValueSet.append("GENRE"); - } else - setGenre(String::null); - - if(properties.contains("DATE")) { - bool ok; - int date = properties["DATE"].front().toInt(&ok); - if(ok) { - setYear(date); - oneValueSet.append("DATE"); - } else - setYear(0); - } - else - setYear(0); - - if(properties.contains("TRACKNUMBER")) { - bool ok; - int track = properties["TRACKNUMBER"].front().toInt(&ok); - if(ok) { - setTrack(track); - oneValueSet.append("TRACKNUMBER"); - } else - setTrack(0); - } - else - setYear(0); - - // for each tag that has been set above, remove the first entry in the corresponding - // value list. The others will be returned as unsupported by this format. - for(StringList::Iterator it = oneValueSet.begin(); it != oneValueSet.end(); ++it) { - if(properties[*it].size() == 1) - properties.erase(*it); - else - properties[*it].erase( properties[*it].begin() ); - } - return properties; -} - -void Tag::duplicate(const Tag *source, Tag *target, bool overwrite) // static -{ - if(overwrite) { - target->setTitle(source->title()); - target->setArtist(source->artist()); - target->setAlbum(source->album()); - target->setComment(source->comment()); - target->setGenre(source->genre()); - target->setYear(source->year()); - target->setTrack(source->track()); - } - else { - if(target->title().isEmpty()) - target->setTitle(source->title()); - if(target->artist().isEmpty()) - target->setArtist(source->artist()); - if(target->album().isEmpty()) - target->setAlbum(source->album()); - if(target->comment().isEmpty()) - target->setComment(source->comment()); - if(target->genre().isEmpty()) - target->setGenre(source->genre()); - if(target->year() <= 0) - target->setYear(source->year()); - if(target->track() <= 0) - target->setTrack(source->track()); - } -} diff --git a/taglib/taglib/tag.h b/taglib/taglib/tag.h deleted file mode 100644 index 76c9a82..0000000 --- a/taglib/taglib/tag.h +++ /dev/null @@ -1,201 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_TAG_H -#define TAGLIB_TAG_H - -#include "taglib_export.h" -#include "tstring.h" - -namespace TagLib { - - //! A simple, generic interface to common audio meta data fields - - /*! - * This is an attempt to abstract away the difference in the meta data formats - * of various audio codecs and tagging schemes. As such it is generally a - * subset of what is available in the specific formats but should be suitable - * for most applications. This is meant to compliment the generic APIs found - * in TagLib::AudioProperties, TagLib::File and TagLib::FileRef. - */ - - class PropertyMap; - - class TAGLIB_EXPORT Tag - { - public: - - /*! - * Detroys this Tag instance. - */ - virtual ~Tag(); - - /*! - * Exports the tags of the file as dictionary mapping (human readable) tag - * names (Strings) to StringLists of tag values. - * The default implementation in this class considers only the usual built-in - * tags (artist, album, ...) and only one value per key. - */ - PropertyMap properties() const; - - /*! - * Removes unsupported properties, or a subset of them, from the tag. - * The parameter \a properties must contain only entries from - * properties().unsupportedData(). - * BIC: Will become virtual in future releases. Currently the non-virtual - * standard implementation of TagLib::Tag does nothing, since there are - * no unsupported elements. - */ - void removeUnsupportedProperties(const StringList& properties); - - /*! - * Sets the tags of this File to those specified in \a properties. This default - * implementation sets only the tags for which setter methods exist in this class - * (artist, album, ...), and only one value per key; the rest will be contained - * in the returned PropertyMap. - */ - PropertyMap setProperties(const PropertyMap &properties); - - /*! - * Returns the track name; if no track name is present in the tag - * String::null will be returned. - */ - virtual String title() const = 0; - - /*! - * Returns the artist name; if no artist name is present in the tag - * String::null will be returned. - */ - virtual String artist() const = 0; - - /*! - * Returns the album name; if no album name is present in the tag - * String::null will be returned. - */ - virtual String album() const = 0; - - /*! - * Returns the track comment; if no comment is present in the tag - * String::null will be returned. - */ - virtual String comment() const = 0; - - /*! - * Returns the genre name; if no genre is present in the tag String::null - * will be returned. - */ - virtual String genre() const = 0; - - /*! - * Returns the year; if there is no year set, this will return 0. - */ - virtual uint year() const = 0; - - /*! - * Returns the track number; if there is no track number set, this will - * return 0. - */ - virtual uint track() const = 0; - - /*! - * Sets the title to \a s. If \a s is String::null then this value will be - * cleared. - */ - virtual void setTitle(const String &s) = 0; - - /*! - * Sets the artist to \a s. If \a s is String::null then this value will be - * cleared. - */ - virtual void setArtist(const String &s) = 0; - - /*! - * Sets the album to \a s. If \a s is String::null then this value will be - * cleared. - */ - virtual void setAlbum(const String &s) = 0; - - /*! - * Sets the comment to \a s. If \a s is String::null then this value will be - * cleared. - */ - virtual void setComment(const String &s) = 0; - - /*! - * Sets the genre to \a s. If \a s is String::null then this value will be - * cleared. For tag formats that use a fixed set of genres, the appropriate - * value will be selected based on a string comparison. A list of available - * genres for those formats should be available in that type's - * implementation. - */ - virtual void setGenre(const String &s) = 0; - - /*! - * Sets the year to \a i. If \a s is 0 then this value will be cleared. - */ - virtual void setYear(uint i) = 0; - - /*! - * Sets the track to \a i. If \a s is 0 then this value will be cleared. - */ - virtual void setTrack(uint i) = 0; - - /*! - * Returns true if the tag does not contain any data. This should be - * reimplemented in subclasses that provide more than the basic tagging - * abilities in this class. - */ - virtual bool isEmpty() const; - - /*! - * Copies the generic data from one tag to another. - * - * \note This will no affect any of the lower level details of the tag. For - * instance if any of the tag type specific data (maybe a URL for a band) is - * set, this will not modify or copy that. This just copies using the API - * in this class. - * - * If \a overwrite is true then the values will be unconditionally copied. - * If false only empty values will be overwritten. - */ - static void duplicate(const Tag *source, Tag *target, bool overwrite = true); - - protected: - /*! - * Construct a Tag. This is protected since tags should only be instantiated - * through subclasses. - */ - Tag(); - - private: - Tag(const Tag &); - Tag &operator=(const Tag &); - - class TagPrivate; - TagPrivate *d; - }; -} - -#endif diff --git a/taglib/taglib/taglib_config.h.cmake b/taglib/taglib/taglib_config.h.cmake deleted file mode 100644 index 0f499e2..0000000 --- a/taglib/taglib/taglib_config.h.cmake +++ /dev/null @@ -1,4 +0,0 @@ -/* taglib_config.h. Generated by cmake from taglib_config.h.cmake */ - -#define TAGLIB_WITH_ASF 1 -#define TAGLIB_WITH_MP4 1 diff --git a/taglib/taglib/taglib_export.h b/taglib/taglib/taglib_export.h deleted file mode 100644 index 737ae64..0000000 --- a/taglib/taglib/taglib_export.h +++ /dev/null @@ -1,43 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_EXPORT_H -#define TAGLIB_EXPORT_H - -#if defined(TAGLIB_STATIC) -#define TAGLIB_EXPORT -#elif (defined(_WIN32) || defined(_WIN64)) -#ifdef MAKE_TAGLIB_LIB -#define TAGLIB_EXPORT __declspec(dllexport) -#else -#define TAGLIB_EXPORT __declspec(dllimport) -#endif -#elif defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 1) -#define TAGLIB_EXPORT __attribute__ ((visibility("default"))) -#else -#define TAGLIB_EXPORT -#endif - -#endif diff --git a/taglib/taglib/tagunion.cpp b/taglib/taglib/tagunion.cpp deleted file mode 100644 index 52d7136..0000000 --- a/taglib/taglib/tagunion.cpp +++ /dev/null @@ -1,186 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include "tagunion.h" -#include "tstringlist.h" - -using namespace TagLib; - -#define stringUnion(method) \ - if(tag(0) && !tag(0)->method().isEmpty()) \ - return tag(0)->method(); \ - if(tag(1) && !tag(1)->method().isEmpty()) \ - return tag(1)->method(); \ - if(tag(2) && !tag(2)->method().isEmpty()) \ - return tag(2)->method(); \ - return String::null \ - -#define numberUnion(method) \ - if(tag(0) && tag(0)->method() > 0) \ - return tag(0)->method(); \ - if(tag(1) && tag(1)->method() > 0) \ - return tag(1)->method(); \ - if(tag(2) && tag(2)->method() > 0) \ - return tag(2)->method(); \ - return 0 - -#define setUnion(method, value) \ - if(tag(0)) \ - tag(0)->set##method(value); \ - if(tag(1)) \ - tag(1)->set##method(value); \ - if(tag(2)) \ - tag(2)->set##method(value); \ - -class TagUnion::TagUnionPrivate -{ -public: - TagUnionPrivate() : tags(3, static_cast<Tag *>(0)) - { - - } - - ~TagUnionPrivate() - { - delete tags[0]; - delete tags[1]; - delete tags[2]; - } - - std::vector<Tag *> tags; -}; - -TagUnion::TagUnion(Tag *first, Tag *second, Tag *third) -{ - d = new TagUnionPrivate; - - d->tags[0] = first; - d->tags[1] = second; - d->tags[2] = third; -} - -TagUnion::~TagUnion() -{ - delete d; -} - -Tag *TagUnion::operator[](int index) const -{ - return tag(index); -} - -Tag *TagUnion::tag(int index) const -{ - return d->tags[index]; -} - -void TagUnion::set(int index, Tag *tag) -{ - delete d->tags[index]; - d->tags[index] = tag; -} - -String TagUnion::title() const -{ - stringUnion(title); -} - -String TagUnion::artist() const -{ - stringUnion(artist); -} - -String TagUnion::album() const -{ - stringUnion(album); -} - -String TagUnion::comment() const -{ - stringUnion(comment); -} - -String TagUnion::genre() const -{ - stringUnion(genre); -} - -TagLib::uint TagUnion::year() const -{ - numberUnion(year); -} - -TagLib::uint TagUnion::track() const -{ - numberUnion(track); -} - -void TagUnion::setTitle(const String &s) -{ - setUnion(Title, s); -} - -void TagUnion::setArtist(const String &s) -{ - setUnion(Artist, s); -} - -void TagUnion::setAlbum(const String &s) -{ - setUnion(Album, s); -} - -void TagUnion::setComment(const String &s) -{ - setUnion(Comment, s); -} - -void TagUnion::setGenre(const String &s) -{ - setUnion(Genre, s); -} - -void TagUnion::setYear(uint i) -{ - setUnion(Year, i); -} - -void TagUnion::setTrack(uint i) -{ - setUnion(Track, i); -} - -bool TagUnion::isEmpty() const -{ - if(d->tags[0] && !d->tags[0]->isEmpty()) - return false; - if(d->tags[1] && !d->tags[1]->isEmpty()) - return false; - if(d->tags[2] && !d->tags[2]->isEmpty()) - return false; - - return true; -} - diff --git a/taglib/taglib/tagunion.h b/taglib/taglib/tagunion.h deleted file mode 100644 index e94d523..0000000 --- a/taglib/taglib/tagunion.h +++ /dev/null @@ -1,95 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_TAGUNION_H -#define TAGLIB_TAGUNION_H - -#include "tag.h" - -#ifndef DO_NOT_DOCUMENT - -namespace TagLib { - - /*! - * \internal - */ - - class TagUnion : public Tag - { - public: - - enum AccessType { Read, Write }; - - /*! - * Creates a TagLib::Tag that is the union of \a first, \a second, and - * \a third. The TagUnion takes ownership of these tags and will handle - * their deletion. - */ - TagUnion(Tag *first = 0, Tag *second = 0, Tag *third = 0); - - virtual ~TagUnion(); - - Tag *operator[](int index) const; - Tag *tag(int index) const; - - void set(int index, Tag *tag); - - virtual String title() const; - virtual String artist() const; - virtual String album() const; - virtual String comment() const; - virtual String genre() const; - virtual uint year() const; - virtual 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 bool isEmpty() const; - - template <class T> T *access(int index, bool create) - { - if(!create || tag(index)) - return static_cast<T *>(tag(index)); - - set(index, new T); - return static_cast<T *>(tag(index)); - } - - private: - TagUnion(const Tag &); - TagUnion &operator=(const Tag &); - - class TagUnionPrivate; - TagUnionPrivate *d; - }; -} - -#endif -#endif diff --git a/taglib/taglib/toolkit/taglib.h b/taglib/taglib/toolkit/taglib.h deleted file mode 100644 index cbca107..0000000 --- a/taglib/taglib/toolkit/taglib.h +++ /dev/null @@ -1,170 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_H -#define TAGLIB_H - -#include "taglib_config.h" - -#define TAGLIB_MAJOR_VERSION 1 -#define TAGLIB_MINOR_VERSION 9 -#define TAGLIB_PATCH_VERSION 1 - -#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 1)) -#define TAGLIB_IGNORE_MISSING_DESTRUCTOR _Pragma("GCC diagnostic ignored \"-Wnon-virtual-dtor\"") -#else -#define TAGLIB_IGNORE_MISSING_DESTRUCTOR -#endif - -#if (defined(_MSC_VER) && _MSC_VER >= 1600) -#define TAGLIB_CONSTRUCT_BITSET(x) static_cast<unsigned long long>(x) -#else -#define TAGLIB_CONSTRUCT_BITSET(x) static_cast<unsigned long>(x) -#endif - -#include <string> - -//! A namespace for all TagLib related classes and functions - -/*! - * This namespace contains everything in TagLib. For projects working with - * TagLib extensively it may be convenient to add a - * \code - * using namespace TagLib; - * \endcode - */ - -namespace TagLib { - - class String; - - typedef wchar_t wchar; // Assumed to be sufficient to store a UTF-16 char. - typedef unsigned char uchar; - typedef unsigned short ushort; - typedef unsigned int uint; - typedef unsigned long long ulonglong; - - // long/ulong can be either 32-bit or 64-bit wide. - typedef unsigned long ulong; - - /*! - * Unfortunately std::wstring isn't defined on some systems, (i.e. GCC < 3) - * so I'm providing something here that should be constant. - */ - typedef std::basic_string<wchar> wstring; -} - -/*! - * \mainpage TagLib - * - * \section intro Introduction - * - * TagLib is a library for reading and editing audio meta data, commonly know as \e tags. - * - * Features: - * - A clean, high level, C++ API to handling audio meta data. - * - Format specific APIs for advanced API users. - * - ID3v1, ID3v2, APE, FLAC, Xiph, iTunes-style MP4 and WMA tag formats. - * - MP3, MPC, FLAC, MP4, ASF, AIFF, WAV, TrueAudio, WavPack, Ogg FLAC, Ogg Vorbis, Speex and Opus file formats. - * - Basic audio file properties such as length, sample rate, etc. - * - Long term binary and source compatibility. - * - Extensible design, notably the ability to add other formats or extend current formats as a library user. - * - Full support for unicode and internationalized tags. - * - Dual <a href="http://www.mozilla.org/MPL/MPL-1.1.html">MPL</a> and - * <a href="http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html">LGPL</a> licenses. - * - No external toolkit dependancies. - * - * \section why Why TagLib? - * - * TagLib originally was written to provide an updated and improved ID3v2 implementation in C++ for use - * in a variety of Open Source projects. Since development began in 2002 and the 1.0 release in 2004 - * it has expanded to cover a wide variety of tag and file formats and is used in a wide variety of - * Open Source and proprietary applications. It now supports a variety of UNIXes, including Apple's OS - * X, as well as Microsoft Windows. - * - * \section commercial Usage in Commercial Applications - * - * TagLib's licenses \e do allow usage within propriety (\e closed) applications, however TagLib is \e not - * public domain. Please note the requirements of the LGPL or MPL, and adhere to at least one of them. - * In simple terms, you must at a minimum note your usage of TagLib, note the licensing terms of TagLib and - * if you make changes to TagLib publish them. Please review the licenses above before using TagLib in your - * software. Note that you may choose either the MPL or the LGPL, you do not have to fulfill the - * requirements of both. - * - * \section installing Installing TagLib - * - * Please see the <a href="http://developer.kde.org/~wheeler/taglib.html">TagLib website</a> for the latest - * downloads. - * - * TagLib can be built using the CMake build system. TagLib installs a taglib-config and pkg-config file to - * make it easier to integrate into various build systems. Note that TagLib's include install directory \e must - * be included in the header include path. Simply adding <taglib/tag.h> will \e not work. - * - * \section start Getting Started - * - * TagLib provides both simple, abstract APIs which make it possible to ignore the differences between tagging - * formats and format specific APIs which allow programmers to work with the features of specific tagging - * schemes. There is a similar abstraction mechanism for AudioProperties. - * - * The best place to start is with the <b>Class Hierarchy</b> linked at the top of the page. The File and - * AudioProperties classes and their subclasses are the core of TagLib. The FileRef class is also a convenient - * way for using a value-based handle. - * - * \note When working with FileRef please consider that it has only the most basic (extension-based) file - * type resolution. Please see its documentation on how to plug in more advanced file type resolution. (Such - * resolution may be part of later TagLib releases by default.) - * - * Here's a very simple example with TagLib: - * - * \code - * - * TagLib::FileRef f("Latex Solar Beef.mp3"); - * TagLib::String artist = f.tag()->artist(); // artist == "Frank Zappa" - * - * f.tag()->setAlbum("Fillmore East"); - * f.save(); - * - * TagLib::FileRef g("Free City Rhymes.ogg"); - * TagLib::String album = g.tag()->album(); // album == "NYC Ghosts & Flowers" - * - * g.tag()->setTrack(1); - * g.save(); - * - * \endcode - * - * More examples can be found in the \e examples directory of the source distribution. - * - * \section Contact - * - * Questions about TagLib should be directed to the TagLib mailing list, not directly to the author. - * - * - <a href="http://developer.kde.org/~wheeler/taglib/">TagLib Homepage</a> - * - <a href="https://mail.kde.org/mailman/listinfo/taglib-devel">TagLib Mailing List (taglib-devel@kde.org)</a> - * - * \author Scott Wheeler <wheeler@kde.org> et al. - * - */ - -#endif diff --git a/taglib/taglib/toolkit/tbytevector.cpp b/taglib/taglib/toolkit/tbytevector.cpp deleted file mode 100644 index b658246..0000000 --- a/taglib/taglib/toolkit/tbytevector.cpp +++ /dev/null @@ -1,857 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <algorithm> -#include <iostream> -#include <cstdio> -#include <cstring> - -#include <tstring.h> -#include <tdebug.h> -#include "trefcounter.h" -#include "tutils.h" - -#include "tbytevector.h" - -// This is a bit ugly to keep writing over and over again. - -// A rather obscure feature of the C++ spec that I hadn't thought of that makes -// working with C libs much more efficient. There's more here: -// -// http://www.informit.com/isapi/product_id~{9C84DAB4-FE6E-49C5-BB0A-FB50331233EA}/content/index.asp - -#define DATA(x) (&(x->data->data[0])) - -namespace TagLib { - -static const char hexTable[17] = "0123456789abcdef"; - -static const uint crcTable[256] = { - 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, - 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, - 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, - 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, - 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, - 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, - 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, - 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, - 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, - 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, - 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, - 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, - 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, - 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, - 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, - 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, - 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, - 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, - 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, - 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, - 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, - 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, - 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, - 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, - 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, - 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, - 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, - 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, - 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, - 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, - 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, - 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, - 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, - 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, - 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, - 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, - 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, - 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, - 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, - 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, - 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, - 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, - 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 -}; - -/*! - * A templatized straightforward find that works with the types - * std::vector<char>::iterator and std::vector<char>::reverse_iterator. - */ -template <class TIterator> -int findChar( - const TIterator dataBegin, const TIterator dataEnd, - char c, uint offset, int byteAlign) -{ - const size_t dataSize = dataEnd - dataBegin; - if(dataSize == 0 || offset > dataSize - 1) - return -1; - - // n % 0 is invalid - - if(byteAlign == 0) - return -1; - - for(TIterator it = dataBegin + offset; it < dataEnd; it += byteAlign) { - if(*it == c) - return (it - dataBegin); - } - - return -1; -} - -/*! - * A templatized KMP find that works with the types - * std::vector<char>::iterator and std::vector<char>::reverse_iterator. - */ -template <class TIterator> -int findVector( - const TIterator dataBegin, const TIterator dataEnd, - const TIterator patternBegin, const TIterator patternEnd, - uint offset, int byteAlign) -{ - const size_t dataSize = dataEnd - dataBegin; - const size_t patternSize = patternEnd - patternBegin; - if(patternSize > dataSize || offset > dataSize - 1) - return -1; - - // n % 0 is invalid - - if(byteAlign == 0) - return -1; - - // Special case that pattern contains just single char. - - if(patternSize == 1) - return findChar(dataBegin, dataEnd, *patternBegin, offset, byteAlign); - - size_t lastOccurrence[256]; - - for(size_t i = 0; i < 256; ++i) - lastOccurrence[i] = patternSize; - - for(size_t i = 0; i < patternSize - 1; ++i) - lastOccurrence[static_cast<uchar>(*(patternBegin + i))] = patternSize - i - 1; - - TIterator it = dataBegin + patternSize - 1 + offset; - while(true) - { - TIterator itBuffer = it; - TIterator itPattern = patternBegin + patternSize - 1; - - while(*itBuffer == *itPattern) - { - if(itPattern == patternBegin) - { - if((itBuffer - dataBegin - offset) % byteAlign == 0) - return (itBuffer - dataBegin); - else - break; - } - - --itBuffer; - --itPattern; - } - - const size_t step = lastOccurrence[static_cast<uchar>(*it)]; - if(dataEnd - step <= it) - break; - - it += step; - } - - return -1; -} - -template <class T> -T toNumber(const ByteVector &v, size_t offset, size_t length, bool mostSignificantByteFirst) -{ - if(offset >= v.size()) { - debug("toNumber<T>() -- No data to convert. Returning 0."); - return 0; - } - - length = std::min(length, v.size() - offset); - - T sum = 0; - for(size_t i = 0; i < length; i++) { - const size_t shift = (mostSignificantByteFirst ? length - 1 - i : i) * 8; - sum |= static_cast<T>(static_cast<uchar>(v[offset + i])) << shift; - } - - return sum; -} - -template <class T> -T toNumber(const ByteVector &v, size_t offset, bool mostSignificantByteFirst) -{ - static const bool isBigEndian = (Utils::SystemByteOrder == Utils::BigEndian); - const bool swap = (mostSignificantByteFirst != isBigEndian); - - if(offset + sizeof(T) > v.size()) - return toNumber<T>(v, offset, v.size() - offset, mostSignificantByteFirst); - - // Uses memcpy instead of reinterpret_cast to avoid an alignment exception. - T tmp; - ::memcpy(&tmp, v.data() + offset, sizeof(T)); - - if(swap) - return Utils::byteSwap(tmp); - else - return tmp; -} - -template <class T> -ByteVector fromNumber(T value, bool mostSignificantByteFirst) -{ - static const bool isBigEndian = (Utils::SystemByteOrder == Utils::BigEndian); - const bool swap = (mostSignificantByteFirst != isBigEndian); - - if(swap) - value = Utils::byteSwap(value); - - return ByteVector(reinterpret_cast<const char *>(&value), sizeof(T)); -} - -class DataPrivate : public RefCounter -{ -public: - DataPrivate() - { - } - - DataPrivate(const std::vector<char> &v, uint offset, uint length) - : data(v.begin() + offset, v.begin() + offset + length) - { - } - - // A char* can be an iterator. - DataPrivate(const char *begin, const char *end) - : data(begin, end) - { - } - - DataPrivate(uint len, char c) - : data(len, c) - { - } - - std::vector<char> data; -}; - -class ByteVector::ByteVectorPrivate : public RefCounter -{ -public: - ByteVectorPrivate() - : RefCounter() - , data(new DataPrivate()) - , offset(0) - , length(0) - { - } - - ByteVectorPrivate(ByteVectorPrivate *d, uint o, uint l) - : RefCounter() - , data(d->data) - , offset(d->offset + o) - , length(l) - { - data->ref(); - } - - ByteVectorPrivate(const std::vector<char> &v, uint o, uint l) - : RefCounter() - , data(new DataPrivate(v, o, l)) - , offset(0) - , length(l) - { - } - - ByteVectorPrivate(uint l, char c) - : RefCounter() - , data(new DataPrivate(l, c)) - , offset(0) - , length(l) - { - } - - ByteVectorPrivate(const char *s, uint l) - : RefCounter() - , data(new DataPrivate(s, s + l)) - , offset(0) - , length(l) - { - } - - void detach() - { - if(data->count() > 1) { - data->deref(); - data = new DataPrivate(data->data, offset, length); - offset = 0; - } - } - - ~ByteVectorPrivate() - { - if(data->deref()) - delete data; - } - - ByteVectorPrivate &operator=(const ByteVectorPrivate &x) - { - if(&x != this) - { - if(data->deref()) - delete data; - - data = x.data; - data->ref(); - } - - return *this; - } - - DataPrivate *data; - uint offset; - uint length; -}; - -//////////////////////////////////////////////////////////////////////////////// -// static members -//////////////////////////////////////////////////////////////////////////////// - -ByteVector ByteVector::null; - -ByteVector ByteVector::fromCString(const char *s, uint length) -{ - if(length == 0xffffffff) - return ByteVector(s, ::strlen(s)); - else - return ByteVector(s, length); -} - -ByteVector ByteVector::fromUInt(uint value, bool mostSignificantByteFirst) -{ - return fromNumber<uint>(value, mostSignificantByteFirst); -} - -ByteVector ByteVector::fromShort(short value, bool mostSignificantByteFirst) -{ - return fromNumber<ushort>(value, mostSignificantByteFirst); -} - -ByteVector ByteVector::fromLongLong(long long value, bool mostSignificantByteFirst) -{ - return fromNumber<unsigned long long>(value, mostSignificantByteFirst); -} - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -ByteVector::ByteVector() - : d(new ByteVectorPrivate()) -{ -} - -ByteVector::ByteVector(uint size, char value) - : d(new ByteVectorPrivate(size, value)) -{ -} - -ByteVector::ByteVector(const ByteVector &v) - : d(v.d) -{ - d->ref(); -} - -ByteVector::ByteVector(const ByteVector &v, uint offset, uint length) - : d(new ByteVectorPrivate(v.d, offset, length)) -{ -} - -ByteVector::ByteVector(char c) - : d(new ByteVectorPrivate(1, c)) -{ -} - -ByteVector::ByteVector(const char *data, uint length) - : d(new ByteVectorPrivate(data, length)) -{ -} - -ByteVector::ByteVector(const char *data) - : d(new ByteVectorPrivate(data, ::strlen(data))) -{ -} - -ByteVector::~ByteVector() -{ - if(d->deref()) - delete d; -} - -ByteVector &ByteVector::setData(const char *s, uint length) -{ - *this = ByteVector(s, length); - return *this; -} - -ByteVector &ByteVector::setData(const char *data) -{ - *this = ByteVector(data); - return *this; -} - -char *ByteVector::data() -{ - detach(); - return size() > 0 ? (DATA(d) + d->offset) : 0; -} - -const char *ByteVector::data() const -{ - return size() > 0 ? (DATA(d) + d->offset) : 0; -} - -ByteVector ByteVector::mid(uint index, uint length) const -{ - index = std::min(index, size()); - length = std::min(length, size() - index); - - return ByteVector(*this, index, length); -} - -char ByteVector::at(uint index) const -{ - return index < size() ? DATA(d)[d->offset + index] : 0; -} - -int ByteVector::find(const ByteVector &pattern, uint offset, int byteAlign) const -{ - return findVector<ConstIterator>( - begin(), end(), pattern.begin(), pattern.end(), offset, byteAlign); -} - -int ByteVector::find(char c, uint offset, int byteAlign) const -{ - return findChar<ConstIterator>(begin(), end(), c, offset, byteAlign); -} - -int ByteVector::rfind(const ByteVector &pattern, uint offset, int byteAlign) const -{ - if(offset > 0) { - offset = size() - offset - pattern.size(); - if(offset >= size()) - offset = 0; - } - - const int pos = findVector<ConstReverseIterator>( - rbegin(), rend(), pattern.rbegin(), pattern.rend(), offset, byteAlign); - - if(pos == -1) - return -1; - else - return size() - pos - pattern.size(); -} - -bool ByteVector::containsAt(const ByteVector &pattern, uint offset, uint patternOffset, uint patternLength) const -{ - if(pattern.size() < patternLength) - patternLength = pattern.size(); - - // do some sanity checking -- all of these things are needed for the search to be valid - const uint compareLength = patternLength - patternOffset; - if(offset + compareLength > size() || patternOffset >= pattern.size() || patternLength == 0) - return false; - - return (::memcmp(data() + offset, pattern.data() + patternOffset, compareLength) == 0); -} - -bool ByteVector::startsWith(const ByteVector &pattern) const -{ - return containsAt(pattern, 0); -} - -bool ByteVector::endsWith(const ByteVector &pattern) const -{ - return containsAt(pattern, size() - pattern.size()); -} - -ByteVector &ByteVector::replace(const ByteVector &pattern, const ByteVector &with) -{ - if(pattern.size() == 0 || pattern.size() > size()) - return *this; - - const uint withSize = with.size(); - const uint patternSize = pattern.size(); - int offset = 0; - - if(withSize == patternSize) { - // I think this case might be common enough to optimize it - detach(); - offset = find(pattern); - while(offset >= 0) { - ::memcpy(data() + offset, with.data(), withSize); - offset = find(pattern, offset + withSize); - } - return *this; - } - - // calculate new size: - uint newSize = 0; - for(;;) { - int next = find(pattern, offset); - if(next < 0) { - if(offset == 0) - // pattern not found, do nothing: - return *this; - newSize += size() - offset; - break; - } - newSize += (next - offset) + withSize; - offset = next + patternSize; - } - - // new private data of appropriate size: - ByteVectorPrivate *newData = new ByteVectorPrivate(newSize, 0); - char *target = DATA(newData); - const char *source = data(); - - // copy modified data into new private data: - offset = 0; - for(;;) { - int next = find(pattern, offset); - if(next < 0) { - ::memcpy(target, source + offset, size() - offset); - break; - } - int chunkSize = next - offset; - ::memcpy(target, source + offset, chunkSize); - target += chunkSize; - ::memcpy(target, with.data(), withSize); - target += withSize; - offset += chunkSize + patternSize; - } - - // replace private data: - if(d->deref()) - delete d; - - d = newData; - - return *this; -} - -int ByteVector::endsWithPartialMatch(const ByteVector &pattern) const -{ - if(pattern.size() > size()) - return -1; - - const int startIndex = size() - pattern.size(); - - // try to match the last n-1 bytes from the vector (where n is the pattern - // size) -- continue trying to match n-2, n-3...1 bytes - - for(uint i = 1; i < pattern.size(); i++) { - if(containsAt(pattern, startIndex + i, 0, pattern.size() - i)) - return startIndex + i; - } - - return -1; -} - -ByteVector &ByteVector::append(const ByteVector &v) -{ - if(v.d->length != 0) - { - detach(); - - uint originalSize = size(); - resize(originalSize + v.size()); - ::memcpy(data() + originalSize, v.data(), v.size()); - } - - return *this; -} - -ByteVector &ByteVector::clear() -{ - *this = ByteVector(); - return *this; -} - -TagLib::uint ByteVector::size() const -{ - return d->length; -} - -ByteVector &ByteVector::resize(uint size, char padding) -{ - if(size != d->length) { - detach(); - d->data->data.resize(d->offset + size, padding); - d->length = size; - } - - return *this; -} - -ByteVector::Iterator ByteVector::begin() -{ - return d->data->data.begin() + d->offset; -} - -ByteVector::ConstIterator ByteVector::begin() const -{ - return d->data->data.begin() + d->offset; -} - -ByteVector::Iterator ByteVector::end() -{ - return d->data->data.begin() + d->offset + d->length; -} - -ByteVector::ConstIterator ByteVector::end() const -{ - return d->data->data.begin() + d->offset + d->length; -} - -ByteVector::ReverseIterator ByteVector::rbegin() -{ - std::vector<char> &v = d->data->data; - return v.rbegin() + (v.size() - (d->offset + d->length)); -} - -ByteVector::ConstReverseIterator ByteVector::rbegin() const -{ - std::vector<char> &v = d->data->data; - return v.rbegin() + (v.size() - (d->offset + d->length)); -} - -ByteVector::ReverseIterator ByteVector::rend() -{ - std::vector<char> &v = d->data->data; - return v.rbegin() + (v.size() - d->offset); -} - -ByteVector::ConstReverseIterator ByteVector::rend() const -{ - std::vector<char> &v = d->data->data; - return v.rbegin() + (v.size() - d->offset); -} - -bool ByteVector::isNull() const -{ - return (d == null.d); -} - -bool ByteVector::isEmpty() const -{ - return (d->length == 0); -} - -TagLib::uint ByteVector::checksum() const -{ - uint sum = 0; - for(ByteVector::ConstIterator it = begin(); it != end(); ++it) - sum = (sum << 8) ^ crcTable[((sum >> 24) & 0xff) ^ uchar(*it)]; - return sum; -} - -TagLib::uint ByteVector::toUInt(bool mostSignificantByteFirst) const -{ - return toNumber<uint>(*this, 0, mostSignificantByteFirst); -} - -TagLib::uint ByteVector::toUInt(uint offset, bool mostSignificantByteFirst) const -{ - return toNumber<uint>(*this, offset, mostSignificantByteFirst); -} - -TagLib::uint ByteVector::toUInt(uint offset, uint length, bool mostSignificantByteFirst) const -{ - return toNumber<uint>(*this, offset, length, mostSignificantByteFirst); -} - -short ByteVector::toShort(bool mostSignificantByteFirst) const -{ - return toNumber<unsigned short>(*this, 0, mostSignificantByteFirst); -} - -short ByteVector::toShort(uint offset, bool mostSignificantByteFirst) const -{ - return toNumber<unsigned short>(*this, offset, mostSignificantByteFirst); -} - -unsigned short ByteVector::toUShort(bool mostSignificantByteFirst) const -{ - return toNumber<unsigned short>(*this, 0, mostSignificantByteFirst); -} - -unsigned short ByteVector::toUShort(uint offset, bool mostSignificantByteFirst) const -{ - return toNumber<unsigned short>(*this, offset, mostSignificantByteFirst); -} - -long long ByteVector::toLongLong(bool mostSignificantByteFirst) const -{ - return toNumber<unsigned long long>(*this, 0, mostSignificantByteFirst); -} - -long long ByteVector::toLongLong(uint offset, bool mostSignificantByteFirst) const -{ - return toNumber<unsigned long long>(*this, offset, mostSignificantByteFirst); -} - -const char &ByteVector::operator[](int index) const -{ - return d->data->data[d->offset + index]; -} - -char &ByteVector::operator[](int index) -{ - detach(); - return d->data->data[d->offset + index]; -} - -bool ByteVector::operator==(const ByteVector &v) const -{ - if(size() != v.size()) - return false; - - return (::memcmp(data(), v.data(), size()) == 0); -} - -bool ByteVector::operator!=(const ByteVector &v) const -{ - return !operator==(v); -} - -bool ByteVector::operator==(const char *s) const -{ - if(size() != ::strlen(s)) - return false; - - return (::memcmp(data(), s, size()) == 0); -} - -bool ByteVector::operator!=(const char *s) const -{ - return !operator==(s); -} - -bool ByteVector::operator<(const ByteVector &v) const -{ - const int result = ::memcmp(data(), v.data(), std::min(size(), v.size())); - if(result != 0) - return result < 0; - else - return size() < v.size(); -} - -bool ByteVector::operator>(const ByteVector &v) const -{ - return v < *this; -} - -ByteVector ByteVector::operator+(const ByteVector &v) const -{ - ByteVector sum(*this); - sum.append(v); - return sum; -} - -ByteVector &ByteVector::operator=(const ByteVector &v) -{ - if(&v == this) - return *this; - - if(d->deref()) - delete d; - - d = v.d; - d->ref(); - return *this; -} - -ByteVector &ByteVector::operator=(char c) -{ - *this = ByteVector(c); - return *this; -} - -ByteVector &ByteVector::operator=(const char *data) -{ - *this = ByteVector(data); - return *this; -} - -ByteVector ByteVector::toHex() const -{ - ByteVector encoded(size() * 2); - char *p = encoded.data(); - - for(uint i = 0; i < size(); i++) { - unsigned char c = data()[i]; - *p++ = hexTable[(c >> 4) & 0x0F]; - *p++ = hexTable[(c ) & 0x0F]; - } - - return encoded; -} - -//////////////////////////////////////////////////////////////////////////////// -// protected members -//////////////////////////////////////////////////////////////////////////////// - -void ByteVector::detach() -{ - if(d->data->count() > 1) { - d->data->deref(); - d->data = new DataPrivate(d->data->data, d->offset, d->length); - d->offset = 0; - } - - if(d->count() > 1) { - d->deref(); - d = new ByteVectorPrivate(d->data->data, d->offset, d->length); - } -} -} - -//////////////////////////////////////////////////////////////////////////////// -// related functions -//////////////////////////////////////////////////////////////////////////////// - -std::ostream &operator<<(std::ostream &s, const TagLib::ByteVector &v) -{ - for(TagLib::uint i = 0; i < v.size(); i++) - s << v[i]; - return s; -} diff --git a/taglib/taglib/toolkit/tbytevector.h b/taglib/taglib/toolkit/tbytevector.h deleted file mode 100644 index 538565b..0000000 --- a/taglib/taglib/toolkit/tbytevector.h +++ /dev/null @@ -1,518 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_BYTEVECTOR_H -#define TAGLIB_BYTEVECTOR_H - -#include "taglib.h" -#include "taglib_export.h" - -#include <vector> -#include <iostream> - -namespace TagLib { - - //! A byte vector - - /*! - * This class provides a byte vector with some methods that are useful for - * tagging purposes. Many of the search functions are tailored to what is - * useful for finding tag related paterns in a data array. - */ - - class TAGLIB_EXPORT ByteVector - { - public: -#ifndef DO_NOT_DOCUMENT - typedef std::vector<char>::iterator Iterator; - typedef std::vector<char>::const_iterator ConstIterator; - typedef std::vector<char>::reverse_iterator ReverseIterator; - typedef std::vector<char>::const_reverse_iterator ConstReverseIterator; -#endif - - /*! - * Constructs an empty byte vector. - */ - ByteVector(); - - /*! - * Construct a vector of size \a size with all values set to \a value by - * default. - */ - ByteVector(uint size, char value = 0); - - /*! - * Constructs a byte vector that is a copy of \a v. - */ - ByteVector(const ByteVector &v); - - /*! - * Constructs a byte vector that is a copy of \a v. - */ - ByteVector(const ByteVector &v, uint offset, uint length); - - /*! - * Constructs a byte vector that contains \a c. - */ - ByteVector(char c); - - /*! - * Constructs a byte vector that copies \a data for up to \a length bytes. - */ - ByteVector(const char *data, uint length); - - /*! - * Constructs a byte vector that copies \a data up to the first null - * byte. The behavior is undefined if \a data is not null terminated. - * This is particularly useful for constructing byte arrays from string - * constants. - */ - ByteVector(const char *data); - - /*! - * Destroys this ByteVector instance. - */ - virtual ~ByteVector(); - - /*! - * Sets the data for the byte array using the first \a length bytes of \a data - */ - ByteVector &setData(const char *data, uint length); - - /*! - * Sets the data for the byte array copies \a data up to the first null - * byte. The behavior is undefined if \a data is not null terminated. - */ - ByteVector &setData(const char *data); - - /*! - * Returns a pointer to the internal data structure. - * - * \warning Care should be taken when modifying this data structure as it is - * easy to corrupt the ByteVector when doing so. Specifically, while the - * data may be changed, its length may not be. - */ - char *data(); - - /*! - * Returns a pointer to the internal data structure which may not be modified. - */ - const char *data() const; - - /*! - * Returns a byte vector made up of the bytes starting at \a index and - * for \a length bytes. If \a length is not specified it will return the bytes - * from \a index to the end of the vector. - */ - ByteVector mid(uint index, uint length = 0xffffffff) const; - - /*! - * This essentially performs the same as operator[](), but instead of causing - * a runtime error if the index is out of bounds, it will return a null byte. - */ - char at(uint index) const; - - /*! - * Searches the ByteVector for \a pattern starting at \a offset and returns - * the offset. Returns -1 if the pattern was not found. If \a byteAlign is - * specified the pattern will only be matched if it starts on a byte divisible - * by \a byteAlign (starting from \a offset). - */ - int find(const ByteVector &pattern, uint offset = 0, int byteAlign = 1) const; - - /*! - * Searches the char for \a c starting at \a offset and returns - * the offset. Returns \a npos if the pattern was not found. If \a byteAlign is - * specified the pattern will only be matched if it starts on a byte divisible - * by \a byteAlign (starting from \a offset). - */ - int find(char c, uint offset = 0, int byteAlign = 1) const; - - /*! - * Searches the ByteVector for \a pattern starting from either the end of the - * vector or \a offset and returns the offset. Returns -1 if the pattern was - * not found. If \a byteAlign is specified the pattern will only be matched - * if it starts on a byte divisible by \a byteAlign (starting from \a offset). - */ - int rfind(const ByteVector &pattern, uint offset = 0, int byteAlign = 1) const; - - /*! - * Checks to see if the vector contains the \a pattern starting at position - * \a offset. Optionally, if you only want to search for part of the pattern - * you can specify an offset within the pattern to start from. Also, you can - * specify to only check for the first \a patternLength bytes of \a pattern with - * the \a patternLength argument. - */ - bool containsAt(const ByteVector &pattern, uint offset, uint patternOffset = 0, uint patternLength = 0xffffffff) const; - - /*! - * Returns true if the vector starts with \a pattern. - */ - bool startsWith(const ByteVector &pattern) const; - - /*! - * Returns true if the vector ends with \a pattern. - */ - bool endsWith(const ByteVector &pattern) const; - - /*! - * Replaces \a pattern with \a with and returns a reference to the ByteVector - * after the operation. This \e does modify the vector. - */ - ByteVector &replace(const ByteVector &pattern, const ByteVector &with); - - /*! - * Checks for a partial match of \a pattern at the end of the vector. It - * returns the offset of the partial match within the vector, or -1 if the - * pattern is not found. This method is particularly useful when searching for - * patterns that start in one vector and end in another. When combined with - * startsWith() it can be used to find a pattern that overlaps two buffers. - * - * \note This will not match the complete pattern at the end of the string; use - * endsWith() for that. - */ - int endsWithPartialMatch(const ByteVector &pattern) const; - - /*! - * Appends \a v to the end of the ByteVector. - */ - ByteVector &append(const ByteVector &v); - - /*! - * Clears the data. - */ - ByteVector &clear(); - - /*! - * Returns the size of the array. - */ - uint size() const; - - /*! - * Resize the vector to \a size. If the vector is currently less than - * \a size, pad the remaining spaces with \a padding. Returns a reference - * to the resized vector. - */ - ByteVector &resize(uint size, char padding = 0); - - /*! - * Returns an Iterator that points to the front of the vector. - */ - Iterator begin(); - - /*! - * Returns a ConstIterator that points to the front of the vector. - */ - ConstIterator begin() const; - - /*! - * Returns an Iterator that points to the back of the vector. - */ - Iterator end(); - - /*! - * Returns a ConstIterator that points to the back of the vector. - */ - ConstIterator end() const; - - /*! - * Returns a ReverseIterator that points to the front of the vector. - */ - ReverseIterator rbegin(); - - /*! - * Returns a ConstReverseIterator that points to the front of the vector. - */ - ConstReverseIterator rbegin() const; - - /*! - * Returns a ReverseIterator that points to the back of the vector. - */ - ReverseIterator rend(); - - /*! - * Returns a ConstReverseIterator that points to the back of the vector. - */ - ConstReverseIterator rend() const; - - /*! - * Returns true if the vector is null. - * - * \note A vector may be empty without being null. - * \see isEmpty() - */ - bool isNull() const; - - /*! - * Returns true if the ByteVector is empty. - * - * \see size() - * \see isNull() - */ - bool isEmpty() const; - - /*! - * Returns a CRC checksum of the byte vector's data. - */ - uint checksum() const; - - /*! - * Converts the first 4 bytes of the vector to an unsigned integer. - * - * If \a mostSignificantByteFirst is true this will operate left to right - * evaluating the integer. For example if \a mostSignificantByteFirst is - * true then $00 $00 $00 $01 == 0x00000001 == 1, if false, $01 00 00 00 == - * 0x01000000 == 1. - * - * \see fromUInt() - */ - uint toUInt(bool mostSignificantByteFirst = true) const; - - /*! - * Converts the 4 bytes at \a offset of the vector to an unsigned integer. - * - * If \a mostSignificantByteFirst is true this will operate left to right - * evaluating the integer. For example if \a mostSignificantByteFirst is - * true then $00 $00 $00 $01 == 0x00000001 == 1, if false, $01 00 00 00 == - * 0x01000000 == 1. - * - * \see fromUInt() - */ - uint toUInt(uint offset, bool mostSignificantByteFirst = true) const; - - /*! - * Converts the \a length bytes at \a offset of the vector to an unsigned - * integer. If \a length is larger than 4, the excess is ignored. - * - * If \a mostSignificantByteFirst is true this will operate left to right - * evaluating the integer. For example if \a mostSignificantByteFirst is - * true then $00 $00 $00 $01 == 0x00000001 == 1, if false, $01 00 00 00 == - * 0x01000000 == 1. - * - * \see fromUInt() - */ - uint toUInt(uint offset, uint length, bool mostSignificantByteFirst = true) const; - - /*! - * Converts the first 2 bytes of the vector to a (signed) short. - * - * If \a mostSignificantByteFirst is true this will operate left to right - * evaluating the integer. For example if \a mostSignificantByteFirst is - * true then $00 $01 == 0x0001 == 1, if false, $01 00 == 0x01000000 == 1. - * - * \see fromShort() - */ - short toShort(bool mostSignificantByteFirst = true) const; - - /*! - * Converts the 2 bytes at \a offset of the vector to a (signed) short. - * - * If \a mostSignificantByteFirst is true this will operate left to right - * evaluating the integer. For example if \a mostSignificantByteFirst is - * true then $00 $01 == 0x0001 == 1, if false, $01 00 == 0x01000000 == 1. - * - * \see fromShort() - */ - short toShort(uint offset, bool mostSignificantByteFirst = true) const; - - /*! - * Converts the first 2 bytes of the vector to a unsigned short. - * - * If \a mostSignificantByteFirst is true this will operate left to right - * evaluating the integer. For example if \a mostSignificantByteFirst is - * true then $00 $01 == 0x0001 == 1, if false, $01 00 == 0x01000000 == 1. - * - * \see fromShort() - */ - unsigned short toUShort(bool mostSignificantByteFirst = true) const; - - /*! - * Converts the 2 bytes at \a offset of the vector to a unsigned short. - * - * If \a mostSignificantByteFirst is true this will operate left to right - * evaluating the integer. For example if \a mostSignificantByteFirst is - * true then $00 $01 == 0x0001 == 1, if false, $01 00 == 0x01000000 == 1. - * - * \see fromShort() - */ - unsigned short toUShort(uint offset, bool mostSignificantByteFirst = true) const; - - /*! - * Converts the first 8 bytes of the vector to a (signed) long long. - * - * If \a mostSignificantByteFirst is true this will operate left to right - * evaluating the integer. For example if \a mostSignificantByteFirst is - * true then $00 00 00 00 00 00 00 01 == 0x0000000000000001 == 1, - * if false, $01 00 00 00 00 00 00 00 == 0x0100000000000000 == 1. - * - * \see fromUInt() - */ - long long toLongLong(bool mostSignificantByteFirst = true) const; - - /*! - * Converts the 8 bytes at \a offset of the vector to a (signed) long long. - * - * If \a mostSignificantByteFirst is true this will operate left to right - * evaluating the integer. For example if \a mostSignificantByteFirst is - * true then $00 00 00 00 00 00 00 01 == 0x0000000000000001 == 1, - * if false, $01 00 00 00 00 00 00 00 == 0x0100000000000000 == 1. - * - * \see fromUInt() - */ - long long toLongLong(uint offset, bool mostSignificantByteFirst = true) const; - - /*! - * Creates a 4 byte ByteVector based on \a value. If - * \a mostSignificantByteFirst is true, then this will operate left to right - * in building the ByteVector. For example if \a mostSignificantByteFirst is - * true then $00 00 00 01 == 0x00000001 == 1, if false, $01 00 00 00 == - * 0x01000000 == 1. - * - * \see toUInt() - */ - static ByteVector fromUInt(uint value, bool mostSignificantByteFirst = true); - - /*! - * Creates a 2 byte ByteVector based on \a value. If - * \a mostSignificantByteFirst is true, then this will operate left to right - * in building the ByteVector. For example if \a mostSignificantByteFirst is - * true then $00 01 == 0x0001 == 1, if false, $01 00 == 0x0100 == 1. - * - * \see toShort() - */ - static ByteVector fromShort(short value, bool mostSignificantByteFirst = true); - - /*! - * Creates a 8 byte ByteVector based on \a value. If - * \a mostSignificantByteFirst is true, then this will operate left to right - * in building the ByteVector. For example if \a mostSignificantByteFirst is - * true then $00 00 00 01 == 0x0000000000000001 == 1, if false, - * $01 00 00 00 00 00 00 00 == 0x0100000000000000 == 1. - * - * \see toLongLong() - */ - static ByteVector fromLongLong(long long value, bool mostSignificantByteFirst = true); - - /*! - * Returns a ByteVector based on the CString \a s. - */ - static ByteVector fromCString(const char *s, uint length = 0xffffffff); - - /*! - * Returns a const refernence to the byte at \a index. - */ - const char &operator[](int index) const; - - /*! - * Returns a reference to the byte at \a index. - */ - char &operator[](int index); - - /*! - * Returns true if this ByteVector and \a v are equal. - */ - bool operator==(const ByteVector &v) const; - - /*! - * Returns true if this ByteVector and \a v are not equal. - */ - bool operator!=(const ByteVector &v) const; - - /*! - * Returns true if this ByteVector and the null terminated C string \a s - * contain the same data. - */ - bool operator==(const char *s) const; - - /*! - * Returns true if this ByteVector and the null terminated C string \a s - * do not contain the same data. - */ - bool operator!=(const char *s) const; - - /*! - * Returns true if this ByteVector is less than \a v. The value of the - * vectors is determined by evaluating the character from left to right, and - * in the event one vector is a superset of the other, the size is used. - */ - bool operator<(const ByteVector &v) const; - - /*! - * Returns true if this ByteVector is greater than \a v. - */ - bool operator>(const ByteVector &v) const; - - /*! - * Returns a vector that is \a v appended to this vector. - */ - ByteVector operator+(const ByteVector &v) const; - - /*! - * Copies ByteVector \a v. - */ - ByteVector &operator=(const ByteVector &v); - - /*! - * Copies ByteVector \a v. - */ - ByteVector &operator=(char c); - - /*! - * Copies ByteVector \a v. - */ - ByteVector &operator=(const char *data); - - /*! - * A static, empty ByteVector which is convenient and fast (since returning - * an empty or "null" value does not require instantiating a new ByteVector). - */ - static ByteVector null; - - /*! - * Returns a hex-encoded copy of the byte vector. - */ - ByteVector toHex() const; - - protected: - /* - * If this ByteVector is being shared via implicit sharing, do a deep copy - * of the data and separate from the shared members. This should be called - * by all non-const subclass members. - */ - void detach(); - - private: - class ByteVectorPrivate; - ByteVectorPrivate *d; - }; -} - -/*! - * \relates TagLib::ByteVector - * Streams the ByteVector \a v to the output stream \a s. - */ -TAGLIB_EXPORT std::ostream &operator<<(std::ostream &s, const TagLib::ByteVector &v); - -#endif diff --git a/taglib/taglib/toolkit/tbytevectorlist.cpp b/taglib/taglib/toolkit/tbytevectorlist.cpp deleted file mode 100644 index 7ea893f..0000000 --- a/taglib/taglib/toolkit/tbytevectorlist.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include "tbytevectorlist.h" - -using namespace TagLib; - -class ByteVectorListPrivate -{ - -}; - -//////////////////////////////////////////////////////////////////////////////// -// static members -//////////////////////////////////////////////////////////////////////////////// - -ByteVectorList ByteVectorList::split(const ByteVector &v, const ByteVector &pattern, - int byteAlign) -{ - return split(v, pattern, byteAlign, 0); -} - -ByteVectorList ByteVectorList::split(const ByteVector &v, const ByteVector &pattern, - int byteAlign, int max) -{ - ByteVectorList l; - - uint previousOffset = 0; - for(int offset = v.find(pattern, 0, byteAlign); - offset != -1 && (max == 0 || max > int(l.size()) + 1); - offset = v.find(pattern, offset + pattern.size(), byteAlign)) - { - if(offset - previousOffset >= 1) - l.append(v.mid(previousOffset, offset - previousOffset)); - else - l.append(ByteVector::null); - - previousOffset = offset + pattern.size(); - } - - if(previousOffset < v.size()) - l.append(v.mid(previousOffset, v.size() - previousOffset)); - - return l; -} - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -ByteVectorList::ByteVectorList() : List<ByteVector>() -{ - -} - -ByteVectorList::ByteVectorList(const ByteVectorList &l) : List<ByteVector>(l) -{ - -} - -ByteVectorList::~ByteVectorList() -{ - -} - -ByteVector ByteVectorList::toByteVector(const ByteVector &separator) const -{ - ByteVector v; - - ConstIterator it = begin(); - - while(it != end()) { - v.append(*it); - it++; - if(it != end()) - v.append(separator); - } - - return v; -} diff --git a/taglib/taglib/toolkit/tbytevectorlist.h b/taglib/taglib/toolkit/tbytevectorlist.h deleted file mode 100644 index 5852583..0000000 --- a/taglib/taglib/toolkit/tbytevectorlist.h +++ /dev/null @@ -1,91 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_BYTEVECTORLIST_H -#define TAGLIB_BYTEVECTORLIST_H - -#include "taglib_export.h" -#include "tbytevector.h" -#include "tlist.h" - -namespace TagLib { - - //! A list of ByteVectors - - /*! - * A List specialization with some handy features useful for ByteVectors. - */ - - class TAGLIB_EXPORT ByteVectorList : public List<ByteVector> - { - public: - - /*! - * Construct an empty ByteVectorList. - */ - ByteVectorList(); - - /*! - * Destroys this ByteVectorList instance. - */ - virtual ~ByteVectorList(); - - /*! - * Make a shallow, implicitly shared, copy of \a l. Because this is - * implicitly shared, this method is lightweight and suitable for - * pass-by-value usage. - */ - ByteVectorList(const ByteVectorList &l); - - /*! - * Convert the ByteVectorList to a ByteVector separated by \a separator. By - * default a space is used. - */ - ByteVector toByteVector(const ByteVector &separator = " ") const; - - /*! - * Splits the ByteVector \a v into several strings at \a pattern. This will - * not include the pattern in the returned ByteVectors. - */ - static ByteVectorList split(const ByteVector &v, const ByteVector &pattern, - int byteAlign = 1); - /*! - * Splits the ByteVector \a v into several strings at \a pattern. This will - * not include the pattern in the returned ByteVectors. \a max is the - * maximum number of entries that will be separated. If \a max for instance - * is 2 then a maximum of 1 match will be found and the vector will be split - * on that match. - */ - // BIC: merge with the function above - static ByteVectorList split(const ByteVector &v, const ByteVector &pattern, - int byteAlign, int max); - private: - class ByteVectorListPrivate; - ByteVectorListPrivate *d; - }; - -} - -#endif diff --git a/taglib/taglib/toolkit/tbytevectorstream.cpp b/taglib/taglib/toolkit/tbytevectorstream.cpp deleted file mode 100644 index dc480a2..0000000 --- a/taglib/taglib/toolkit/tbytevectorstream.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/*************************************************************************** - copyright : (C) 2011 by Lukas Lalinsky - email : lalinsky@gmail.com - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include "tbytevectorstream.h" -#include "tstring.h" -#include "tdebug.h" - -#include <stdio.h> -#include <string.h> - -#include <stdlib.h> - -using namespace TagLib; - -class ByteVectorStream::ByteVectorStreamPrivate -{ -public: - ByteVectorStreamPrivate(const ByteVector &data); - - ByteVector data; - long position; -}; - -ByteVectorStream::ByteVectorStreamPrivate::ByteVectorStreamPrivate(const ByteVector &data) : - data(data), - position(0) -{ -} - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -ByteVectorStream::ByteVectorStream(const ByteVector &data) -{ - d = new ByteVectorStreamPrivate(data); -} - -ByteVectorStream::~ByteVectorStream() -{ - delete d; -} - -FileName ByteVectorStream::name() const -{ - return FileName(""); // XXX do we need a name? -} - -ByteVector ByteVectorStream::readBlock(ulong length) -{ - if(length == 0) - return ByteVector::null; - - ByteVector v = d->data.mid(d->position, length); - d->position += v.size(); - return v; -} - -void ByteVectorStream::writeBlock(const ByteVector &data) -{ - uint size = data.size(); - if(long(d->position + size) > length()) { - truncate(d->position + size); - } - memcpy(d->data.data() + d->position, data.data(), size); - d->position += size; -} - -void ByteVectorStream::insert(const ByteVector &data, ulong start, ulong replace) -{ - long sizeDiff = data.size() - replace; - if(sizeDiff < 0) { - removeBlock(start + data.size(), -sizeDiff); - } - else if(sizeDiff > 0) { - truncate(length() + sizeDiff); - ulong readPosition = start + replace; - ulong writePosition = start + data.size(); - memmove(d->data.data() + writePosition, d->data.data() + readPosition, length() - sizeDiff - readPosition); - } - seek(start); - writeBlock(data); -} - -void ByteVectorStream::removeBlock(ulong start, ulong length) -{ - ulong readPosition = start + length; - ulong writePosition = start; - if(readPosition < ulong(ByteVectorStream::length())) { - ulong bytesToMove = ByteVectorStream::length() - readPosition; - memmove(d->data.data() + writePosition, d->data.data() + readPosition, bytesToMove); - writePosition += bytesToMove; - } - d->position = writePosition; - truncate(writePosition); -} - -bool ByteVectorStream::readOnly() const -{ - return false; -} - -bool ByteVectorStream::isOpen() const -{ - return true; -} - -void ByteVectorStream::seek(long offset, Position p) -{ - switch(p) { - case Beginning: - d->position = offset; - break; - case Current: - d->position += offset; - break; - case End: - d->position = length() - offset; - break; - } -} - -void ByteVectorStream::clear() -{ -} - -long ByteVectorStream::tell() const -{ - return d->position; -} - -long ByteVectorStream::length() -{ - return d->data.size(); -} - -void ByteVectorStream::truncate(long length) -{ - d->data.resize(length); -} - -ByteVector *ByteVectorStream::data() -{ - return &d->data; -} diff --git a/taglib/taglib/toolkit/tbytevectorstream.h b/taglib/taglib/toolkit/tbytevectorstream.h deleted file mode 100644 index 456b854..0000000 --- a/taglib/taglib/toolkit/tbytevectorstream.h +++ /dev/null @@ -1,145 +0,0 @@ -/*************************************************************************** - copyright : (C) 2011 by Lukas Lalinsky - email : lalinsky@gmail.com - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_BYTEVECTORSTREAM_H -#define TAGLIB_BYTEVECTORSTREAM_H - -#include "taglib_export.h" -#include "taglib.h" -#include "tbytevector.h" -#include "tiostream.h" - -namespace TagLib { - - class String; - class Tag; - class AudioProperties; - - //! In-memory Stream class using ByteVector for its storage. - - class TAGLIB_EXPORT ByteVectorStream : public IOStream - { - public: - /*! - * Construct a File object and opens the \a file. \a file should be a - * be a C-string in the local file system encoding. - */ - ByteVectorStream(const ByteVector &data); - - /*! - * Destroys this ByteVectorStream instance. - */ - virtual ~ByteVectorStream(); - - /*! - * Returns the file name in the local file system encoding. - */ - FileName name() const; - - /*! - * Reads a block of size \a length at the current get pointer. - */ - ByteVector readBlock(ulong length); - - /*! - * Attempts to write the block \a data at the current get pointer. If the - * file is currently only opened read only -- i.e. readOnly() returns true -- - * this attempts to reopen the file in read/write mode. - * - * \note This should be used instead of using the streaming output operator - * for a ByteVector. And even this function is significantly slower than - * doing output with a char[]. - */ - void writeBlock(const ByteVector &data); - - /*! - * Insert \a data at position \a start in the file overwriting \a replace - * bytes of the original content. - * - * \note This method is slow since it requires rewriting all of the file - * after the insertion point. - */ - void insert(const ByteVector &data, ulong start = 0, ulong replace = 0); - - /*! - * Removes a block of the file starting a \a start and continuing for - * \a length bytes. - * - * \note This method is slow since it involves rewriting all of the file - * after the removed portion. - */ - void removeBlock(ulong start = 0, ulong length = 0); - - /*! - * Returns true if the file is read only (or if the file can not be opened). - */ - bool readOnly() const; - - /*! - * Since the file can currently only be opened as an argument to the - * constructor (sort-of by design), this returns if that open succeeded. - */ - bool isOpen() const; - - /*! - * Move the I/O pointer to \a offset in the file from position \a p. This - * defaults to seeking from the beginning of the file. - * - * \see Position - */ - void seek(long offset, Position p = Beginning); - - /*! - * Reset the end-of-file and error flags on the file. - */ - void clear(); - - /*! - * Returns the current offset within the file. - */ - long tell() const; - - /*! - * Returns the length of the file. - */ - long length(); - - /*! - * Truncates the file to a \a length. - */ - void truncate(long length); - - ByteVector *data(); - - protected: - - private: - class ByteVectorStreamPrivate; - ByteVectorStreamPrivate *d; - }; - -} - -#endif diff --git a/taglib/taglib/toolkit/tdebug.cpp b/taglib/taglib/toolkit/tdebug.cpp deleted file mode 100644 index 71350af..0000000 --- a/taglib/taglib/toolkit/tdebug.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "tdebug.h" -#include "tstring.h" -#include "tdebuglistener.h" - -#include <bitset> -#include <cstdio> -#include <cstdarg> - -using namespace TagLib; - -namespace -{ - String format(const char *fmt, ...) - { - va_list args; - va_start(args, fmt); - - char buf[256]; - -#if defined(HAVE_SNPRINTF) - - vsnprintf(buf, sizeof(buf), fmt, args); - -#elif defined(HAVE_SPRINTF_S) - - vsprintf_s(buf, fmt, args); - -#else - - // Be careful. May cause a buffer overflow. - vsprintf(buf, fmt, args); - -#endif - - va_end(args); - - return String(buf); - } -} - -namespace TagLib -{ - // The instance is defined in tdebuglistener.cpp. - extern DebugListener *debugListener; - - void debug(const String &s) - { -#if !defined(NDEBUG) || defined(TRACE_IN_RELEASE) - - debugListener->printMessage("TagLib: " + s + "\n"); - -#endif - } - - void debugData(const ByteVector &v) - { -#if !defined(NDEBUG) || defined(TRACE_IN_RELEASE) - - for(size_t i = 0; i < v.size(); ++i) - { - std::string bits = std::bitset<8>(v[i]).to_string(); - String msg = format("*** [%d] - char '%c' - int %d, 0x%02x, 0b%s\n", - i, v[i], v[i], v[i], bits.c_str()); - - debugListener->printMessage(msg); - } - -#endif - } -} diff --git a/taglib/taglib/toolkit/tdebug.h b/taglib/taglib/toolkit/tdebug.h deleted file mode 100644 index bd94d15..0000000 --- a/taglib/taglib/toolkit/tdebug.h +++ /dev/null @@ -1,62 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_DEBUG_H -#define TAGLIB_DEBUG_H - -namespace TagLib { - - class String; - class ByteVector; - -#ifndef DO_NOT_DOCUMENT - - /*! - * A simple function that outputs the debug messages to the listener. - * The default listener redirects the messages to \a stderr when NDEBUG is - * not defined. - * - * \warning Do not use this outside of TagLib, it could lead to undefined - * symbols in your build if TagLib is built with NDEBUG defined and your - * application is not. - * - * \internal - */ - void debug(const String &s); - - /*! - * For debugging binary data. - * - * \warning Do not use this outside of TagLib, it could lead to undefined - * symbols in your build if TagLib is built with NDEBUG defined and your - * application is not. - * - * \internal - */ - void debugData(const ByteVector &v); -} - -#endif -#endif diff --git a/taglib/taglib/toolkit/tdebuglistener.cpp b/taglib/taglib/toolkit/tdebuglistener.cpp deleted file mode 100644 index 4891222..0000000 --- a/taglib/taglib/toolkit/tdebuglistener.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/*************************************************************************** - copyright : (C) 2013 by Tsuda Kageyu - email : tsuda.kageyu@gmail.com - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include "tdebuglistener.h" - -#include <iostream> -#include <bitset> - -#ifdef _WIN32 -# include <windows.h> -#endif - -using namespace TagLib; - -namespace -{ - class DefaultListener : public DebugListener - { - public: - virtual void printMessage(const String &msg) - { -#ifdef _WIN32 - - const wstring wstr = msg.toWString(); - const int len = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, NULL, 0, NULL, NULL); - if(len != 0) { - std::vector<char> buf(len); - WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, &buf[0], len, NULL, NULL); - - std::cerr << std::string(&buf[0]); - } - -#else - - std::cerr << msg; - -#endif - } - }; - - DefaultListener defaultListener; -} - -namespace TagLib -{ - DebugListener *debugListener = &defaultListener; - - DebugListener::DebugListener() - { - } - - DebugListener::~DebugListener() - { - } - - void setDebugListener(DebugListener *listener) - { - if(listener) - debugListener = listener; - else - debugListener = &defaultListener; - } -} diff --git a/taglib/taglib/toolkit/tdebuglistener.h b/taglib/taglib/toolkit/tdebuglistener.h deleted file mode 100644 index a32f285..0000000 --- a/taglib/taglib/toolkit/tdebuglistener.h +++ /dev/null @@ -1,74 +0,0 @@ -/*************************************************************************** - copyright : (C) 2013 by Tsuda Kageyu - email : tsuda.kageyu@gmail.com - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_DEBUGLISTENER_H -#define TAGLIB_DEBUGLISTENER_H - -#include "taglib_export.h" -#include "tstring.h" - -namespace TagLib -{ - //! An abstraction for the listener to the debug messages. - - /*! - * This class enables you to handle the debug messages in your preferred - * way by subclassing this class, reimplementing printMessage() and setting - * your reimplementation as the default with setDebugListener(). - * - * \see setDebugListener() - */ - class TAGLIB_EXPORT DebugListener - { - public: - DebugListener(); - virtual ~DebugListener(); - - /*! - * When overridden in a derived class, redirects \a msg to your preferred - * channel such as stderr, Windows debugger or so forth. - */ - virtual void printMessage(const String &msg) = 0; - - private: - // Noncopyable - DebugListener(const DebugListener &); - DebugListener &operator=(const DebugListener &); - }; - - /*! - * Sets the listener that decides how the debug messages are redirected. - * If the parameter \a listener is null, the previous listener is released - * and default stderr listener is restored. - * - * \note The caller is responsible for deleting the previous listener - * as needed after it is released. - * - * \see DebugListener - */ - TAGLIB_EXPORT void setDebugListener(DebugListener *listener); -} - -#endif diff --git a/taglib/taglib/toolkit/tfile.cpp b/taglib/taglib/toolkit/tfile.cpp deleted file mode 100644 index 4a05b05..0000000 --- a/taglib/taglib/toolkit/tfile.cpp +++ /dev/null @@ -1,503 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include "tfile.h" -#include "tfilestream.h" -#include "tstring.h" -#include "tdebug.h" -#include "tpropertymap.h" - -#ifdef _WIN32 -# include <windows.h> -# include <io.h> -#else -# include <stdio.h> -# include <unistd.h> -#endif - -#ifndef R_OK -# define R_OK 4 -#endif -#ifndef W_OK -# define W_OK 2 -#endif - -#include "asffile.h" -#include "mpegfile.h" -#include "vorbisfile.h" -#include "flacfile.h" -#include "oggflacfile.h" -#include "mpcfile.h" -#include "mp4file.h" -#include "wavpackfile.h" -#include "speexfile.h" -#include "opusfile.h" -#include "trueaudiofile.h" -#include "aifffile.h" -#include "wavfile.h" -#include "apefile.h" -#include "modfile.h" -#include "s3mfile.h" -#include "itfile.h" -#include "xmfile.h" -#include "mp4file.h" - -using namespace TagLib; - -namespace -{ -#ifdef _WIN32 - const TagLib::uint BufferSize = 8192; -#else - const TagLib::uint BufferSize = 1024; -#endif -} - -class File::FilePrivate -{ -public: - FilePrivate(IOStream *stream, bool owner); - - IOStream *stream; - bool streamOwner; - bool valid; -}; - -File::FilePrivate::FilePrivate(IOStream *stream, bool owner) : - stream(stream), - streamOwner(owner), - valid(true) -{ -} - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -File::File(FileName fileName) -{ - IOStream *stream = new FileStream(fileName); - d = new FilePrivate(stream, true); -} - -File::File(IOStream *stream) -{ - d = new FilePrivate(stream, false); -} - -File::~File() -{ - if(d->stream && d->streamOwner) - delete d->stream; - delete d; -} - -FileName File::name() const -{ - return d->stream->name(); -} - -PropertyMap File::properties() const -{ - // ugly workaround until this method is virtual - if(dynamic_cast<const APE::File* >(this)) - return dynamic_cast<const APE::File* >(this)->properties(); - if(dynamic_cast<const FLAC::File* >(this)) - return dynamic_cast<const FLAC::File* >(this)->properties(); - if(dynamic_cast<const IT::File* >(this)) - return dynamic_cast<const IT::File* >(this)->properties(); - if(dynamic_cast<const Mod::File* >(this)) - return dynamic_cast<const Mod::File* >(this)->properties(); - if(dynamic_cast<const MPC::File* >(this)) - return dynamic_cast<const MPC::File* >(this)->properties(); - if(dynamic_cast<const MPEG::File* >(this)) - return dynamic_cast<const MPEG::File* >(this)->properties(); - if(dynamic_cast<const Ogg::FLAC::File* >(this)) - return dynamic_cast<const Ogg::FLAC::File* >(this)->properties(); - if(dynamic_cast<const Ogg::Speex::File* >(this)) - return dynamic_cast<const Ogg::Speex::File* >(this)->properties(); - if(dynamic_cast<const Ogg::Opus::File* >(this)) - return dynamic_cast<const Ogg::Opus::File* >(this)->properties(); - if(dynamic_cast<const Ogg::Vorbis::File* >(this)) - return dynamic_cast<const Ogg::Vorbis::File* >(this)->properties(); - if(dynamic_cast<const RIFF::AIFF::File* >(this)) - return dynamic_cast<const RIFF::AIFF::File* >(this)->properties(); - if(dynamic_cast<const RIFF::WAV::File* >(this)) - return dynamic_cast<const RIFF::WAV::File* >(this)->properties(); - if(dynamic_cast<const S3M::File* >(this)) - return dynamic_cast<const S3M::File* >(this)->properties(); - if(dynamic_cast<const TrueAudio::File* >(this)) - return dynamic_cast<const TrueAudio::File* >(this)->properties(); - if(dynamic_cast<const WavPack::File* >(this)) - return dynamic_cast<const WavPack::File* >(this)->properties(); - if(dynamic_cast<const XM::File* >(this)) - return dynamic_cast<const XM::File* >(this)->properties(); - if(dynamic_cast<const MP4::File* >(this)) - return dynamic_cast<const MP4::File* >(this)->properties(); - if(dynamic_cast<const ASF::File* >(this)) - return dynamic_cast<const ASF::File* >(this)->properties(); - return tag()->properties(); -} - -void File::removeUnsupportedProperties(const StringList &properties) -{ - // here we only consider those formats that could possibly contain - // unsupported properties - if(dynamic_cast<APE::File* >(this)) - dynamic_cast<APE::File* >(this)->removeUnsupportedProperties(properties); - else if(dynamic_cast<FLAC::File* >(this)) - dynamic_cast<FLAC::File* >(this)->removeUnsupportedProperties(properties); - else if(dynamic_cast<MPC::File* >(this)) - dynamic_cast<MPC::File* >(this)->removeUnsupportedProperties(properties); - else if(dynamic_cast<MPEG::File* >(this)) - dynamic_cast<MPEG::File* >(this)->removeUnsupportedProperties(properties); - else if(dynamic_cast<Ogg::Vorbis::File* >(this)) - dynamic_cast<Ogg::Vorbis::File* >(this)->removeUnsupportedProperties(properties); - else if(dynamic_cast<RIFF::AIFF::File* >(this)) - dynamic_cast<RIFF::AIFF::File* >(this)->removeUnsupportedProperties(properties); - else if(dynamic_cast<RIFF::WAV::File* >(this)) - dynamic_cast<RIFF::WAV::File* >(this)->removeUnsupportedProperties(properties); - else if(dynamic_cast<TrueAudio::File* >(this)) - dynamic_cast<TrueAudio::File* >(this)->removeUnsupportedProperties(properties); - else if(dynamic_cast<WavPack::File* >(this)) - dynamic_cast<WavPack::File* >(this)->removeUnsupportedProperties(properties); - else if(dynamic_cast<MP4::File* >(this)) - dynamic_cast<MP4::File* >(this)->removeUnsupportedProperties(properties); - else if(dynamic_cast<ASF::File* >(this)) - dynamic_cast<ASF::File* >(this)->removeUnsupportedProperties(properties); - else - tag()->removeUnsupportedProperties(properties); -} - -PropertyMap File::setProperties(const PropertyMap &properties) -{ - if(dynamic_cast<APE::File* >(this)) - return dynamic_cast<APE::File* >(this)->setProperties(properties); - else if(dynamic_cast<FLAC::File* >(this)) - return dynamic_cast<FLAC::File* >(this)->setProperties(properties); - else if(dynamic_cast<IT::File* >(this)) - return dynamic_cast<IT::File* >(this)->setProperties(properties); - else if(dynamic_cast<Mod::File* >(this)) - return dynamic_cast<Mod::File* >(this)->setProperties(properties); - else if(dynamic_cast<MPC::File* >(this)) - return dynamic_cast<MPC::File* >(this)->setProperties(properties); - else if(dynamic_cast<MPEG::File* >(this)) - return dynamic_cast<MPEG::File* >(this)->setProperties(properties); - else if(dynamic_cast<Ogg::FLAC::File* >(this)) - return dynamic_cast<Ogg::FLAC::File* >(this)->setProperties(properties); - else if(dynamic_cast<Ogg::Speex::File* >(this)) - return dynamic_cast<Ogg::Speex::File* >(this)->setProperties(properties); - else if(dynamic_cast<Ogg::Opus::File* >(this)) - return dynamic_cast<Ogg::Opus::File* >(this)->setProperties(properties); - else if(dynamic_cast<Ogg::Vorbis::File* >(this)) - return dynamic_cast<Ogg::Vorbis::File* >(this)->setProperties(properties); - else if(dynamic_cast<RIFF::AIFF::File* >(this)) - return dynamic_cast<RIFF::AIFF::File* >(this)->setProperties(properties); - else if(dynamic_cast<RIFF::WAV::File* >(this)) - return dynamic_cast<RIFF::WAV::File* >(this)->setProperties(properties); - else if(dynamic_cast<S3M::File* >(this)) - return dynamic_cast<S3M::File* >(this)->setProperties(properties); - else if(dynamic_cast<TrueAudio::File* >(this)) - return dynamic_cast<TrueAudio::File* >(this)->setProperties(properties); - else if(dynamic_cast<WavPack::File* >(this)) - return dynamic_cast<WavPack::File* >(this)->setProperties(properties); - else if(dynamic_cast<XM::File* >(this)) - return dynamic_cast<XM::File* >(this)->setProperties(properties); - else if(dynamic_cast<MP4::File* >(this)) - return dynamic_cast<MP4::File* >(this)->setProperties(properties); - else if(dynamic_cast<ASF::File* >(this)) - return dynamic_cast<ASF::File* >(this)->setProperties(properties); - else - return tag()->setProperties(properties); -} - -ByteVector File::readBlock(ulong length) -{ - return d->stream->readBlock(length); -} - -void File::writeBlock(const ByteVector &data) -{ - d->stream->writeBlock(data); -} - -long File::find(const ByteVector &pattern, long fromOffset, const ByteVector &before) -{ - if(!d->stream || pattern.size() > bufferSize()) - return -1; - - // The position in the file that the current buffer starts at. - - long bufferOffset = fromOffset; - ByteVector buffer; - - // These variables are used to keep track of a partial match that happens at - // the end of a buffer. - - int previousPartialMatch = -1; - int beforePreviousPartialMatch = -1; - - // Save the location of the current read pointer. We will restore the - // position using seek() before all returns. - - long originalPosition = tell(); - - // Start the search at the offset. - - seek(fromOffset); - - // This loop is the crux of the find method. There are three cases that we - // want to account for: - // - // (1) The previously searched buffer contained a partial match of the search - // pattern and we want to see if the next one starts with the remainder of - // that pattern. - // - // (2) The search pattern is wholly contained within the current buffer. - // - // (3) The current buffer ends with a partial match of the pattern. We will - // note this for use in the next itteration, where we will check for the rest - // of the pattern. - // - // All three of these are done in two steps. First we check for the pattern - // and do things appropriately if a match (or partial match) is found. We - // then check for "before". The order is important because it gives priority - // to "real" matches. - - for(buffer = readBlock(bufferSize()); buffer.size() > 0; buffer = readBlock(bufferSize())) { - - // (1) previous partial match - - if(previousPartialMatch >= 0 && int(bufferSize()) > previousPartialMatch) { - const int patternOffset = (bufferSize() - previousPartialMatch); - if(buffer.containsAt(pattern, 0, patternOffset)) { - seek(originalPosition); - return bufferOffset - bufferSize() + previousPartialMatch; - } - } - - if(!before.isNull() && beforePreviousPartialMatch >= 0 && int(bufferSize()) > beforePreviousPartialMatch) { - const int beforeOffset = (bufferSize() - beforePreviousPartialMatch); - if(buffer.containsAt(before, 0, beforeOffset)) { - seek(originalPosition); - return -1; - } - } - - // (2) pattern contained in current buffer - - long location = buffer.find(pattern); - if(location >= 0) { - seek(originalPosition); - return bufferOffset + location; - } - - if(!before.isNull() && buffer.find(before) >= 0) { - seek(originalPosition); - return -1; - } - - // (3) partial match - - previousPartialMatch = buffer.endsWithPartialMatch(pattern); - - if(!before.isNull()) - beforePreviousPartialMatch = buffer.endsWithPartialMatch(before); - - bufferOffset += bufferSize(); - } - - // Since we hit the end of the file, reset the status before continuing. - - clear(); - - seek(originalPosition); - - return -1; -} - - -long File::rfind(const ByteVector &pattern, long fromOffset, const ByteVector &before) -{ - if(!d->stream || pattern.size() > bufferSize()) - return -1; - - // The position in the file that the current buffer starts at. - - ByteVector buffer; - - // These variables are used to keep track of a partial match that happens at - // the end of a buffer. - - /* - int previousPartialMatch = -1; - int beforePreviousPartialMatch = -1; - */ - - // Save the location of the current read pointer. We will restore the - // position using seek() before all returns. - - long originalPosition = tell(); - - // Start the search at the offset. - - long bufferOffset; - if(fromOffset == 0) { - seek(-1 * int(bufferSize()), End); - bufferOffset = tell(); - } - else { - seek(fromOffset + -1 * int(bufferSize()), Beginning); - bufferOffset = tell(); - } - - // See the notes in find() for an explanation of this algorithm. - - for(buffer = readBlock(bufferSize()); buffer.size() > 0; buffer = readBlock(bufferSize())) { - - // TODO: (1) previous partial match - - // (2) pattern contained in current buffer - - long location = buffer.rfind(pattern); - if(location >= 0) { - seek(originalPosition); - return bufferOffset + location; - } - - if(!before.isNull() && buffer.find(before) >= 0) { - seek(originalPosition); - return -1; - } - - // TODO: (3) partial match - - bufferOffset -= bufferSize(); - seek(bufferOffset); - } - - // Since we hit the end of the file, reset the status before continuing. - - clear(); - - seek(originalPosition); - - return -1; -} - -void File::insert(const ByteVector &data, ulong start, ulong replace) -{ - d->stream->insert(data, start, replace); -} - -void File::removeBlock(ulong start, ulong length) -{ - d->stream->removeBlock(start, length); -} - -bool File::readOnly() const -{ - return d->stream->readOnly(); -} - -bool File::isOpen() const -{ - return d->stream->isOpen(); -} - -bool File::isValid() const -{ - return isOpen() && d->valid; -} - -void File::seek(long offset, Position p) -{ - d->stream->seek(offset, IOStream::Position(p)); -} - -void File::truncate(long length) -{ - d->stream->truncate(length); -} - -void File::clear() -{ - d->stream->clear(); -} - -long File::tell() const -{ - return d->stream->tell(); -} - -long File::length() -{ - return d->stream->length(); -} - -bool File::isReadable(const char *file) -{ - -#if defined(_MSC_VER) && (_MSC_VER >= 1400) // VC++2005 or later - - return _access_s(file, R_OK) == 0; - -#else - - return access(file, R_OK) == 0; - -#endif - -} - -bool File::isWritable(const char *file) -{ - -#if defined(_MSC_VER) && (_MSC_VER >= 1400) // VC++2005 or later - - return _access_s(file, W_OK) == 0; - -#else - - return access(file, W_OK) == 0; - -#endif - -} - -//////////////////////////////////////////////////////////////////////////////// -// protected members -//////////////////////////////////////////////////////////////////////////////// - -TagLib::uint File::bufferSize() -{ - return BufferSize; -} - -void File::setValid(bool valid) -{ - d->valid = valid; -} - diff --git a/taglib/taglib/toolkit/tfile.h b/taglib/taglib/toolkit/tfile.h deleted file mode 100644 index 67f6f80..0000000 --- a/taglib/taglib/toolkit/tfile.h +++ /dev/null @@ -1,306 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_FILE_H -#define TAGLIB_FILE_H - -#include "taglib_export.h" -#include "taglib.h" -#include "tag.h" -#include "tbytevector.h" -#include "tiostream.h" - -namespace TagLib { - - class String; - class Tag; - class AudioProperties; - class PropertyMap; - - //! A file class with some useful methods for tag manipulation - - /*! - * This class is a basic file class with some methods that are particularly - * useful for tag editors. It has methods to take advantage of - * ByteVector and a binary search method for finding patterns in a file. - */ - - class TAGLIB_EXPORT File - { - public: - /*! - * Position in the file used for seeking. - */ - enum Position { - //! Seek from the beginning of the file. - Beginning, - //! Seek from the current position in the file. - Current, - //! Seek from the end of the file. - End - }; - - /*! - * Destroys this File instance. - */ - virtual ~File(); - - /*! - * Returns the file name in the local file system encoding. - */ - FileName name() const; - - /*! - * Returns a pointer to this file's tag. This should be reimplemented in - * the concrete subclasses. - */ - virtual Tag *tag() const = 0; - - /*! - * Exports the tags of the file as dictionary mapping (human readable) tag - * names (uppercase Strings) to StringLists of tag values. Calls the according - * specialization in the File subclasses. - * For each metadata object of the file that could not be parsed into the PropertyMap - * format, the returend map's unsupportedData() list will contain one entry identifying - * that object (e.g. the frame type for ID3v2 tags). Use removeUnsupportedProperties() - * to remove (a subset of) them. - * For files that contain more than one tag (e.g. an MP3 with both an ID3v2 and an ID3v2 - * tag) only the most "modern" one will be exported (ID3v2 in this case). - * BIC: Will be made virtual in future releases. - */ - PropertyMap properties() const; - - /*! - * Removes unsupported properties, or a subset of them, from the file's metadata. - * The parameter \a properties must contain only entries from - * properties().unsupportedData(). - * BIC: Will be mad virtual in future releases. - */ - void removeUnsupportedProperties(const StringList& properties); - - /*! - * Sets the tags of this File to those specified in \a properties. Calls the - * according specialization method in the subclasses of File to do the translation - * into the format-specific details. - * If some value(s) could not be written imported to the specific metadata format, - * the returned PropertyMap will contain those value(s). Otherwise it will be empty, - * indicating that no problems occured. - * With file types that support several tag formats (for instance, MP3 files can have - * ID3v1, ID3v2, and APEv2 tags), this function will create the most appropriate one - * (ID3v2 for MP3 files). Older formats will be updated as well, if they exist, but won't - * be taken into account for the return value of this function. - * See the documentation of the subclass implementations for detailed descriptions. - * BIC: will become pure virtual in the future - */ - PropertyMap setProperties(const PropertyMap &properties); - - /*! - * Returns a pointer to this file's audio properties. This should be - * reimplemented in the concrete subclasses. If no audio properties were - * read then this will return a null pointer. - */ - virtual AudioProperties *audioProperties() const = 0; - - /*! - * Save the file and its associated tags. This should be reimplemented in - * the concrete subclasses. Returns true if the save succeeds. - * - * \warning On UNIX multiple processes are able to write to the same file at - * the same time. This can result in serious file corruption. If you are - * developing a program that makes use of TagLib from multiple processes you - * must insure that you are only doing writes to a particular file from one - * of them. - */ - virtual bool save() = 0; - - /*! - * Reads a block of size \a length at the current get pointer. - */ - ByteVector readBlock(ulong length); - - /*! - * Attempts to write the block \a data at the current get pointer. If the - * file is currently only opened read only -- i.e. readOnly() returns true -- - * this attempts to reopen the file in read/write mode. - * - * \note This should be used instead of using the streaming output operator - * for a ByteVector. And even this function is significantly slower than - * doing output with a char[]. - */ - void writeBlock(const ByteVector &data); - - /*! - * Returns the offset in the file that \a pattern occurs at or -1 if it can - * not be found. If \a before is set, the search will only continue until the - * pattern \a before is found. This is useful for tagging purposes to search - * for a tag before the synch frame. - * - * Searching starts at \a fromOffset, which defaults to the beginning of the - * file. - * - * \note This has the practial limitation that \a pattern can not be longer - * than the buffer size used by readBlock(). Currently this is 1024 bytes. - */ - long find(const ByteVector &pattern, - long fromOffset = 0, - const ByteVector &before = ByteVector::null); - - /*! - * Returns the offset in the file that \a pattern occurs at or -1 if it can - * not be found. If \a before is set, the search will only continue until the - * pattern \a before is found. This is useful for tagging purposes to search - * for a tag before the synch frame. - * - * Searching starts at \a fromOffset and proceeds from the that point to the - * beginning of the file and defaults to the end of the file. - * - * \note This has the practial limitation that \a pattern can not be longer - * than the buffer size used by readBlock(). Currently this is 1024 bytes. - */ - long rfind(const ByteVector &pattern, - long fromOffset = 0, - const ByteVector &before = ByteVector::null); - - /*! - * Insert \a data at position \a start in the file overwriting \a replace - * bytes of the original content. - * - * \note This method is slow since it requires rewriting all of the file - * after the insertion point. - */ - void insert(const ByteVector &data, ulong start = 0, ulong replace = 0); - - /*! - * Removes a block of the file starting a \a start and continuing for - * \a length bytes. - * - * \note This method is slow since it involves rewriting all of the file - * after the removed portion. - */ - void removeBlock(ulong start = 0, ulong length = 0); - - /*! - * Returns true if the file is read only (or if the file can not be opened). - */ - bool readOnly() const; - - /*! - * Since the file can currently only be opened as an argument to the - * constructor (sort-of by design), this returns if that open succeeded. - */ - bool isOpen() const; - - /*! - * Returns true if the file is open and readable. - */ - bool isValid() const; - - /*! - * Move the I/O pointer to \a offset in the file from position \a p. This - * defaults to seeking from the beginning of the file. - * - * \see Position - */ - void seek(long offset, Position p = Beginning); - - /*! - * Reset the end-of-file and error flags on the file. - */ - void clear(); - - /*! - * Returns the current offset within the file. - */ - long tell() const; - - /*! - * Returns the length of the file. - */ - long length(); - - /*! - * Returns true if \a file can be opened for reading. If the file does not - * exist, this will return false. - * - * \deprecated - */ - static bool isReadable(const char *file); - - /*! - * Returns true if \a file can be opened for writing. - * - * \deprecated - */ - static bool isWritable(const char *name); - - protected: - /*! - * Construct a File object and opens the \a file. \a file should be a - * be a C-string in the local file system encoding. - * - * \note Constructor is protected since this class should only be - * instantiated through subclasses. - */ - File(FileName file); - - /*! - * Construct a File object and use the \a stream instance. - * - * \note TagLib will *not* take ownership of the stream, the caller is - * responsible for deleting it after the File object. - * - * \note Constructor is protected since this class should only be - * instantiated through subclasses. - */ - File(IOStream *stream); - - /*! - * Marks the file as valid or invalid. - * - * \see isValid() - */ - void setValid(bool valid); - - /*! - * Truncates the file to a \a length. - */ - void truncate(long length); - - /*! - * Returns the buffer size that is used for internal buffering. - */ - static uint bufferSize(); - - private: - File(const File &); - File &operator=(const File &); - - class FilePrivate; - FilePrivate *d; - }; - -} - -#endif diff --git a/taglib/taglib/toolkit/tfilestream.cpp b/taglib/taglib/toolkit/tfilestream.cpp deleted file mode 100644 index eae5257..0000000 --- a/taglib/taglib/toolkit/tfilestream.cpp +++ /dev/null @@ -1,492 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include "tfilestream.h" -#include "tstring.h" -#include "tdebug.h" - -#ifdef _WIN32 -# include <windows.h> -#else -# include <stdio.h> -# include <unistd.h> -#endif - -using namespace TagLib; - -namespace -{ -#ifdef _WIN32 - - // Uses Win32 native API instead of POSIX API to reduce the resource consumption. - - typedef FileName FileNameHandle; - typedef HANDLE FileHandle; - - const TagLib::uint BufferSize = 8192; - const FileHandle InvalidFileHandle = INVALID_HANDLE_VALUE; - - inline FileHandle openFile(const FileName &path, bool readOnly) - { - const DWORD access = readOnly ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE); - - if(!path.wstr().empty()) - return CreateFileW(path.wstr().c_str(), access, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); - else if(!path.str().empty()) - return CreateFileA(path.str().c_str(), access, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); - else - return InvalidFileHandle; - } - - inline void closeFile(FileHandle file) - { - CloseHandle(file); - } - - inline size_t readFile(FileHandle file, ByteVector &buffer) - { - DWORD length; - if(ReadFile(file, buffer.data(), static_cast<DWORD>(buffer.size()), &length, NULL)) - return static_cast<size_t>(length); - else - return 0; - } - - inline size_t writeFile(FileHandle file, const ByteVector &buffer) - { - DWORD length; - if(WriteFile(file, buffer.data(), static_cast<DWORD>(buffer.size()), &length, NULL)) - return static_cast<size_t>(length); - else - return 0; - } - -#else // _WIN32 - - struct FileNameHandle : public std::string - { - FileNameHandle(FileName name) : std::string(name) {} - operator FileName () const { return c_str(); } - }; - - typedef FILE* FileHandle; - - const TagLib::uint BufferSize = 8192; - const FileHandle InvalidFileHandle = 0; - - inline FileHandle openFile(const FileName &path, bool readOnly) - { - return fopen(path, readOnly ? "rb" : "rb+"); - } - - inline void closeFile(FileHandle file) - { - fclose(file); - } - - inline size_t readFile(FileHandle file, ByteVector &buffer) - { - return fread(buffer.data(), sizeof(char), buffer.size(), file); - } - - inline size_t writeFile(FileHandle file, const ByteVector &buffer) - { - return fwrite(buffer.data(), sizeof(char), buffer.size(), file); - } - -#endif // _WIN32 -} - -class FileStream::FileStreamPrivate -{ -public: - FileStreamPrivate(const FileName &fileName) - : file(InvalidFileHandle) - , name(fileName) - , readOnly(true) - { - } - - FileHandle file; - FileNameHandle name; - bool readOnly; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -FileStream::FileStream(FileName fileName, bool openReadOnly) - : d(new FileStreamPrivate(fileName)) -{ - // First try with read / write mode, if that fails, fall back to read only. - - if(!openReadOnly) - d->file = openFile(fileName, false); - - if(d->file != InvalidFileHandle) - d->readOnly = false; - else - d->file = openFile(fileName, true); - - if(d->file == InvalidFileHandle) - { -# ifdef _WIN32 - debug("Could not open file " + fileName.toString()); -# else - debug("Could not open file " + String(static_cast<const char *>(d->name))); -# endif - } -} - -FileStream::~FileStream() -{ - if(isOpen()) - closeFile(d->file); - - delete d; -} - -FileName FileStream::name() const -{ - return d->name; -} - -ByteVector FileStream::readBlock(ulong length) -{ - if(!isOpen()) { - debug("File::readBlock() -- invalid file."); - return ByteVector::null; - } - - if(length == 0) - return ByteVector::null; - - const ulong streamLength = static_cast<ulong>(FileStream::length()); - if(length > bufferSize() && length > streamLength) - length = streamLength; - - ByteVector buffer(static_cast<uint>(length)); - - const size_t count = readFile(d->file, buffer); - buffer.resize(static_cast<uint>(count)); - - return buffer; -} - -void FileStream::writeBlock(const ByteVector &data) -{ - if(!isOpen()) { - debug("File::writeBlock() -- invalid file."); - return; - } - - if(readOnly()) { - debug("File::writeBlock() -- read only file."); - return; - } - - writeFile(d->file, data); -} - -void FileStream::insert(const ByteVector &data, ulong start, ulong replace) -{ - if(!isOpen()) { - debug("File::insert() -- invalid file."); - return; - } - - if(readOnly()) { - debug("File::insert() -- read only file."); - return; - } - - if(data.size() == replace) { - seek(start); - writeBlock(data); - return; - } - else if(data.size() < replace) { - seek(start); - writeBlock(data); - removeBlock(start + data.size(), replace - data.size()); - return; - } - - // Woohoo! Faster (about 20%) than id3lib at last. I had to get hardcore - // and avoid TagLib's high level API for rendering just copying parts of - // the file that don't contain tag data. - // - // Now I'll explain the steps in this ugliness: - - // First, make sure that we're working with a buffer that is longer than - // the *differnce* in the tag sizes. We want to avoid overwriting parts - // that aren't yet in memory, so this is necessary. - - ulong bufferLength = bufferSize(); - - while(data.size() - replace > bufferLength) - bufferLength += bufferSize(); - - // Set where to start the reading and writing. - - long readPosition = start + replace; - long writePosition = start; - - ByteVector buffer = data; - ByteVector aboutToOverwrite(static_cast<uint>(bufferLength)); - - while(true) - { - // Seek to the current read position and read the data that we're about - // to overwrite. Appropriately increment the readPosition. - - seek(readPosition); - const size_t bytesRead = readFile(d->file, aboutToOverwrite); - aboutToOverwrite.resize(bytesRead); - readPosition += bufferLength; - - // Check to see if we just read the last block. We need to call clear() - // if we did so that the last write succeeds. - - if(bytesRead < bufferLength) - clear(); - - // Seek to the write position and write our buffer. Increment the - // writePosition. - - seek(writePosition); - writeBlock(buffer); - - // We hit the end of the file. - - if(bytesRead == 0) - break; - - writePosition += buffer.size(); - - // Make the current buffer the data that we read in the beginning. - - buffer = aboutToOverwrite; - } -} - -void FileStream::removeBlock(ulong start, ulong length) -{ - if(!isOpen()) { - debug("File::removeBlock() -- invalid file."); - return; - } - - ulong bufferLength = bufferSize(); - - long readPosition = start + length; - long writePosition = start; - - ByteVector buffer(static_cast<uint>(bufferLength)); - - for(size_t bytesRead = -1; bytesRead != 0;) - { - seek(readPosition); - bytesRead = readFile(d->file, buffer); - readPosition += bytesRead; - - // Check to see if we just read the last block. We need to call clear() - // if we did so that the last write succeeds. - - if(bytesRead < buffer.size()) { - clear(); - buffer.resize(bytesRead); - } - - seek(writePosition); - writeFile(d->file, buffer); - - writePosition += bytesRead; - } - - truncate(writePosition); -} - -bool FileStream::readOnly() const -{ - return d->readOnly; -} - -bool FileStream::isOpen() const -{ - return (d->file != InvalidFileHandle); -} - -void FileStream::seek(long offset, Position p) -{ - if(!isOpen()) { - debug("File::seek() -- invalid file."); - return; - } - -#ifdef _WIN32 - - DWORD whence; - switch(p) { - case Beginning: - whence = FILE_BEGIN; - break; - case Current: - whence = FILE_CURRENT; - break; - case End: - whence = FILE_END; - break; - default: - debug("FileStream::seek() -- Invalid Position value."); - return; - } - - SetFilePointer(d->file, offset, NULL, whence); - if(GetLastError() != NO_ERROR) { - debug("File::seek() -- Failed to set the file pointer."); - } - -#else - - int whence; - switch(p) { - case Beginning: - whence = SEEK_SET; - break; - case Current: - whence = SEEK_CUR; - break; - case End: - whence = SEEK_END; - break; - default: - debug("FileStream::seek() -- Invalid Position value."); - return; - } - - fseek(d->file, offset, whence); - -#endif -} - -void FileStream::clear() -{ -#ifdef _WIN32 - - // NOP - -#else - - clearerr(d->file); - -#endif -} - -long FileStream::tell() const -{ -#ifdef _WIN32 - - const DWORD position = SetFilePointer(d->file, 0, NULL, FILE_CURRENT); - if(GetLastError() == NO_ERROR) { - return static_cast<long>(position); - } - else { - debug("File::tell() -- Failed to get the file pointer."); - return 0; - } - -#else - - return ftell(d->file); - -#endif -} - -long FileStream::length() -{ - if(!isOpen()) { - debug("File::length() -- invalid file."); - return 0; - } - -#ifdef _WIN32 - - const DWORD fileSize = GetFileSize(d->file, NULL); - if(GetLastError() == NO_ERROR) { - return static_cast<ulong>(fileSize); - } - else { - debug("File::length() -- Failed to get the file size."); - return 0; - } - -#else - - const long curpos = tell(); - - seek(0, End); - const long endpos = tell(); - - seek(curpos, Beginning); - - return endpos; - -#endif -} - -//////////////////////////////////////////////////////////////////////////////// -// protected members -//////////////////////////////////////////////////////////////////////////////// - -void FileStream::truncate(long length) -{ -#ifdef _WIN32 - - const long currentPos = tell(); - - seek(length); - SetEndOfFile(d->file); - if(GetLastError() != NO_ERROR) { - debug("File::truncate() -- Failed to truncate the file."); - } - - seek(currentPos); - -#else - - const int error = ftruncate(fileno(d->file), length); - if(error != 0) { - debug("FileStream::truncate() -- Coundn't truncate the file."); - } - -#endif -} - -TagLib::uint FileStream::bufferSize() -{ - return BufferSize; -} diff --git a/taglib/taglib/toolkit/tfilestream.h b/taglib/taglib/toolkit/tfilestream.h deleted file mode 100644 index fa113b7..0000000 --- a/taglib/taglib/toolkit/tfilestream.h +++ /dev/null @@ -1,154 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_FILESTREAM_H -#define TAGLIB_FILESTREAM_H - -#include "taglib_export.h" -#include "taglib.h" -#include "tbytevector.h" -#include "tiostream.h" - -namespace TagLib { - - class String; - class Tag; - class AudioProperties; - - //! A file class with some useful methods for tag manipulation - - /*! - * This class is a basic file class with some methods that are particularly - * useful for tag editors. It has methods to take advantage of - * ByteVector and a binary search method for finding patterns in a file. - */ - - class TAGLIB_EXPORT FileStream : public IOStream - { - public: - /*! - * Construct a File object and opens the \a file. \a file should be a - * be a C-string in the local file system encoding. - */ - FileStream(FileName file, bool openReadOnly = false); - - /*! - * Destroys this FileStream instance. - */ - virtual ~FileStream(); - - /*! - * Returns the file name in the local file system encoding. - */ - FileName name() const; - - /*! - * Reads a block of size \a length at the current get pointer. - */ - ByteVector readBlock(ulong length); - - /*! - * Attempts to write the block \a data at the current get pointer. If the - * file is currently only opened read only -- i.e. readOnly() returns true -- - * this attempts to reopen the file in read/write mode. - * - * \note This should be used instead of using the streaming output operator - * for a ByteVector. And even this function is significantly slower than - * doing output with a char[]. - */ - void writeBlock(const ByteVector &data); - - /*! - * Insert \a data at position \a start in the file overwriting \a replace - * bytes of the original content. - * - * \note This method is slow since it requires rewriting all of the file - * after the insertion point. - */ - void insert(const ByteVector &data, ulong start = 0, ulong replace = 0); - - /*! - * Removes a block of the file starting a \a start and continuing for - * \a length bytes. - * - * \note This method is slow since it involves rewriting all of the file - * after the removed portion. - */ - void removeBlock(ulong start = 0, ulong length = 0); - - /*! - * Returns true if the file is read only (or if the file can not be opened). - */ - bool readOnly() const; - - /*! - * Since the file can currently only be opened as an argument to the - * constructor (sort-of by design), this returns if that open succeeded. - */ - bool isOpen() const; - - /*! - * Move the I/O pointer to \a offset in the file from position \a p. This - * defaults to seeking from the beginning of the file. - * - * \see Position - */ - void seek(long offset, Position p = Beginning); - - /*! - * Reset the end-of-file and error flags on the file. - */ - void clear(); - - /*! - * Returns the current offset within the file. - */ - long tell() const; - - /*! - * Returns the length of the file. - */ - long length(); - - /*! - * Truncates the file to a \a length. - */ - void truncate(long length); - - protected: - - /*! - * Returns the buffer size that is used for internal buffering. - */ - static uint bufferSize(); - - private: - class FileStreamPrivate; - FileStreamPrivate *d; - }; - -} - -#endif diff --git a/taglib/taglib/toolkit/tiostream.cpp b/taglib/taglib/toolkit/tiostream.cpp deleted file mode 100644 index c2ad291..0000000 --- a/taglib/taglib/toolkit/tiostream.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/*************************************************************************** - copyright : (C) 2011 by Lukas Lalinsky - email : lalinsky@gmail.com - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include "tiostream.h" - -using namespace TagLib; - -#ifdef _WIN32 - -# include "tstring.h" -# include "tdebug.h" -# include <windows.h> - -namespace -{ - // Check if the running system has CreateFileW() function. - // Windows9x systems don't have CreateFileW() or can't accept Unicode file names. - - bool supportsUnicode() - { - const FARPROC p = GetProcAddress(GetModuleHandleA("kernel32"), "CreateFileW"); - return (p != NULL); - } - - // Indicates whether the system supports Unicode file names. - - const bool SystemSupportsUnicode = supportsUnicode(); - - // Converts a UTF-16 string into a local encoding. - // This function should only be used in Windows9x systems which don't support - // Unicode file names. - - std::string unicodeToAnsi(const wchar_t *wstr) - { - if(SystemSupportsUnicode) { - debug("unicodeToAnsi() - Should not be used on WinNT systems."); - } - - const int len = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL); - if(len == 0) - return std::string(); - - std::string str(len, '\0'); - WideCharToMultiByte(CP_ACP, 0, wstr, -1, &str[0], len, NULL, NULL); - - return str; - } -} - -// If WinNT, stores a Unicode string into m_wname directly. -// If Win9x, converts and stores it into m_name to avoid calling Unicode version functions. - -FileName::FileName(const wchar_t *name) - : m_name (SystemSupportsUnicode ? "" : unicodeToAnsi(name)) - , m_wname(SystemSupportsUnicode ? name : L"") -{ -} - -FileName::FileName(const char *name) - : m_name(name) -{ -} - -FileName::FileName(const FileName &name) - : m_name (name.m_name) - , m_wname(name.m_wname) -{ -} - -FileName::operator const wchar_t *() const -{ - return m_wname.c_str(); -} - -FileName::operator const char *() const -{ - return m_name.c_str(); -} - -const std::wstring &FileName::wstr() const -{ - return m_wname; -} - -const std::string &FileName::str() const -{ - return m_name; -} - -String FileName::toString() const -{ - if(!m_wname.empty()) { - return String(m_wname); - } - else if(!m_name.empty()) { - const int len = MultiByteToWideChar(CP_ACP, 0, m_name.c_str(), -1, NULL, 0); - if(len == 0) - return String::null; - - std::vector<wchar_t> buf(len); - MultiByteToWideChar(CP_ACP, 0, m_name.c_str(), -1, &buf[0], len); - - return String(&buf[0]); - } - else { - return String::null; - } -} - - -#endif // _WIN32 - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -IOStream::IOStream() -{ -} - -IOStream::~IOStream() -{ -} - -void IOStream::clear() -{ -} - diff --git a/taglib/taglib/toolkit/tiostream.h b/taglib/taglib/toolkit/tiostream.h deleted file mode 100644 index 8682696..0000000 --- a/taglib/taglib/toolkit/tiostream.h +++ /dev/null @@ -1,169 +0,0 @@ -/*************************************************************************** - copyright : (C) 2011 by Lukas Lalinsky - email : lalinsky@gmail.com - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_IOSTREAM_H -#define TAGLIB_IOSTREAM_H - -#include "taglib_export.h" -#include "taglib.h" -#include "tbytevector.h" - -namespace TagLib { - -#ifdef _WIN32 - class TAGLIB_EXPORT FileName - { - public: - FileName(const wchar_t *name); - FileName(const char *name); - - FileName(const FileName &name); - - operator const wchar_t *() const; - operator const char *() const; - - const std::wstring &wstr() const; - const std::string &str() const; - - String toString() const; - - private: - const std::string m_name; - const std::wstring m_wname; - }; -#else - typedef const char *FileName; -#endif - - //! An abstract class that provides operations on a sequence of bytes - - class TAGLIB_EXPORT IOStream - { - public: - /*! - * Position in the file used for seeking. - */ - enum Position { - //! Seek from the beginning of the file. - Beginning, - //! Seek from the current position in the file. - Current, - //! Seek from the end of the file. - End - }; - - IOStream(); - - /*! - * Destroys this IOStream instance. - */ - virtual ~IOStream(); - - /*! - * Returns the stream name in the local file system encoding. - */ - virtual FileName name() const = 0; - - /*! - * Reads a block of size \a length at the current get pointer. - */ - virtual ByteVector readBlock(ulong length) = 0; - - /*! - * Attempts to write the block \a data at the current get pointer. If the - * file is currently only opened read only -- i.e. readOnly() returns true -- - * this attempts to reopen the file in read/write mode. - * - * \note This should be used instead of using the streaming output operator - * for a ByteVector. And even this function is significantly slower than - * doing output with a char[]. - */ - virtual void writeBlock(const ByteVector &data) = 0; - - /*! - * Insert \a data at position \a start in the file overwriting \a replace - * bytes of the original content. - * - * \note This method is slow since it requires rewriting all of the file - * after the insertion point. - */ - virtual void insert(const ByteVector &data, ulong start = 0, ulong replace = 0) = 0; - - /*! - * Removes a block of the file starting a \a start and continuing for - * \a length bytes. - * - * \note This method is slow since it involves rewriting all of the file - * after the removed portion. - */ - virtual void removeBlock(ulong start = 0, ulong length = 0) = 0; - - /*! - * Returns true if the file is read only (or if the file can not be opened). - */ - virtual bool readOnly() const = 0; - - /*! - * Since the file can currently only be opened as an argument to the - * constructor (sort-of by design), this returns if that open succeeded. - */ - virtual bool isOpen() const = 0; - - /*! - * Move the I/O pointer to \a offset in the stream from position \a p. This - * defaults to seeking from the beginning of the stream. - * - * \see Position - */ - virtual void seek(long offset, Position p = Beginning) = 0; - - /*! - * Reset the end-of-stream and error flags on the stream. - */ - virtual void clear(); - - /*! - * Returns the current offset within the stream. - */ - virtual long tell() const = 0; - - /*! - * Returns the length of the stream. - */ - virtual long length() = 0; - - /*! - * Truncates the stream to a \a length. - */ - virtual void truncate(long length) = 0; - - private: - IOStream(const IOStream &); - IOStream &operator=(const IOStream &); - }; - -} - -#endif diff --git a/taglib/taglib/toolkit/tlist.h b/taglib/taglib/toolkit/tlist.h deleted file mode 100644 index 0099dad..0000000 --- a/taglib/taglib/toolkit/tlist.h +++ /dev/null @@ -1,257 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_LIST_H -#define TAGLIB_LIST_H - -#include "taglib.h" - -#include <list> - -namespace TagLib { - - //! A generic, implicitly shared list. - - /*! - * This is basic generic list that's somewhere between a std::list and a - * QValueList. This class is implicitly shared. For example: - * - * \code - * - * TagLib::List<int> l = someOtherIntList; - * - * \endcode - * - * The above example is very cheap. This also makes lists suitable for the - * return types of functions. The above example will just copy a pointer rather - * than copying the data in the list. When your \e shared list's data changes, - * only \e then will the data be copied. - */ - - template <class T> class List - { - public: -#ifndef DO_NOT_DOCUMENT - typedef typename std::list<T>::iterator Iterator; - typedef typename std::list<T>::const_iterator ConstIterator; -#endif - - /*! - * Constructs an empty list. - */ - List(); - - /*! - * Make a shallow, implicitly shared, copy of \a l. Because this is - * implicitly shared, this method is lightweight and suitable for - * pass-by-value usage. - */ - List(const List<T> &l); - - /*! - * Destroys this List instance. If auto deletion is enabled and this list - * contains a pointer type all of the memebers are also deleted. - */ - virtual ~List(); - - /*! - * Returns an STL style iterator to the beginning of the list. See - * std::list::const_iterator for the semantics. - */ - Iterator begin(); - - /*! - * Returns an STL style constant iterator to the beginning of the list. See - * std::list::iterator for the semantics. - */ - ConstIterator begin() const; - - /*! - * Returns an STL style iterator to the end of the list. See - * std::list::iterator for the semantics. - */ - Iterator end(); - - /*! - * Returns an STL style constant iterator to the end of the list. See - * std::list::const_iterator for the semantics. - */ - ConstIterator end() const; - - /*! - * Inserts a copy of \a value before \a it. - */ - Iterator insert(Iterator it, const T &value); - - /*! - * Inserts the \a value into the list. This assumes that the list is - * currently sorted. If \a unique is true then the value will not - * be inserted if it is already in the list. - */ - List<T> &sortedInsert(const T &value, bool unique = false); - - /*! - * Appends \a item to the end of the list and returns a reference to the - * list. - */ - List<T> &append(const T &item); - - /*! - * Appends all of the values in \a l to the end of the list and returns a - * reference to the list. - */ - List<T> &append(const List<T> &l); - - /*! - * Prepends \a item to the beginning list and returns a reference to the - * list. - */ - List<T> &prepend(const T &item); - - /*! - * Prepends all of the items in \a l to the beginning list and returns a - * reference to the list. - */ - List<T> &prepend(const List<T> &l); - - /*! - * Clears the list. If auto deletion is enabled and this list contains a - * pointer type the members are also deleted. - * - * \see setAutoDelete() - */ - List<T> &clear(); - - /*! - * Returns the number of elements in the list. - */ - uint size() const; - bool isEmpty() const; - - /*! - * Find the first occurrence of \a value. - */ - Iterator find(const T &value); - - /*! - * Find the first occurrence of \a value. - */ - ConstIterator find(const T &value) const; - - /*! - * Returns true if the list contains \a value. - */ - bool contains(const T &value) const; - - /*! - * Erase the item at \a it from the list. - */ - Iterator erase(Iterator it); - - /*! - * Returns a reference to the first item in the list. - */ - const T &front() const; - - /*! - * Returns a reference to the first item in the list. - */ - T &front(); - - /*! - * Returns a reference to the last item in the list. - */ - const T &back() const; - - /*! - * Returns a reference to the last item in the list. - */ - T &back(); - - /*! - * Auto delete the members of the list when the last reference to the list - * passes out of scope. This will have no effect on lists which do not - * contain a pointer type. - * - * \note This relies on partial template instantiation -- most modern C++ - * compilers should now support this. - */ - void setAutoDelete(bool autoDelete); - - /*! - * Returns a reference to item \a i in the list. - * - * \warning This method is slow. Use iterators to loop through the list. - */ - T &operator[](uint i); - - /*! - * Returns a const reference to item \a i in the list. - * - * \warning This method is slow. Use iterators to loop through the list. - */ - const T &operator[](uint i) const; - - /*! - * Make a shallow, implicitly shared, copy of \a l. Because this is - * implicitly shared, this method is lightweight and suitable for - * pass-by-value usage. - */ - List<T> &operator=(const List<T> &l); - - /*! - * Compares this list with \a l and returns true if all of the elements are - * the same. - */ - bool operator==(const List<T> &l) const; - - /*! - * Compares this list with \a l and returns true if the lists differ. - */ - bool operator!=(const List<T> &l) const; - - protected: - /* - * If this List is being shared via implicit sharing, do a deep copy of the - * data and separate from the shared members. This should be called by all - * non-const subclass members. - */ - void detach(); - - private: -#ifndef DO_NOT_DOCUMENT - template <class TP> class ListPrivate; - ListPrivate<T> *d; -#endif - }; - -} - -// Since GCC doesn't support the "export" keyword, we have to include the -// implementation. - -#include "tlist.tcc" - -#endif diff --git a/taglib/taglib/toolkit/tlist.tcc b/taglib/taglib/toolkit/tlist.tcc deleted file mode 100644 index 72d4767..0000000 --- a/taglib/taglib/toolkit/tlist.tcc +++ /dev/null @@ -1,324 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include <algorithm> -#include "trefcounter.h" - -namespace TagLib { - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -// The functionality of List<T>::setAutoDelete() is implemented here partial -// template specialization. This is implemented in such a way that calling -// setAutoDelete() on non-pointer types will simply have no effect. - -// A base for the generic and specialized private class types. New -// non-templatized members should be added here. - -// BIC change to RefCounter -class ListPrivateBase : public RefCounterOld -{ -public: - ListPrivateBase() : autoDelete(false) {} - bool autoDelete; -}; - -// A generic implementation - -template <class T> -template <class TP> class List<T>::ListPrivate : public ListPrivateBase -{ -public: - ListPrivate() : ListPrivateBase() {} - ListPrivate(const std::list<TP> &l) : ListPrivateBase(), list(l) {} - void clear() { - list.clear(); - } - std::list<TP> list; -}; - -// A partial specialization for all pointer types that implements the -// setAutoDelete() functionality. - -template <class T> -template <class TP> class List<T>::ListPrivate<TP *> : public ListPrivateBase -{ -public: - ListPrivate() : ListPrivateBase() {} - ListPrivate(const std::list<TP *> &l) : ListPrivateBase(), list(l) {} - ~ListPrivate() { - clear(); - } - void clear() { - if(autoDelete) { - typename std::list<TP *>::const_iterator it = list.begin(); - for(; it != list.end(); ++it) - delete *it; - } - list.clear(); - } - std::list<TP *> list; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -template <class T> -List<T>::List() -{ - d = new ListPrivate<T>; -} - -template <class T> -List<T>::List(const List<T> &l) : d(l.d) -{ - d->ref(); -} - -template <class T> -List<T>::~List() -{ - if(d->deref()) - delete d; -} - -template <class T> -typename List<T>::Iterator List<T>::begin() -{ - detach(); - return d->list.begin(); -} - -template <class T> -typename List<T>::ConstIterator List<T>::begin() const -{ - return d->list.begin(); -} - -template <class T> -typename List<T>::Iterator List<T>::end() -{ - detach(); - return d->list.end(); -} - -template <class T> -typename List<T>::ConstIterator List<T>::end() const -{ - return d->list.end(); -} - -template <class T> -typename List<T>::Iterator List<T>::insert(Iterator it, const T &item) -{ - detach(); - return d->list.insert(it, item); -} - -template <class T> -List<T> &List<T>::sortedInsert(const T &value, bool unique) -{ - detach(); - Iterator it = begin(); - while(it != end() && *it < value) - ++it; - if(unique && it != end() && *it == value) - return *this; - insert(it, value); - return *this; -} - -template <class T> -List<T> &List<T>::append(const T &item) -{ - detach(); - d->list.push_back(item); - return *this; -} - -template <class T> -List<T> &List<T>::append(const List<T> &l) -{ - detach(); - d->list.insert(d->list.end(), l.begin(), l.end()); - return *this; -} - -template <class T> -List<T> &List<T>::prepend(const T &item) -{ - detach(); - d->list.push_front(item); - return *this; -} - -template <class T> -List<T> &List<T>::prepend(const List<T> &l) -{ - detach(); - d->list.insert(d->list.begin(), l.begin(), l.end()); - return *this; -} - -template <class T> -List<T> &List<T>::clear() -{ - detach(); - d->clear(); - return *this; -} - -template <class T> -TagLib::uint List<T>::size() const -{ - return d->list.size(); -} - -template <class T> -bool List<T>::isEmpty() const -{ - return d->list.empty(); -} - -template <class T> -typename List<T>::Iterator List<T>::find(const T &value) -{ - return std::find(d->list.begin(), d->list.end(), value); -} - -template <class T> -typename List<T>::ConstIterator List<T>::find(const T &value) const -{ - return std::find(d->list.begin(), d->list.end(), value); -} - -template <class T> -bool List<T>::contains(const T &value) const -{ - return std::find(d->list.begin(), d->list.end(), value) != d->list.end(); -} - -template <class T> -typename List<T>::Iterator List<T>::erase(Iterator it) -{ - return d->list.erase(it); -} - -template <class T> -const T &List<T>::front() const -{ - return d->list.front(); -} - -template <class T> -T &List<T>::front() -{ - detach(); - return d->list.front(); -} - -template <class T> -const T &List<T>::back() const -{ - return d->list.back(); -} - -template <class T> -void List<T>::setAutoDelete(bool autoDelete) -{ - d->autoDelete = autoDelete; -} - -template <class T> -T &List<T>::back() -{ - detach(); - return d->list.back(); -} - -template <class T> -T &List<T>::operator[](uint i) -{ - Iterator it = d->list.begin(); - - for(uint j = 0; j < i; j++) - ++it; - - return *it; -} - -template <class T> -const T &List<T>::operator[](uint i) const -{ - ConstIterator it = d->list.begin(); - - for(uint j = 0; j < i; j++) - ++it; - - return *it; -} - -template <class T> -List<T> &List<T>::operator=(const List<T> &l) -{ - if(&l == this) - return *this; - - if(d->deref()) - delete d; - d = l.d; - d->ref(); - return *this; -} - -template <class T> -bool List<T>::operator==(const List<T> &l) const -{ - return d->list == l.d->list; -} - -template <class T> -bool List<T>::operator!=(const List<T> &l) const -{ - return d->list != l.d->list; -} - -//////////////////////////////////////////////////////////////////////////////// -// protected members -//////////////////////////////////////////////////////////////////////////////// - -template <class T> -void List<T>::detach() -{ - if(d->count() > 1) { - d->deref(); - d = new ListPrivate<T>(d->list); - } -} - -} // namespace TagLib diff --git a/taglib/taglib/toolkit/tmap.h b/taglib/taglib/toolkit/tmap.h deleted file mode 100644 index a7d9930..0000000 --- a/taglib/taglib/toolkit/tmap.h +++ /dev/null @@ -1,199 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_MAP_H -#define TAGLIB_MAP_H - -#include <map> - -#include "taglib.h" - -namespace TagLib { - - //! A generic, implicitly shared map. - - /*! - * This implements a standard map container that associates a key with a value - * and has fast key-based lookups. This map is also implicitly shared making - * it suitable for pass-by-value usage. - */ - - template <class Key, class T> class Map - { - public: -#ifndef DO_NOT_DOCUMENT -#ifdef WANT_CLASS_INSTANTIATION_OF_MAP - // Some STL implementations get snippy over the use of the - // class keyword to distinguish different templates; Sun Studio - // in particular finds multiple specializations in certain rare - // cases and complains about that. GCC doesn't seem to mind, - // and uses the typedefs further below without the class keyword. - // Not all the specializations of Map can use the class keyword - // (when T is not actually a class type), so don't apply this - // generally. - typedef typename std::map<class Key, class T>::iterator Iterator; - typedef typename std::map<class Key, class T>::const_iterator ConstIterator; -#else - typedef typename std::map<Key, T>::iterator Iterator; - typedef typename std::map<Key, T>::const_iterator ConstIterator; -#endif -#endif - - /*! - * Constructs an empty Map. - */ - Map(); - - /*! - * Make a shallow, implicitly shared, copy of \a m. Because this is - * implicitly shared, this method is lightweight and suitable for - * pass-by-value usage. - */ - Map(const Map<Key, T> &m); - - /*! - * Destroys this instance of the Map. - */ - virtual ~Map(); - - /*! - * Returns an STL style iterator to the beginning of the map. See - * std::map::iterator for the semantics. - */ - Iterator begin(); - - /*! - * Returns an STL style iterator to the beginning of the map. See - * std::map::const_iterator for the semantics. - */ - ConstIterator begin() const; - - /*! - * Returns an STL style iterator to the end of the map. See - * std::map::iterator for the semantics. - */ - Iterator end(); - - /*! - * Returns an STL style iterator to the end of the map. See - * std::map::const_iterator for the semantics. - */ - ConstIterator end() const; - - /*! - * Inserts \a value under \a key in the map. If a value for \a key already - * exists it will be overwritten. - */ - Map<Key, T> &insert(const Key &key, const T &value); - - /*! - * Removes all of the elements from elements from the map. This however - * will not delete pointers if the mapped type is a pointer type. - */ - Map<Key, T> &clear(); - - /*! - * The number of elements in the map. - * - * \see isEmpty() - */ - uint size() const; - - /*! - * Returns true if the map is empty. - * - * \see size() - */ - bool isEmpty() const; - - /*! - * Find the first occurrence of \a key. - */ - Iterator find(const Key &key); - - /*! - * Find the first occurrence of \a key. - */ - ConstIterator find(const Key &key) const; - - /*! - * Returns true if the map contains an instance of \a key. - */ - bool contains(const Key &key) const; - - /*! - * Erase the item at \a it from the list. - */ - Map<Key, T> &erase(Iterator it); - - /*! - * Erase the item with \a key from the list. - */ - Map<Key, T> &erase(const Key &key); - - /*! - * Returns a reference to the value associated with \a key. - * - * \note This has undefined behavior if the key is not present in the map. - */ - const T &operator[](const Key &key) const; - - /*! - * Returns a reference to the value associated with \a key. - * - * \note This has undefined behavior if the key is not present in the map. - */ - T &operator[](const Key &key); - - /*! - * Make a shallow, implicitly shared, copy of \a m. Because this is - * implicitly shared, this method is lightweight and suitable for - * pass-by-value usage. - */ - Map<Key, T> &operator=(const Map<Key, T> &m); - - protected: - /* - * If this List is being shared via implicit sharing, do a deep copy of the - * data and separate from the shared members. This should be called by all - * non-const subclass members. - */ - void detach(); - - private: -#ifndef DO_NOT_DOCUMENT - template <class KeyP, class TP> class MapPrivate; - MapPrivate<Key, T> *d; -#endif - }; - -} - -// Since GCC doesn't support the "export" keyword, we have to include the -// implementation. - -#include "tmap.tcc" - -#endif diff --git a/taglib/taglib/toolkit/tmap.tcc b/taglib/taglib/toolkit/tmap.tcc deleted file mode 100644 index 5d3abca..0000000 --- a/taglib/taglib/toolkit/tmap.tcc +++ /dev/null @@ -1,199 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include "trefcounter.h" - -namespace TagLib { - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -// BIC change to RefCounter -template <class Key, class T> -template <class KeyP, class TP> -class Map<Key, T>::MapPrivate : public RefCounterOld -{ -public: - MapPrivate() : RefCounterOld() {} -#ifdef WANT_CLASS_INSTANTIATION_OF_MAP - MapPrivate(const std::map<class KeyP, class TP>& m) : RefCounterOld(), map(m) {} - std::map<class KeyP, class TP> map; -#else - MapPrivate(const std::map<KeyP, TP>& m) : RefCounterOld(), map(m) {} - std::map<KeyP, TP> map; -#endif -}; - -template <class Key, class T> -Map<Key, T>::Map() -{ - d = new MapPrivate<Key, T>; -} - -template <class Key, class T> -Map<Key, T>::Map(const Map<Key, T> &m) : d(m.d) -{ - d->ref(); -} - -template <class Key, class T> -Map<Key, T>::~Map() -{ - if(d->deref()) - delete(d); -} - -template <class Key, class T> -typename Map<Key, T>::Iterator Map<Key, T>::begin() -{ - detach(); - return d->map.begin(); -} - -template <class Key, class T> -typename Map<Key, T>::ConstIterator Map<Key, T>::begin() const -{ - return d->map.begin(); -} - -template <class Key, class T> -typename Map<Key, T>::Iterator Map<Key, T>::end() -{ - detach(); - return d->map.end(); -} - -template <class Key, class T> -typename Map<Key, T>::ConstIterator Map<Key, T>::end() const -{ - return d->map.end(); -} - -template <class Key, class T> -Map<Key, T> &Map<Key, T>::insert(const Key &key, const T &value) -{ - detach(); - d->map[key] = value; - return *this; -} - -template <class Key, class T> -Map<Key, T> &Map<Key, T>::clear() -{ - detach(); - d->map.clear(); - return *this; -} - -template <class Key, class T> -bool Map<Key, T>::isEmpty() const -{ - return d->map.empty(); -} - -template <class Key, class T> -typename Map<Key, T>::Iterator Map<Key, T>::find(const Key &key) -{ - detach(); - return d->map.find(key); -} - -template <class Key, class T> -typename Map<Key,T>::ConstIterator Map<Key, T>::find(const Key &key) const -{ - return d->map.find(key); -} - -template <class Key, class T> -bool Map<Key, T>::contains(const Key &key) const -{ - return d->map.find(key) != d->map.end(); -} - -template <class Key, class T> -Map<Key, T> &Map<Key,T>::erase(Iterator it) -{ - detach(); - d->map.erase(it); - return *this; -} - -template <class Key, class T> -Map<Key, T> &Map<Key,T>::erase(const Key &key) -{ - detach(); - Iterator it = d->map.find(key); - if(it != d->map.end()) - d->map.erase(it); - return *this; -} - -template <class Key, class T> -TagLib::uint Map<Key, T>::size() const -{ - return d->map.size(); -} - -template <class Key, class T> -const T &Map<Key, T>::operator[](const Key &key) const -{ - return d->map[key]; -} - -template <class Key, class T> -T &Map<Key, T>::operator[](const Key &key) -{ - detach(); - return d->map[key]; -} - -template <class Key, class T> -Map<Key, T> &Map<Key, T>::operator=(const Map<Key, T> &m) -{ - if(&m == this) - return *this; - - if(d->deref()) - delete(d); - d = m.d; - d->ref(); - return *this; -} - -//////////////////////////////////////////////////////////////////////////////// -// protected members -//////////////////////////////////////////////////////////////////////////////// - -template <class Key, class T> -void Map<Key, T>::detach() -{ - if(d->count() > 1) { - d->deref(); - d = new MapPrivate<Key, T>(d->map); - } -} - -} // namespace TagLib diff --git a/taglib/taglib/toolkit/tpropertymap.cpp b/taglib/taglib/toolkit/tpropertymap.cpp deleted file mode 100644 index 3317cc9..0000000 --- a/taglib/taglib/toolkit/tpropertymap.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/*************************************************************************** - copyright : (C) 2012 by Michael Helmling - email : helmling@mathematik.uni-kl.de - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * - ***************************************************************************/ - -#include "tpropertymap.h" -using namespace TagLib; - - -PropertyMap::PropertyMap() : SimplePropertyMap() -{ -} - -PropertyMap::PropertyMap(const PropertyMap &m) : SimplePropertyMap(m), unsupported(m.unsupported) -{ -} - -PropertyMap::PropertyMap(const SimplePropertyMap &m) -{ - for(SimplePropertyMap::ConstIterator it = m.begin(); it != m.end(); ++it){ - String key = it->first.upper(); - if(!key.isNull()) - insert(it->first, it->second); - else - unsupported.append(it->first); - } -} - -PropertyMap::~PropertyMap() -{ -} - -bool PropertyMap::insert(const String &key, const StringList &values) -{ - String realKey = key.upper(); - Iterator result = SimplePropertyMap::find(realKey); - if(result == end()) - SimplePropertyMap::insert(realKey, values); - else - SimplePropertyMap::operator[](realKey).append(values); - return true; -} - -bool PropertyMap::replace(const String &key, const StringList &values) -{ - String realKey = key.upper(); - SimplePropertyMap::erase(realKey); - SimplePropertyMap::insert(realKey, values); - return true; -} - -PropertyMap::Iterator PropertyMap::find(const String &key) -{ - return SimplePropertyMap::find(key.upper()); -} - -PropertyMap::ConstIterator PropertyMap::find(const String &key) const -{ - return SimplePropertyMap::find(key.upper()); -} - -bool PropertyMap::contains(const String &key) const -{ - return SimplePropertyMap::contains(key.upper()); -} - -bool PropertyMap::contains(const PropertyMap &other) const -{ - for(ConstIterator it = other.begin(); it != other.end(); ++it) { - if(!SimplePropertyMap::contains(it->first)) - return false; - if ((*this)[it->first] != it->second) - return false; - } - return true; -} - -PropertyMap &PropertyMap::erase(const String &key) -{ - SimplePropertyMap::erase(key.upper()); - return *this; -} - -PropertyMap &PropertyMap::erase(const PropertyMap &other) -{ - for(ConstIterator it = other.begin(); it != other.end(); ++it) - erase(it->first); - return *this; -} - -PropertyMap &PropertyMap::merge(const PropertyMap &other) -{ - for(PropertyMap::ConstIterator it = other.begin(); it != other.end(); ++it) - insert(it->first, it->second); - unsupported.append(other.unsupported); - return *this; -} - -const StringList &PropertyMap::operator[](const String &key) const -{ - return SimplePropertyMap::operator[](key.upper()); -} - -StringList &PropertyMap::operator[](const String &key) -{ - return SimplePropertyMap::operator[](key.upper()); -} - -bool PropertyMap::operator==(const PropertyMap &other) const -{ - for(ConstIterator it = other.begin(); it != other.end(); ++it) { - ConstIterator thisFind = find(it->first); - if( thisFind == end() || (thisFind->second != it->second) ) - return false; - } - for(ConstIterator it = begin(); it != end(); ++it) { - ConstIterator otherFind = other.find(it->first); - if( otherFind == other.end() || (otherFind->second != it->second) ) - return false; - } - return unsupported == other.unsupported; -} - -bool PropertyMap::operator!=(const PropertyMap &other) const -{ - return !(*this == other); -} - -String PropertyMap::toString() const -{ - String ret = ""; - for(ConstIterator it = begin(); it != end(); ++it) - ret += it->first+"="+it->second.toString(", ") + "\n"; - if(!unsupported.isEmpty()) - ret += "Unsupported Data: " + unsupported.toString(", ") + "\n"; - return ret; -} - -void PropertyMap::removeEmpty() -{ - StringList emptyKeys; - for(Iterator it = begin(); it != end(); ++it) - if(it->second.isEmpty()) - emptyKeys.append(it->first); - for(StringList::Iterator emptyIt = emptyKeys.begin(); emptyIt != emptyKeys.end(); emptyIt++ ) - erase(*emptyIt); -} - -StringList &PropertyMap::unsupportedData() -{ - return unsupported; -} - -const StringList &PropertyMap::unsupportedData() const -{ - return unsupported; -} diff --git a/taglib/taglib/toolkit/tpropertymap.h b/taglib/taglib/toolkit/tpropertymap.h deleted file mode 100644 index 2be49dd..0000000 --- a/taglib/taglib/toolkit/tpropertymap.h +++ /dev/null @@ -1,233 +0,0 @@ -/*************************************************************************** - copyright : (C) 2012 by Michael Helmling - email : helmling@mathematik.uni-kl.de - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef PROPERTYMAP_H_ -#define PROPERTYMAP_H_ - -#include "tmap.h" -#include "tstringlist.h" - -namespace TagLib { - - typedef Map<String,StringList> SimplePropertyMap; - - //! A map for format-independent <key,valuelist> tag representations. - - /*! - * This map implements a generic representation of textual audio metadata - * ("tags") realized as pairs of a case-insensitive key - * and a nonempty list of corresponding values, each value being an an arbitrary - * unicode String. - * - * Note that most metadata formats pose additional conditions on the tag keys. The - * most popular ones (Vorbis, APE, ID3v2) should support all ASCII only words of - * length between 2 and 16. - * - * This class can contain any tags, but here is a list of "well-known" tags that - * you might want to use: - * - * Basic tags: - * - * - TITLE - * - ALBUM - * - ARTIST - * - ALBUMARTIST - * - SUBTITLE - * - TRACKNUMBER - * - DISCNUMBER - * - DATE - * - ORIGINALDATE - * - GENRE - * - COMMENT - * - * Sort names: - * - * - TITLESORT - * - ALBUMSORT - * - ARTISTSORT - * - ALBUMARTISTSORT - * - * Credits: - * - * - COMPOSER - * - LYRICIST - * - CONDUCTOR - * - REMIXER - * - PERFORMER:<XXXX> - * - * Other tags: - * - * - ISRC - * - ASIN - * - BPM - * - COPYRIGHT - * - ENCODEDBY - * - MOOD - * - COMMENT - * - MEDIA - * - LABEL - * - CATALOGNUMBER - * - BARCODE - * - * MusicBrainz identifiers: - * - * - MUSICBRAINZ_TRACKID - * - MUSICBRAINZ_ALBUMID - * - MUSICBRAINZ_RELEASEGROUPID - * - MUSICBRAINZ_WORKID - * - MUSICBRAINZ_ARTISTID - * - MUSICBRAINZ_ALBUMARTISTID - * - ACOUSTID_ID - * - ACOUSTID_FINGERPRINT - * - MUSICIP_PUID - * - */ - - class TAGLIB_EXPORT PropertyMap: public SimplePropertyMap - { - public: - - typedef SimplePropertyMap::Iterator Iterator; - typedef SimplePropertyMap::ConstIterator ConstIterator; - - PropertyMap(); - - PropertyMap(const PropertyMap &m); - - /*! - * Creates a PropertyMap initialized from a SimplePropertyMap. Copies all - * entries from \a m that have valid keys. - * Invalid keys will be appended to the unsupportedData() list. - */ - PropertyMap(const SimplePropertyMap &m); - - virtual ~PropertyMap(); - - /*! - * Inserts \a values under \a key in the map. If \a key already exists, - * then \values will be appended to the existing StringList. - * The returned value indicates success, i.e. whether \a key is a - * valid key. - */ - bool insert(const String &key, const StringList &values); - - /*! - * Replaces any existing values for \a key with the given \a values, - * and simply insert them if \a key did not exist before. - * The returned value indicates success, i.e. whether \a key is a - * valid key. - */ - bool replace(const String &key, const StringList &values); - - /*! - * Find the first occurrence of \a key. - */ - Iterator find(const String &key); - - /*! - * Find the first occurrence of \a key. - */ - ConstIterator find(const String &key) const; - - /*! - * Returns true if the map contains values for \a key. - */ - bool contains(const String &key) const; - - /*! - * Returns true if this map contains all keys of \a other - * and the values coincide for that keys. Does not take - * the unsupportedData list into account. - */ - bool contains(const PropertyMap &other) const; - - /*! - * Erase the \a key and its values from the map. - */ - PropertyMap &erase(const String &key); - - /*! - * Erases from this map all keys that appear in \a other. - */ - PropertyMap &erase(const PropertyMap &other); - - /*! - * Merge the contents of \a other into this PropertyMap. - * If a key is contained in both maps, the values of the second - * are appended to that of the first. - * The unsupportedData() lists are concatenated as well. - */ - PropertyMap &merge(const PropertyMap &other); - - /*! - * Returns a reference to the value associated with \a key. - * - * \note: If \a key is not contained in the map, an empty - * StringList is returned without error. - */ - const StringList &operator[](const String &key) const; - - /*! - * Returns a reference to the value associated with \a key. - * - * \note: If \a key is not contained in the map, an empty - * StringList is returned. You can also directly add entries - * by using this function as an lvalue. - */ - StringList &operator[](const String &key); - - /*! - * Returns true if and only if \other has the same contents as this map. - */ - bool operator==(const PropertyMap &other) const; - - /*! - * Returns false if and only \other has the same contents as this map. - */ - bool operator!=(const PropertyMap &other) const; - - /*! - * If a PropertyMap is read from a File object using File::properties(), - * the StringList returned from this function will represent metadata - * that could not be parsed into the PropertyMap representation. This could - * be e.g. binary data, unknown ID3 frames, etc. - * You can remove items from the returned list, which tells TagLib to remove - * those unsupported elements if you call File::setProperties() with the - * same PropertyMap as argument. - */ - StringList &unsupportedData(); - const StringList &unsupportedData() const; - - /*! - * Removes all entries which have an empty value list. - */ - void removeEmpty(); - - String toString() const; - - private: - - - StringList unsupported; - }; - -} -#endif /* PROPERTYMAP_H_ */ diff --git a/taglib/taglib/toolkit/trefcounter.cpp b/taglib/taglib/toolkit/trefcounter.cpp deleted file mode 100644 index 71f3c2f..0000000 --- a/taglib/taglib/toolkit/trefcounter.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/*************************************************************************** - copyright : (C) 2013 by Tsuda Kageyu - email : tsuda.kageyu@gmail.com - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "trefcounter.h" - -#if defined(HAVE_STD_ATOMIC) -# include <atomic> -# define ATOMIC_INT std::atomic<unsigned int> -# define ATOMIC_INC(x) x.fetch_add(1) -# define ATOMIC_DEC(x) (x.fetch_sub(1) - 1) -#elif defined(HAVE_BOOST_ATOMIC) -# include <boost/atomic.hpp> -# define ATOMIC_INT boost::atomic<unsigned int> -# define ATOMIC_INC(x) x.fetch_add(1) -# define ATOMIC_DEC(x) (x.fetch_sub(1) - 1) -#elif defined(HAVE_GCC_ATOMIC) -# define ATOMIC_INT int -# define ATOMIC_INC(x) __sync_add_and_fetch(&x, 1) -# define ATOMIC_DEC(x) __sync_sub_and_fetch(&x, 1) -#elif defined(HAVE_WIN_ATOMIC) -# if !defined(NOMINMAX) -# define NOMINMAX -# endif -# include <windows.h> -# define ATOMIC_INT long -# define ATOMIC_INC(x) InterlockedIncrement(&x) -# define ATOMIC_DEC(x) InterlockedDecrement(&x) -#elif defined(HAVE_MAC_ATOMIC) -# include <libkern/OSAtomic.h> -# define ATOMIC_INT int32_t -# define ATOMIC_INC(x) OSAtomicIncrement32Barrier(&x) -# define ATOMIC_DEC(x) OSAtomicDecrement32Barrier(&x) -#elif defined(HAVE_IA64_ATOMIC) -# include <ia64intrin.h> -# define ATOMIC_INT int -# define ATOMIC_INC(x) __sync_add_and_fetch(&x, 1) -# define ATOMIC_DEC(x) __sync_sub_and_fetch(&x, 1) -#else -# define ATOMIC_INT int -# define ATOMIC_INC(x) (++x) -# define ATOMIC_DEC(x) (--x) -#endif - -namespace TagLib -{ - class RefCounter::RefCounterPrivate - { - public: - RefCounterPrivate() : refCount(1) {} - - void ref() { ATOMIC_INC(refCount); } - bool deref() { return (ATOMIC_DEC(refCount) == 0); } - int count() const { return refCount; } - - volatile ATOMIC_INT refCount; - }; - - RefCounter::RefCounter() - : d(new RefCounterPrivate()) - { - } - - RefCounter::~RefCounter() - { - delete d; - } - - void RefCounter::ref() - { - d->ref(); - } - - bool RefCounter::deref() - { - return d->deref(); - } - - int RefCounter::count() const - { - return d->count(); - } -} diff --git a/taglib/taglib/toolkit/trefcounter.h b/taglib/taglib/toolkit/trefcounter.h deleted file mode 100644 index 75388b1..0000000 --- a/taglib/taglib/toolkit/trefcounter.h +++ /dev/null @@ -1,111 +0,0 @@ -/*************************************************************************** - copyright : (C) 2013 by Tsuda Kageyu - email : tsuda.kageyu@gmail.com - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_REFCOUNTER_H -#define TAGLIB_REFCOUNTER_H - -#include "taglib_export.h" -#include "taglib.h" - -#ifdef __APPLE__ -# include <libkern/OSAtomic.h> -# define TAGLIB_ATOMIC_MAC -#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# define NOMINMAX -# include <windows.h> -# define TAGLIB_ATOMIC_WIN -#elif defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 401) \ - && (defined(__i386__) || defined(__i486__) || defined(__i586__) || \ - defined(__i686__) || defined(__x86_64) || defined(__ia64)) \ - && !defined(__INTEL_COMPILER) -# define TAGLIB_ATOMIC_GCC -#elif defined(__ia64) && defined(__INTEL_COMPILER) -# include <ia64intrin.h> -# define TAGLIB_ATOMIC_GCC -#endif - -#ifndef DO_NOT_DOCUMENT // Tell Doxygen to skip this class. -/*! - * \internal - * This is just used as a base class for shared classes in TagLib. - * - * \warning This <b>is not</b> part of the TagLib public API! - */ -namespace TagLib -{ - - class TAGLIB_EXPORT RefCounter - { - public: - RefCounter(); - virtual ~RefCounter(); - - void ref(); - bool deref(); - int count() const; - - private: - class RefCounterPrivate; - RefCounterPrivate *d; - }; - - // BIC this old class is needed by tlist.tcc and tmap.tcc - class RefCounterOld - { - public: - RefCounterOld() : refCount(1) {} - -#ifdef TAGLIB_ATOMIC_MAC - void ref() { OSAtomicIncrement32Barrier(const_cast<int32_t*>(&refCount)); } - bool deref() { return ! OSAtomicDecrement32Barrier(const_cast<int32_t*>(&refCount)); } - int32_t count() { return refCount; } - private: - volatile int32_t refCount; -#elif defined(TAGLIB_ATOMIC_WIN) - void ref() { InterlockedIncrement(&refCount); } - bool deref() { return ! InterlockedDecrement(&refCount); } - long count() { return refCount; } - private: - volatile long refCount; -#elif defined(TAGLIB_ATOMIC_GCC) - void ref() { __sync_add_and_fetch(&refCount, 1); } - bool deref() { return ! __sync_sub_and_fetch(&refCount, 1); } - int count() { return refCount; } - private: - volatile int refCount; -#else - void ref() { refCount++; } - bool deref() { return ! --refCount; } - int count() { return refCount; } - private: - uint refCount; -#endif - }; - -} - -#endif // DO_NOT_DOCUMENT -#endif - diff --git a/taglib/taglib/toolkit/tstring.cpp b/taglib/taglib/toolkit/tstring.cpp deleted file mode 100644 index 75a9833..0000000 --- a/taglib/taglib/toolkit/tstring.cpp +++ /dev/null @@ -1,880 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -// This class assumes that std::basic_string<T> has a contiguous and null-terminated buffer. - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "tstring.h" -#include "tdebug.h" -#include "tstringlist.h" -#include "trefcounter.h" -#include "tutils.h" - -#include <iostream> -#include <cstdio> -#include <cstring> - -#ifdef HAVE_STD_CODECVT -# include <codecvt> -#else -# include "unicode.h" -#endif - -namespace -{ - - inline unsigned short combine(unsigned char c1, unsigned char c2) - { - return (c1 << 8) | c2; - } - - void UTF16toUTF8(const wchar_t *src, size_t srcLength, char *dst, size_t dstLength) - { -#ifdef HAVE_STD_CODECVT - - typedef std::codecvt_utf8_utf16<wchar_t> utf8_utf16_t; - - using namespace TagLib; - - const wchar_t *srcBegin = src; - const wchar_t *srcEnd = srcBegin + srcLength; - - char *dstBegin = dst; - char *dstEnd = dstBegin + dstLength; - - std::mbstate_t st; - const wchar_t *source; - char *target; - memset(&st, 0, sizeof(st)); - std::codecvt_base::result result = utf8_utf16_t().out( - st, srcBegin, srcEnd, source, dstBegin, dstEnd, target); - - if(result != utf8_utf16_t::ok) { - debug("String::copyFromUTF8() - Unicode conversion error."); - } - -#else - - using namespace Unicode; - using namespace TagLib; - - const Unicode::UTF16 *srcBegin = src; - const Unicode::UTF16 *srcEnd = srcBegin + srcLength; - - Unicode::UTF8 *dstBegin = reinterpret_cast<Unicode::UTF8*>(dst); - Unicode::UTF8 *dstEnd = dstBegin + dstLength; - - Unicode::ConversionResult result = Unicode::ConvertUTF16toUTF8( - &srcBegin, srcEnd, &dstBegin, dstEnd, Unicode::lenientConversion); - - if(result != Unicode::conversionOK) { - debug("String::to8Bit() - Unicode conversion error."); - } - -#endif - } - - void UTF8toUTF16(const char *src, size_t srcLength, wchar_t *dst, size_t dstLength) - { -#ifdef HAVE_STD_CODECVT - - typedef std::codecvt_utf8_utf16<wchar_t> utf8_utf16_t; - - using namespace TagLib; - - const char *srcBegin = src; - const char *srcEnd = srcBegin + srcLength; - - wchar_t *dstBegin = dst; - wchar_t *dstEnd = dstBegin + dstLength; - - std::mbstate_t st; - const char *source; - wchar_t *target; - memset(&st, 0, sizeof(st)); - std::codecvt_base::result result = utf8_utf16_t().in( - st, srcBegin, srcEnd, source, dstBegin, dstEnd, target); - - if(result != utf8_utf16_t::ok) { - debug("String::copyFromUTF8() - Unicode conversion error."); - } - -#else - - using namespace Unicode; - using namespace TagLib; - - const Unicode::UTF8 *srcBegin = reinterpret_cast<const Unicode::UTF8*>(src); - const Unicode::UTF8 *srcEnd = srcBegin + srcLength; - - Unicode::UTF16 *dstBegin = dst; - Unicode::UTF16 *dstEnd = dstBegin + dstLength; - - Unicode::ConversionResult result = Unicode::ConvertUTF8toUTF16( - &srcBegin, srcEnd, &dstBegin, dstEnd, Unicode::lenientConversion); - - if(result != Unicode::conversionOK) { - debug("String::copyFromUTF8() - Unicode conversion error."); - } - -#endif - } -} - -namespace TagLib { - -class String::StringPrivate : public RefCounter -{ -public: - StringPrivate() - : RefCounter() - { - } - - StringPrivate(const wstring &s) - : RefCounter() - , data(s) - { - } - - StringPrivate(uint n, wchar_t c) - : RefCounter() - , data(static_cast<size_t>(n), c) - { - } - - /*! - * Stores string in UTF-16. The byte order depends on the CPU endian. - */ - TagLib::wstring data; - - /*! - * This is only used to hold the the most recent value of toCString(). - */ - std::string cstring; -}; - -String String::null; - -//////////////////////////////////////////////////////////////////////////////// - -String::String() - : d(new StringPrivate()) -{ -} - -String::String(const String &s) - : d(s.d) -{ - d->ref(); -} - -String::String(const std::string &s, Type t) - : d(new StringPrivate()) -{ - if(t == Latin1) - copyFromLatin1(&s[0], s.length()); - else if(t == String::UTF8) - copyFromUTF8(&s[0], s.length()); - else { - debug("String::String() -- A std::string should not contain UTF16."); - } -} - -String::String(const wstring &s, Type t) - : d(new StringPrivate()) -{ - if(t == UTF16 || t == UTF16BE || t == UTF16LE) - copyFromUTF16(s.c_str(), s.length(), t); - else { - debug("String::String() -- A TagLib::wstring should not contain Latin1 or UTF-8."); - } -} - -String::String(const wchar_t *s, Type t) - : d(new StringPrivate()) -{ - if(t == UTF16 || t == UTF16BE || t == UTF16LE) - copyFromUTF16(s, ::wcslen(s), t); - else { - debug("String::String() -- A const wchar_t * should not contain Latin1 or UTF-8."); - } -} - -String::String(const char *s, Type t) - : d(new StringPrivate()) -{ - if(t == Latin1) - copyFromLatin1(s, ::strlen(s)); - else if(t == String::UTF8) - copyFromUTF8(s, ::strlen(s)); - else { - debug("String::String() -- A const char * should not contain UTF16."); - } -} - -String::String(wchar_t c, Type t) - : d(new StringPrivate()) -{ - if(t == UTF16 || t == UTF16BE || t == UTF16LE) - copyFromUTF16(&c, 1, t); - else { - debug("String::String() -- A const wchar_t should not contain Latin1 or UTF-8."); - } -} - -String::String(char c, Type t) - : d(new StringPrivate(1, static_cast<uchar>(c))) -{ - if(t != Latin1 && t != UTF8) { - debug("String::String() -- A char should not contain UTF16."); - } -} - -String::String(const ByteVector &v, Type t) - : d(new StringPrivate()) -{ - if(v.isEmpty()) - return; - - if(t == Latin1) - copyFromLatin1(v.data(), v.size()); - else if(t == UTF8) - copyFromUTF8(v.data(), v.size()); - else - copyFromUTF16(v.data(), v.size(), t); - - // If we hit a null in the ByteVector, shrink the string again. - d->data.resize(::wcslen(d->data.c_str())); -} - -//////////////////////////////////////////////////////////////////////////////// - -String::~String() -{ - if(d->deref()) - delete d; -} - -std::string String::to8Bit(bool unicode) const -{ - std::string s; - - if(!unicode) { - s.resize(d->data.size()); - - std::string::iterator targetIt = s.begin(); - for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) { - *targetIt = static_cast<char>(*it); - ++targetIt; - } - } - else { - s.resize(d->data.size() * 4 + 1); - - UTF16toUTF8(&d->data[0], d->data.size(), &s[0], s.size()); - s.resize(::strlen(s.c_str())); - } - - return s; -} - -TagLib::wstring String::toWString() const -{ - return d->data; -} - -const char *String::toCString(bool unicode) const -{ - d->cstring = to8Bit(unicode); - return d->cstring.c_str(); -} - -const wchar_t *String::toCWString() const -{ - return d->data.c_str(); -} - -String::Iterator String::begin() -{ - return d->data.begin(); -} - -String::ConstIterator String::begin() const -{ - return d->data.begin(); -} - -String::Iterator String::end() -{ - return d->data.end(); -} - -String::ConstIterator String::end() const -{ - return d->data.end(); -} - -int String::find(const String &s, int offset) const -{ - return d->data.find(s.d->data, offset); -} - -int String::rfind(const String &s, int offset) const -{ - return d->data.rfind(s.d->data, offset); -} - -StringList String::split(const String &separator) const -{ - StringList list; - for(int index = 0;;) - { - int sep = find(separator, index); - if(sep < 0) - { - list.append(substr(index, size() - index)); - break; - } - else - { - list.append(substr(index, sep - index)); - index = sep + separator.size(); - } - } - return list; -} - -bool String::startsWith(const String &s) const -{ - if(s.length() > length()) - return false; - - return substr(0, s.length()) == s; -} - -String String::substr(uint position, uint n) const -{ - return String(d->data.substr(position, n)); -} - -String &String::append(const String &s) -{ - detach(); - d->data += s.d->data; - return *this; -} - -String String::upper() const -{ - String s; - - static int shift = 'A' - 'a'; - - for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); ++it) { - if(*it >= 'a' && *it <= 'z') - s.d->data.push_back(*it + shift); - else - s.d->data.push_back(*it); - } - - return s; -} - -TagLib::uint String::size() const -{ - return d->data.size(); -} - -TagLib::uint String::length() const -{ - return size(); -} - -bool String::isEmpty() const -{ - return d->data.size() == 0; -} - -bool String::isNull() const -{ - return d == null.d; -} - -ByteVector String::data(Type t) const -{ - switch(t) - { - case Latin1: - { - ByteVector v(size(), 0); - char *p = v.data(); - - for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) - *p++ = static_cast<char>(*it); - - return v; - } - case UTF8: - { - ByteVector v(size() * 4 + 1, 0); - - UTF16toUTF8(&d->data[0], d->data.size(), v.data(), v.size()); - v.resize(::strlen(v.data())); - - return v; - } - case UTF16: - { - ByteVector v(2 + size() * 2, 0); - char *p = v.data(); - - // Assume that if we're doing UTF16 and not UTF16BE that we want little - // endian encoding. (Byte Order Mark) - - *p++ = '\xff'; - *p++ = '\xfe'; - - for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) { - *p++ = static_cast<char>(*it & 0xff); - *p++ = static_cast<char>(*it >> 8); - } - - return v; - } - case UTF16BE: - { - ByteVector v(size() * 2, 0); - char *p = v.data(); - - for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) { - *p++ = static_cast<char>(*it >> 8); - *p++ = static_cast<char>(*it & 0xff); - } - - return v; - } - case UTF16LE: - { - ByteVector v(size() * 2, 0); - char *p = v.data(); - - for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) { - *p++ = static_cast<char>(*it & 0xff); - *p++ = static_cast<char>(*it >> 8); - } - - return v; - } - default: - { - debug("String::data() - Invalid Type value."); - return ByteVector(); - } - } -} - -int String::toInt() const -{ - return toInt(0); -} - -int String::toInt(bool *ok) const -{ - int value = 0; - - uint size = d->data.size(); - bool negative = size > 0 && d->data[0] == '-'; - uint start = negative ? 1 : 0; - uint i = start; - - for(; i < size && d->data[i] >= '0' && d->data[i] <= '9'; i++) - value = value * 10 + (d->data[i] - '0'); - - if(negative) - value = value * -1; - - if(ok) - *ok = (size > start && i == size); - - return value; -} - -String String::stripWhiteSpace() const -{ - wstring::const_iterator begin = d->data.begin(); - wstring::const_iterator end = d->data.end(); - - while(begin != end && - (*begin == '\t' || *begin == '\n' || *begin == '\f' || - *begin == '\r' || *begin == ' ')) - { - ++begin; - } - - if(begin == end) - return null; - - // There must be at least one non-whitespace character here for us to have - // gotten this far, so we should be safe not doing bounds checking. - - do { - --end; - } while(*end == '\t' || *end == '\n' || - *end == '\f' || *end == '\r' || *end == ' '); - - return String(wstring(begin, end + 1)); -} - -bool String::isLatin1() const -{ - for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) { - if(*it >= 256) - return false; - } - return true; -} - -bool String::isAscii() const -{ - for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) { - if(*it >= 128) - return false; - } - return true; -} - -String String::number(int n) // static -{ - static const size_t BufferSize = 11; // Sufficient to store "-214748364". - static const char *Format = "%d"; - - char buffer[BufferSize]; - int length; - -#if defined(HAVE_SNPRINTF) - - length = snprintf(buffer, BufferSize, Format, n); - -#elif defined(HAVE_SPRINTF_S) - - length = sprintf_s(buffer, Format, n); - -#else - - length = sprintf(buffer, Format, n); - -#endif - - if(length > 0) - return String(buffer); - else - return String::null; -} - -TagLib::wchar &String::operator[](int i) -{ - detach(); - return d->data[i]; -} - -const TagLib::wchar &String::operator[](int i) const -{ - return d->data[i]; -} - -bool String::operator==(const String &s) const -{ - return d == s.d || d->data == s.d->data; -} - -bool String::operator!=(const String &s) const -{ - return !operator==(s); -} - -String &String::operator+=(const String &s) -{ - detach(); - - d->data += s.d->data; - return *this; -} - -String &String::operator+=(const wchar_t *s) -{ - detach(); - - d->data += s; - return *this; -} - -String &String::operator+=(const char *s) -{ - detach(); - - for(int i = 0; s[i] != 0; i++) - d->data += uchar(s[i]); - return *this; -} - -String &String::operator+=(wchar_t c) -{ - detach(); - - d->data += c; - return *this; -} - -String &String::operator+=(char c) -{ - detach(); - - d->data += uchar(c); - return *this; -} - -String &String::operator=(const String &s) -{ - if(&s == this) - return *this; - - if(d->deref()) - delete d; - d = s.d; - d->ref(); - return *this; -} - -String &String::operator=(const std::string &s) -{ - if(d->deref()) - delete d; - - d = new StringPrivate; - copyFromLatin1(s.c_str(), s.length()); - - return *this; -} - -String &String::operator=(const wstring &s) -{ - if(d->deref()) - delete d; - d = new StringPrivate(s); - return *this; -} - -String &String::operator=(const wchar_t *s) -{ - if(d->deref()) - delete d; - - d = new StringPrivate(s); - return *this; -} - -String &String::operator=(char c) -{ - if(d->deref()) - delete d; - - d = new StringPrivate(1, static_cast<uchar>(c)); - return *this; -} - -String &String::operator=(wchar_t c) -{ - if(d->deref()) - delete d; - - d = new StringPrivate(1, c); - return *this; -} - -String &String::operator=(const char *s) -{ - if(d->deref()) - delete d; - - d = new StringPrivate; - copyFromLatin1(s, ::strlen(s)); - - return *this; -} - -String &String::operator=(const ByteVector &v) -{ - if(d->deref()) - delete d; - - d = new StringPrivate; - copyFromLatin1(v.data(), v.size()); - - // If we hit a null in the ByteVector, shrink the string again. - d->data.resize(::wcslen(d->data.c_str())); - - return *this; -} - -bool String::operator<(const String &s) const -{ - return d->data < s.d->data; -} - -//////////////////////////////////////////////////////////////////////////////// -// protected members -//////////////////////////////////////////////////////////////////////////////// - -void String::detach() -{ - if(d->count() > 1) { - d->deref(); - d = new StringPrivate(d->data); - } -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -void String::copyFromLatin1(const char *s, size_t length) -{ - d->data.resize(length); - - for(size_t i = 0; i < length; ++i) - d->data[i] = static_cast<uchar>(s[i]); -} - -void String::copyFromUTF8(const char *s, size_t length) -{ - d->data.resize(length); - - UTF8toUTF16(s, length, &d->data[0], d->data.size()); - d->data.resize(::wcslen(d->data.c_str())); -} - -void String::copyFromUTF16(const wchar_t *s, size_t length, Type t) -{ - bool swap; - if(t == UTF16) { - if(length >= 1 && s[0] == 0xfeff) - swap = false; // Same as CPU endian. No need to swap bytes. - else if(length >= 1 && s[0] == 0xfffe) - swap = true; // Not same as CPU endian. Need to swap bytes. - else { - debug("String::copyFromUTF16() - Invalid UTF16 string."); - return; - } - - s++; - length--; - } - else - swap = (t != WCharByteOrder); - - d->data.resize(length); - memcpy(&d->data[0], s, length * sizeof(wchar_t)); - - if(swap) { - for(size_t i = 0; i < length; ++i) - d->data[i] = Utils::byteSwap(static_cast<ushort>(s[i])); - } -} - -void String::copyFromUTF16(const char *s, size_t length, Type t) -{ - bool swap; - if(t == UTF16) { - if(length < 2) { - debug("String::copyFromUTF16() - Invalid UTF16 string."); - return; - } - - // Uses memcpy instead of reinterpret_cast to avoid an alignment exception. - ushort bom; - ::memcpy(&bom, s, 2); - - if(bom == 0xfeff) - swap = false; // Same as CPU endian. No need to swap bytes. - else if(bom == 0xfffe) - swap = true; // Not same as CPU endian. Need to swap bytes. - else { - debug("String::copyFromUTF16() - Invalid UTF16 string."); - return; - } - - s += 2; - length -= 2; - } - else - swap = (t != WCharByteOrder); - - d->data.resize(length / 2); - for(size_t i = 0; i < length / 2; ++i) { - d->data[i] = swap ? combine(*s, *(s + 1)) : combine(*(s + 1), *s); - s += 2; - } -} - -const String::Type String::WCharByteOrder - = (Utils::SystemByteOrder == Utils::BigEndian) ? String::UTF16BE : String::UTF16LE; - -} - -//////////////////////////////////////////////////////////////////////////////// -// related functions -//////////////////////////////////////////////////////////////////////////////// - -const TagLib::String operator+(const TagLib::String &s1, const TagLib::String &s2) -{ - TagLib::String s(s1); - s.append(s2); - return s; -} - -const TagLib::String operator+(const char *s1, const TagLib::String &s2) -{ - TagLib::String s(s1); - s.append(s2); - return s; -} - -const TagLib::String operator+(const TagLib::String &s1, const char *s2) -{ - TagLib::String s(s1); - s.append(s2); - return s; -} - -std::ostream &operator<<(std::ostream &s, const TagLib::String &str) -{ - s << str.to8Bit(); - return s; -} - diff --git a/taglib/taglib/toolkit/tstring.h b/taglib/taglib/toolkit/tstring.h deleted file mode 100644 index 57945be..0000000 --- a/taglib/taglib/toolkit/tstring.h +++ /dev/null @@ -1,543 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_STRING_H -#define TAGLIB_STRING_H - -#include "taglib_export.h" -#include "taglib.h" -#include "tbytevector.h" - -#include <string> -#include <iostream> - -/*! - * \relates TagLib::String - * - * Converts a QString to a TagLib::String without a requirement to link to Qt. - * - * \note consider conversion via usual char-by-char for loop to avoid UTF16->UTF8->UTF16 - * conversion happening in the background - */ -#define QStringToTString(s) TagLib::String(s.utf8().data(), TagLib::String::UTF8) - -/*! - * \relates TagLib::String - * - * Converts a TagLib::String to a QString without a requirement to link to Qt. - * - * \note consider conversion via usual char-by-char for loop to avoid UTF16->UTF8->UTF16 - * conversion happening in the background - * - */ -#define TStringToQString(s) QString::fromUtf8(s.toCString(true)) - -namespace TagLib { - - class StringList; - - //! A \e wide string class suitable for unicode. - - /*! - * This is an implicitly shared \e wide string. For storage it uses - * TagLib::wstring, but as this is an <i>implementation detail</i> this of - * course could change. Strings are stored internally as UTF-16(without BOM/ - * CPU byte order) - * - * The use of implicit sharing means that copying a string is cheap, the only - * \e cost comes into play when the copy is modified. Prior to that the string - * just has a pointer to the data of the \e parent String. This also makes - * this class suitable as a function return type. - * - * In addition to adding implicit sharing, this class keeps track of four - * possible encodings, which are the four supported by the ID3v2 standard. - */ - - class TAGLIB_EXPORT String - { - public: - -#ifndef DO_NOT_DOCUMENT - typedef std::basic_string<wchar>::iterator Iterator; - typedef std::basic_string<wchar>::const_iterator ConstIterator; -#endif - - /** - * The four types of string encodings supported by the ID3v2 specification. - * ID3v1 is assumed to be Latin1 and Ogg Vorbis comments use UTF8. - */ - enum Type { - /*! - * IS08859-1, or <i>Latin1</i> encoding. 8 bit characters. - */ - Latin1 = 0, - /*! - * UTF16 with a <i>byte order mark</i>. 16 bit characters. - */ - UTF16 = 1, - /*! - * UTF16 <i>big endian</i>. 16 bit characters. This is the encoding used - * internally by TagLib. - */ - UTF16BE = 2, - /*! - * UTF8 encoding. Characters are usually 8 bits but can be up to 32. - */ - UTF8 = 3, - /*! - * UTF16 <i>little endian</i>. 16 bit characters. - */ - UTF16LE = 4 - }; - - /*! - * Constructs an empty String. - */ - String(); - - /*! - * Make a shallow, implicitly shared, copy of \a s. Because this is - * implicitly shared, this method is lightweight and suitable for - * pass-by-value usage. - */ - String(const String &s); - - /*! - * Makes a deep copy of the data in \a s. - * - * \note This should only be used with the 8-bit codecs Latin1 and UTF8, when - * used with other codecs it will simply print a warning and exit. - */ - String(const std::string &s, Type t = Latin1); - - /*! - * Makes a deep copy of the data in \a s. - */ - String(const wstring &s, Type t = WCharByteOrder); - - /*! - * Makes a deep copy of the data in \a s. - */ - String(const wchar_t *s, Type t = WCharByteOrder); - - /*! - * Makes a deep copy of the data in \a c. - * - * \note This should only be used with the 8-bit codecs Latin1 and UTF8, when - * used with other codecs it will simply print a warning and exit. - */ - String(char c, Type t = Latin1); - - /*! - * Makes a deep copy of the data in \a c. - */ - String(wchar_t c, Type t = Latin1); - - - /*! - * Makes a deep copy of the data in \a s. - * - * \note This should only be used with the 8-bit codecs Latin1 and UTF8, when - * used with other codecs it will simply print a warning and exit. - */ - String(const char *s, Type t = Latin1); - - /*! - * Makes a deep copy of the data in \a s. - * - * \note This should only be used with the 8-bit codecs Latin1 and UTF8, when - * used with other codecs it will simply print a warning and exit. - */ - String(const ByteVector &v, Type t = Latin1); - - /*! - * Destroys this String instance. - */ - virtual ~String(); - - /*! - * Returns a deep copy of this String as an std::string. The returned string - * is encoded in UTF8 if \a unicode is true, otherwise Latin1. - * - * \see toCString() - */ - std::string to8Bit(bool unicode = false) const; - - /*! - * Returns a deep copy of this String as a wstring. The returned string is - * encoded in UTF-16 (without BOM/CPU byte order). - * - * \see toCWString() - */ - wstring toWString() const; - - /*! - * Creates and returns a standard C-style (null-terminated) version of this - * String. The returned string is encoded in UTF8 if \a unicode is true, - * otherwise Latin1. - * - * The returned string is still owned by this String and should not be deleted - * by the user. - * - * The returned pointer remains valid until this String instance is destroyed - * or toCString() is called again. - * - * \warning This however has the side effect that the returned string will remain - * in memory <b>in addition to</b> other memory that is consumed by this - * String instance. So, this method should not be used on large strings or - * where memory is critical. Consider using to8Bit() instead to avoid it. - * - * \see to8Bit() - */ - const char *toCString(bool unicode = false) const; - - /*! - * Returns a standard C-style (null-terminated) wide character version of - * this String. The returned string is encoded in UTF-16 (without BOM/CPU byte - * order). - * - * The returned string is still owned by this String and should not be deleted - * by the user. - * - * The returned pointer remains valid until this String instance is destroyed - * or any other method of this String is called. - * - * /note This returns a pointer to the String's internal data without any - * conversions. - * - * \see toWString() - */ - const wchar_t *toCWString() const; - - /*! - * Returns an iterator pointing to the beginning of the string. - */ - Iterator begin(); - - /*! - * Returns a const iterator pointing to the beginning of the string. - */ - ConstIterator begin() const; - - /*! - * Returns an iterator pointing to the end of the string (the position - * after the last character). - */ - Iterator end(); - - /*! - * Returns a const iterator pointing to the end of the string (the position - * after the last character). - */ - ConstIterator end() const; - - /*! - * Finds the first occurrence of pattern \a s in this string starting from - * \a offset. If the pattern is not found, -1 is returned. - */ - int find(const String &s, int offset = 0) const; - - /*! - * Finds the last occurrence of pattern \a s in this string, searched backwards, - * either from the end of the string or starting from \a offset. If the pattern - * is not found, -1 is returned. - */ - int rfind(const String &s, int offset = -1) const; - - /*! - * Splits the string on each occurrence of \a separator. - */ - StringList split(const String &separator = " ") const; - - /*! - * Returns true if the strings starts with the substring \a s. - */ - bool startsWith(const String &s) const; - - /*! - * Extract a substring from this string starting at \a position and - * continuing for \a n characters. - */ - String substr(uint position, uint n = 0xffffffff) const; - - /*! - * Append \a s to the current string and return a reference to the current - * string. - */ - String &append(const String &s); - - /*! - * Returns an upper case version of the string. - * - * \warning This only works for the characters in US-ASCII, i.e. A-Z. - */ - String upper() const; - - /*! - * Returns the size of the string. - */ - uint size() const; - - /*! - * Returns the length of the string. Equivalent to size(). - */ - uint length() const; - - /*! - * Returns true if the string is empty. - * - * \see isNull() - */ - bool isEmpty() const; - - /*! - * Returns true if this string is null -- i.e. it is a copy of the - * String::null string. - * - * \note A string can be empty and not null. - * \see isEmpty() - */ - bool isNull() const; - - /*! - * Returns a ByteVector containing the string's data. If \a t is Latin1 or - * UTF8, this will return a vector of 8 bit characters, otherwise it will use - * 16 bit characters. - */ - ByteVector data(Type t) const; - - /*! - * Convert the string to an integer. - * - * Returns the integer if the conversion was successful or 0 if the - * string does not represent a number. - */ - // BIC: merge with the method below - int toInt() const; - - /*! - * Convert the string to an integer. - * - * If the conversion was successfull, it sets the value of \a *ok to - * true and returns the integer. Otherwise it sets \a *ok to false - * and the result is undefined. - */ - int toInt(bool *ok) const; - - /*! - * Returns a string with the leading and trailing whitespace stripped. - */ - String stripWhiteSpace() const; - - /*! - * Returns true if the file only uses characters required by Latin1. - */ - bool isLatin1() const; - - /*! - * Returns true if the file only uses characters required by (7-bit) ASCII. - */ - bool isAscii() const; - - /*! - * Converts the base-10 integer \a n to a string. - */ - static String number(int n); - - /*! - * Returns a reference to the character at position \a i. - */ - wchar &operator[](int i); - - /*! - * Returns a const reference to the character at position \a i. - */ - const wchar &operator[](int i) const; - - /*! - * Compares each character of the String with each character of \a s and - * returns true if the strings match. - */ - bool operator==(const String &s) const; - - /*! - * Compares each character of the String with each character of \a s and - * returns false if the strings match. - */ - bool operator!=(const String &s) const; - - /*! - * Appends \a s to the end of the String. - */ - String &operator+=(const String &s); - - /*! - * Appends \a s to the end of the String. - */ - String &operator+=(const wchar_t* s); - - /*! - * Appends \a s to the end of the String. - */ - String &operator+=(const char* s); - - /*! - * Appends \a s to the end of the String. - */ - String &operator+=(wchar_t c); - - /*! - * Appends \a c to the end of the String. - */ - String &operator+=(char c); - - /*! - * Performs a shallow, implicitly shared, copy of \a s, overwriting the - * String's current data. - */ - String &operator=(const String &s); - - /*! - * Performs a deep copy of the data in \a s. - */ - String &operator=(const std::string &s); - - /*! - * Performs a deep copy of the data in \a s. - */ - String &operator=(const wstring &s); - - /*! - * Performs a deep copy of the data in \a s. - */ - String &operator=(const wchar_t *s); - - /*! - * Performs a deep copy of the data in \a s. - */ - String &operator=(char c); - - /*! - * Performs a deep copy of the data in \a s. - */ - String &operator=(wchar_t c); - - /*! - * Performs a deep copy of the data in \a s. - */ - String &operator=(const char *s); - - /*! - * Performs a deep copy of the data in \a v. - */ - String &operator=(const ByteVector &v); - - /*! - * To be able to use this class in a Map, this operator needed to be - * implemented. Returns true if \a s is less than this string in a bytewise - * comparison. - */ - bool operator<(const String &s) const; - - /*! - * A null string provided for convenience. - */ - static String null; - - protected: - /*! - * If this String is being shared via implicit sharing, do a deep copy of the - * data and separate from the shared members. This should be called by all - * non-const subclass members. - */ - void detach(); - - private: - /*! - * Converts a \e Latin-1 string into \e UTF-16(without BOM/CPU byte order) - * and copies it to the internal buffer. - */ - void copyFromLatin1(const char *s, size_t length); - - /*! - * Converts a \e UTF-8 string into \e UTF-16(without BOM/CPU byte order) - * and copies it to the internal buffer. - */ - void copyFromUTF8(const char *s, size_t length); - - /*! - * Converts a \e UTF-16 (with BOM), UTF-16LE or UTF16-BE string into - * \e UTF-16(without BOM/CPU byte order) and copies it to the internal buffer. - */ - void copyFromUTF16(const wchar_t *s, size_t length, Type t); - - /*! - * Converts a \e UTF-16 (with BOM), UTF-16LE or UTF16-BE string into - * \e UTF-16(without BOM/CPU byte order) and copies it to the internal buffer. - */ - void copyFromUTF16(const char *s, size_t length, Type t); - - /*! - * Indicates which byte order of UTF-16 is used to store strings internally. - * - * \note \e String::UTF16BE or \e String::UTF16LE - */ - static const Type WCharByteOrder; - - class StringPrivate; - StringPrivate *d; - }; -} - -/*! - * \relates TagLib::String - * - * Concatenates \a s1 and \a s2 and returns the result as a string. - */ -TAGLIB_EXPORT const TagLib::String operator+(const TagLib::String &s1, const TagLib::String &s2); - -/*! - * \relates TagLib::String - * - * Concatenates \a s1 and \a s2 and returns the result as a string. - */ -TAGLIB_EXPORT const TagLib::String operator+(const char *s1, const TagLib::String &s2); - -/*! - * \relates TagLib::String - * - * Concatenates \a s1 and \a s2 and returns the result as a string. - */ -TAGLIB_EXPORT const TagLib::String operator+(const TagLib::String &s1, const char *s2); - - -/*! - * \relates TagLib::String - * - * Send the string to an output stream. - */ -TAGLIB_EXPORT std::ostream &operator<<(std::ostream &s, const TagLib::String &str); - -#endif diff --git a/taglib/taglib/toolkit/tstringlist.cpp b/taglib/taglib/toolkit/tstringlist.cpp deleted file mode 100644 index 655fe6c..0000000 --- a/taglib/taglib/toolkit/tstringlist.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#include "tstringlist.h" - -using namespace TagLib; - -class StringListPrivate -{ - -}; - -//////////////////////////////////////////////////////////////////////////////// -// static members -//////////////////////////////////////////////////////////////////////////////// - -StringList StringList::split(const String &s, const String &pattern) -{ - StringList l; - - int previousOffset = 0; - for(int offset = s.find(pattern); offset != -1; offset = s.find(pattern, offset + 1)) { - l.append(s.substr(previousOffset, offset - previousOffset)); - previousOffset = offset + 1; - } - - l.append(s.substr(previousOffset, s.size() - previousOffset)); - - return l; -} - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -StringList::StringList() : List<String>() -{ - -} - -StringList::StringList(const StringList &l) : List<String>(l) -{ - -} - -StringList::StringList(const String &s) : List<String>() -{ - append(s); -} - -StringList::StringList(const ByteVectorList &bl, String::Type t) : List<String>() -{ - ByteVectorList::ConstIterator i = bl.begin(); - for(;i != bl.end(); i++) { - append(String(*i, t)); - } -} - -StringList::~StringList() -{ - -} - -String StringList::toString(const String &separator) const -{ - String s; - - ConstIterator it = begin(); - ConstIterator itEnd = end(); - - while(it != itEnd) { - s += *it; - it++; - if(it != itEnd) - s += separator; - } - - return s; -} - -StringList &StringList::append(const String &s) -{ - List<String>::append(s); - return *this; -} - -StringList &StringList::append(const StringList &l) -{ - List<String>::append(l); - return *this; -} - -//////////////////////////////////////////////////////////////////////////////// -// related functions -//////////////////////////////////////////////////////////////////////////////// - -std::ostream &operator<<(std::ostream &s, const StringList &l) -{ - s << l.toString(); - return s; -} diff --git a/taglib/taglib/toolkit/tstringlist.h b/taglib/taglib/toolkit/tstringlist.h deleted file mode 100644 index f94b50f..0000000 --- a/taglib/taglib/toolkit/tstringlist.h +++ /dev/null @@ -1,115 +0,0 @@ -/*************************************************************************** - copyright : (C) 2002 - 2008 by Scott Wheeler - email : wheeler@kde.org - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_STRINGLIST_H -#define TAGLIB_STRINGLIST_H - -#include "tstring.h" -#include "tlist.h" -#include "tbytevectorlist.h" -#include "taglib_export.h" - -#include <iostream> - -namespace TagLib { - - //! A list of strings - - /*! - * This is a spcialization of the List class with some members convention for - * string operations. - */ - - class TAGLIB_EXPORT StringList : public List<String> - { - public: - - /*! - * Constructs an empty StringList. - */ - StringList(); - - /*! - * Make a shallow, implicitly shared, copy of \a l. Because this is - * implicitly shared, this method is lightweight and suitable for - * pass-by-value usage. - */ - StringList(const StringList &l); - - /*! - * Constructs a StringList with \a s as a member. - */ - StringList(const String &s); - - /*! - * Makes a deep copy of the data in \a vl. - * - * \note This should only be used with the 8-bit codecs Latin1 and UTF8, when - * used with other codecs it will simply print a warning and exit. - */ - StringList(const ByteVectorList &vl, String::Type t = String::Latin1); - - /*! - * Destroys this StringList instance. - */ - virtual ~StringList(); - - /*! - * Concatenate the list of strings into one string separated by \a separator. - */ - String toString(const String &separator = " ") const; - - /*! - * Appends \a s to the end of the list and returns a reference to the - * list. - */ - StringList &append(const String &s); - - /*! - * Appends all of the values in \a l to the end of the list and returns a - * reference to the list. - */ - StringList &append(const StringList &l); - - /*! - * Splits the String \a s into several strings at \a pattern. This will not include - * the pattern in the returned strings. - */ - static StringList split(const String &s, const String &pattern); - - private: - class StringListPrivate; - StringListPrivate *d; - }; - -} - -/*! - * \related TagLib::StringList - * Send the StringList to an output stream. - */ -std::ostream &operator<<(std::ostream &s, const TagLib::StringList &l); - -#endif diff --git a/taglib/taglib/toolkit/tutils.h b/taglib/taglib/toolkit/tutils.h deleted file mode 100644 index 4a398d2..0000000 --- a/taglib/taglib/toolkit/tutils.h +++ /dev/null @@ -1,190 +0,0 @@ -/*************************************************************************** - copyright : (C) 2013 by Tsuda Kageyu - email : tsuda.kageyu@gmail.com - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * - * 02110-1301 USA * - * * - * Alternatively, this file is available under the Mozilla Public * - * License Version 1.1. You may obtain a copy of the License at * - * http://www.mozilla.org/MPL/ * - ***************************************************************************/ - -#ifndef TAGLIB_TUTILS_H -#define TAGLIB_TUTILS_H - -// THIS FILE IS NOT A PART OF THE TAGLIB API - -#ifndef DO_NOT_DOCUMENT // tell Doxygen not to document this header - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#if defined(HAVE_MSC_BYTESWAP) -# include <stdlib.h> -#elif defined(HAVE_GLIBC_BYTESWAP) -# include <byteswap.h> -#elif defined(HAVE_MAC_BYTESWAP) -# include <libkern/OSByteOrder.h> -#elif defined(HAVE_OPENBSD_BYTESWAP) -# include <sys/endian.h> -#endif - -namespace TagLib -{ - namespace Utils - { - inline ushort byteSwap(ushort x) - { -#if defined(HAVE_GCC_BYTESWAP_16) - - return __builtin_bswap16(x); - -#elif defined(HAVE_MSC_BYTESWAP) - - return _byteswap_ushort(x); - -#elif defined(HAVE_GLIBC_BYTESWAP) - - return __bswap_16(x); - -#elif defined(HAVE_MAC_BYTESWAP) - - return OSSwapInt16(x); - -#elif defined(HAVE_OPENBSD_BYTESWAP) - - return swap16(x); - -#else - - return ((x >> 8) & 0xff) | ((x & 0xff) << 8); - -#endif - } - - inline uint byteSwap(uint x) - { -#if defined(HAVE_GCC_BYTESWAP_32) - - return __builtin_bswap32(x); - -#elif defined(HAVE_MSC_BYTESWAP) - - return _byteswap_ulong(x); - -#elif defined(HAVE_GLIBC_BYTESWAP) - - return __bswap_32(x); - -#elif defined(HAVE_MAC_BYTESWAP) - - return OSSwapInt32(x); - -#elif defined(HAVE_OPENBSD_BYTESWAP) - - return swap32(x); - -#else - - return ((x & 0xff000000u) >> 24) - | ((x & 0x00ff0000u) >> 8) - | ((x & 0x0000ff00u) << 8) - | ((x & 0x000000ffu) << 24); - -#endif - } - - inline ulonglong byteSwap(ulonglong x) - { -#if defined(HAVE_GCC_BYTESWAP_64) - - return __builtin_bswap64(x); - -#elif defined(HAVE_MSC_BYTESWAP) - - return _byteswap_uint64(x); - -#elif defined(HAVE_GLIBC_BYTESWAP) - - return __bswap_64(x); - -#elif defined(HAVE_MAC_BYTESWAP) - - return OSSwapInt64(x); - -#elif defined(HAVE_OPENBSD_BYTESWAP) - - return swap64(x); - -#else - - return ((x & 0xff00000000000000ull) >> 56) - | ((x & 0x00ff000000000000ull) >> 40) - | ((x & 0x0000ff0000000000ull) >> 24) - | ((x & 0x000000ff00000000ull) >> 8) - | ((x & 0x00000000ff000000ull) << 8) - | ((x & 0x0000000000ff0000ull) << 24) - | ((x & 0x000000000000ff00ull) << 40) - | ((x & 0x00000000000000ffull) << 56); - -#endif - } - - enum ByteOrder - { - LittleEndian, - BigEndian - }; - -#ifdef SYSTEM_BYTEORDER - -# if SYSTEM_BYTEORDER == 1 - - const ByteOrder SystemByteOrder = LittleEndian; - -# else - - const ByteOrder SystemByteOrder = BigEndian; - -# endif - -#else - - inline ByteOrder systemByteOrder() - { - union { - int i; - char c; - } u; - - u.i = 1; - if(u.c == 1) - return LittleEndian; - else - return BigEndian; - } - - const ByteOrder SystemByteOrder = systemByteOrder(); - -#endif - } -} - -#endif - -#endif diff --git a/taglib/taglib/toolkit/unicode.cpp b/taglib/taglib/toolkit/unicode.cpp deleted file mode 100644 index 1b26977..0000000 --- a/taglib/taglib/toolkit/unicode.cpp +++ /dev/null @@ -1,303 +0,0 @@ -/******************************************************************************* - * * - * THIS FILE IS INCLUDED IN TAGLIB, BUT IS NOT COPYRIGHTED BY THE TAGLIB * - * AUTHORS, NOT PART OF THE TAGLIB API AND COULD GO AWAY AT ANY POINT IN TIME. * - * AS SUCH IT SHOULD BE CONSIERED FOR INTERNAL USE ONLY. * - * * - *******************************************************************************/ - -/* - * Copyright 2001 Unicode, Inc. - * - * Disclaimer - * - * This source code is provided as is by Unicode, Inc. No claims are - * made as to fitness for any particular purpose. No warranties of any - * kind are expressed or implied. The recipient agrees to determine - * applicability of information provided. If this file has been - * purchased on magnetic or optical media from Unicode, Inc., the - * sole remedy for any claim will be exchange of defective media - * within 90 days of receipt. - * - * Limitations on Rights to Redistribute This Code - * - * Unicode, Inc. hereby grants the right to freely use the information - * supplied in this file in the creation of products supporting the - * Unicode Standard, and to make copies of this file in any form - * for internal or external distribution as long as this notice - * remains attached. - */ - -/* - * This file has been modified by Scott Wheeler <wheeler@kde.org> to remove - * the UTF32 conversion functions and to place the appropriate functions - * in their own C++ namespace. - */ - -/* --------------------------------------------------------------------- - - Conversions between UTF32, UTF-16, and UTF-8. Source code file. - Author: Mark E. Davis, 1994. - Rev History: Rick McGowan, fixes & updates May 2001. - Sept 2001: fixed const & error conditions per - mods suggested by S. Parent & A. Lillich. - - See the header file "ConvertUTF.h" for complete documentation. - ------------------------------------------------------------------------- */ - - -#include "unicode.h" -#include <stdio.h> - -#define UNI_SUR_HIGH_START (UTF32)0xD800 -#define UNI_SUR_HIGH_END (UTF32)0xDBFF -#define UNI_SUR_LOW_START (UTF32)0xDC00 -#define UNI_SUR_LOW_END (UTF32)0xDFFF -#define false 0 -#define true 1 - -namespace Unicode { - -static const int halfShift = 10; /* used for shifting by 10 bits */ - -static const UTF32 halfBase = 0x0010000UL; -static const UTF32 halfMask = 0x3FFUL; - -/* - * Index into the table below with the first byte of a UTF-8 sequence to - * get the number of trailing bytes that are supposed to follow it. - */ -static const char trailingBytesForUTF8[256] = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 -}; - -/* - * Magic values subtracted from a buffer value during UTF8 conversion. - * This table contains as many values as there might be trailing bytes - * in a UTF-8 sequence. - */ -static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, - 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; - -/* - * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed - * into the first byte, depending on how many bytes follow. There are - * as many entries in this table as there are UTF-8 sequence types. - * (I.e., one byte sequence, two byte... six byte sequence.) - */ -static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; - -/* --------------------------------------------------------------------- */ - -/* The interface converts a whole buffer to avoid function-call overhead. - * Constants have been gathered. Loops & conditionals have been removed as - * much as possible for efficiency, in favor of drop-through switches. - * (See "Note A" at the bottom of the file for equivalent code.) - * If your compiler supports it, the "isLegalUTF8" call can be turned - * into an inline function. - */ - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF16toUTF8 ( - const UTF16** sourceStart, const UTF16* sourceEnd, - UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF16* source = *sourceStart; - UTF8* target = *targetStart; - while (source < sourceEnd) { - UTF32 ch; - unsigned short bytesToWrite = 0; - const UTF32 byteMask = 0xBF; - const UTF32 byteMark = 0x80; - const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ - ch = *source++; - /* If we have a surrogate pair, convert to UTF32 first. */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END && source < sourceEnd) { - UTF32 ch2 = *source; - if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { - ch = ((ch - UNI_SUR_HIGH_START) << halfShift) - + (ch2 - UNI_SUR_LOW_START) + halfBase; - ++source; - } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } else if ((flags == strictConversion) && (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END)) { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - /* Figure out how many bytes the result will require */ - if (ch < (UTF32)0x80) { bytesToWrite = 1; - } else if (ch < (UTF32)0x800) { bytesToWrite = 2; - } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; - } else if (ch < (UTF32)0x200000) { bytesToWrite = 4; - } else { bytesToWrite = 2; - ch = UNI_REPLACEMENT_CHAR; - } - // printf("bytes to write = %i\n", bytesToWrite); - target += bytesToWrite; - if (target > targetEnd) { - source = oldSource; /* Back up source pointer! */ - target -= bytesToWrite; result = targetExhausted; break; - } - switch (bytesToWrite) { /* note: everything falls through. */ - case 4: *--target = (ch | byteMark) & byteMask; ch >>= 6; - case 3: *--target = (ch | byteMark) & byteMask; ch >>= 6; - case 2: *--target = (ch | byteMark) & byteMask; ch >>= 6; - case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]); - } - target += bytesToWrite; - } - *sourceStart = source; - *targetStart = target; - return result; -} - -/* --------------------------------------------------------------------- */ - -/* - * Utility routine to tell whether a sequence of bytes is legal UTF-8. - * This must be called with the length pre-determined by the first byte. - * If not calling this from ConvertUTF8to*, then the length can be set by: - * length = trailingBytesForUTF8[*source]+1; - * and the sequence is illegal right away if there aren't that many bytes - * available. - * If presented with a length > 4, this returns false. The Unicode - * definition of UTF-8 goes up to 4-byte sequences. - */ - -static Boolean isLegalUTF8(const UTF8 *source, int length) { - UTF8 a; - const UTF8 *srcptr = source+length; - switch (length) { - default: return false; - /* Everything else falls through when "true"... */ - case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; - case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; - case 2: if ((a = (*--srcptr)) > 0xBF) return false; - switch (*source) { - /* no fall-through in this inner switch */ - case 0xE0: if (a < 0xA0) return false; break; - case 0xF0: if (a < 0x90) return false; break; - case 0xF4: if (a > 0x8F) return false; break; - default: if (a < 0x80) return false; - } - case 1: if (*source >= 0x80 && *source < 0xC2) return false; - if (*source > 0xF4) return false; - } - return true; -} - -/* --------------------------------------------------------------------- */ - -/* - * Exported function to return whether a UTF-8 sequence is legal or not. - * This is not used here; it's just exported. - */ -Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) { - int length = trailingBytesForUTF8[*source]+1; - if (source+length > sourceEnd) { - return false; - } - return isLegalUTF8(source, length); -} - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF8toUTF16 ( - const UTF8** sourceStart, const UTF8* sourceEnd, - UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF8* source = *sourceStart; - UTF16* target = *targetStart; - while (source < sourceEnd) { - UTF32 ch = 0; - unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; - if (source + extraBytesToRead >= sourceEnd) { - result = sourceExhausted; break; - } - /* Do this check whether lenient or strict */ - if (! isLegalUTF8(source, extraBytesToRead+1)) { - result = sourceIllegal; - break; - } - /* - * The cases all fall through. See "Note A" below. - */ - switch (extraBytesToRead) { - case 3: ch += *source++; ch <<= 6; - case 2: ch += *source++; ch <<= 6; - case 1: ch += *source++; ch <<= 6; - case 0: ch += *source++; - } - ch -= offsetsFromUTF8[extraBytesToRead]; - - if (target >= targetEnd) { - source -= (extraBytesToRead+1); /* Back up source pointer! */ - result = targetExhausted; break; - } - if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ - if ((flags == strictConversion) && (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END)) { - source -= (extraBytesToRead+1); /* return to the illegal value itself */ - result = sourceIllegal; - break; - } else { - *target++ = (UTF16)ch; /* normal case */ - } - } else if (ch > UNI_MAX_UTF16) { - if (flags == strictConversion) { - result = sourceIllegal; - source -= (extraBytesToRead+1); /* return to the start */ - break; /* Bail out; shouldn't continue */ - } else { - *target++ = UNI_REPLACEMENT_CHAR; - } - } else { - /* target is a character in range 0xFFFF - 0x10FFFF. */ - if (target + 1 >= targetEnd) { - source -= (extraBytesToRead+1); /* Back up source pointer! */ - result = targetExhausted; break; - } - ch -= halfBase; - *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); - *target++ = (ch & halfMask) + UNI_SUR_LOW_START; - } - } - *sourceStart = source; - *targetStart = target; - return result; -} - -} - -/* --------------------------------------------------------------------- - - Note A. - The fall-through switches in UTF-8 reading code save a - temp variable, some decrements & conditionals. The switches - are equivalent to the following loop: - { - int tmpBytesToRead = extraBytesToRead+1; - do { - ch += *source++; - --tmpBytesToRead; - if (tmpBytesToRead) ch <<= 6; - } while (tmpBytesToRead > 0); - } - In UTF-8 writing code, the switches on "bytesToWrite" are - similarly unrolled loops. - - --------------------------------------------------------------------- */ - - diff --git a/taglib/taglib/toolkit/unicode.h b/taglib/taglib/toolkit/unicode.h deleted file mode 100644 index ebf1915..0000000 --- a/taglib/taglib/toolkit/unicode.h +++ /dev/null @@ -1,154 +0,0 @@ -#ifndef TAGLIB_UNICODE_H -#define TAGLIB_UNICODE_H - -/******************************************************************************* - * * - * THIS FILE IS INCLUDED IN TAGLIB, BUT IS NOT COPYRIGHTED BY THE TAGLIB * - * AUTHORS, NOT PART OF THE TAGLIB API AND COULD GO AWAY AT ANY POINT IN TIME. * - * AS SUCH IT SHOULD BE CONSIERED FOR INTERNAL USE ONLY. * - * * - *******************************************************************************/ - -#ifndef DO_NOT_DOCUMENT // tell Doxygen not to document this header - -/* - * Copyright 2001 Unicode, Inc. - * - * Disclaimer - * - * This source code is provided as is by Unicode, Inc. No claims are - * made as to fitness for any particular purpose. No warranties of any - * kind are expressed or implied. The recipient agrees to determine - * applicability of information provided. If this file has been - * purchased on magnetic or optical media from Unicode, Inc., the - * sole remedy for any claim will be exchange of defective media - * within 90 days of receipt. - * - * Limitations on Rights to Redistribute This Code - * - * Unicode, Inc. hereby grants the right to freely use the information - * supplied in this file in the creation of products supporting the - * Unicode Standard, and to make copies of this file in any form - * for internal or external distribution as long as this notice - * remains attached. - */ - -/* - * This file has been modified by Scott Wheeler <wheeler@kde.org> to remove - * the UTF32 conversion functions and to place the appropriate functions - * in their own C++ namespace. - */ - -/* --------------------------------------------------------------------- - - Conversions between UTF32, UTF-16, and UTF-8. Header file. - - Several functions are included here, forming a complete set of - conversions between the three formats. UTF-7 is not included - here, but is handled in a separate source file. - - Each of these routines takes pointers to input buffers and output - buffers. The input buffers are const. - - Each routine converts the text between *sourceStart and sourceEnd, - putting the result into the buffer between *targetStart and - targetEnd. Note: the end pointers are *after* the last item: e.g. - *(sourceEnd - 1) is the last item. - - The return result indicates whether the conversion was successful, - and if not, whether the problem was in the source or target buffers. - (Only the first encountered problem is indicated.) - - After the conversion, *sourceStart and *targetStart are both - updated to point to the end of last text successfully converted in - the respective buffers. - - Input parameters: - sourceStart - pointer to a pointer to the source buffer. - The contents of this are modified on return so that - it points at the next thing to be converted. - targetStart - similarly, pointer to pointer to the target buffer. - sourceEnd, targetEnd - respectively pointers to the ends of the - two buffers, for overflow checking only. - - These conversion functions take a ConversionFlags argument. When this - flag is set to strict, both irregular sequences and isolated surrogates - will cause an error. When the flag is set to lenient, both irregular - sequences and isolated surrogates are converted. - - Whether the flag is strict or lenient, all illegal sequences will cause - an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>, - or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code - must check for illegal sequences. - - When the flag is set to lenient, characters over 0x10FFFF are converted - to the replacement character; otherwise (when the flag is set to strict) - they constitute an error. - - Output parameters: - The value "sourceIllegal" is returned from some routines if the input - sequence is malformed. When "sourceIllegal" is returned, the source - value will point to the illegal value that caused the problem. E.g., - in UTF-8 when a sequence is malformed, it points to the start of the - malformed sequence. - - Author: Mark E. Davis, 1994. - Rev History: Rick McGowan, fixes & updates May 2001. - Fixes & updates, Sept 2001. - ------------------------------------------------------------------------- */ - -/* --------------------------------------------------------------------- - The following 4 definitions are compiler-specific. - The C standard does not guarantee that wchar_t has at least - 16 bits, so wchar_t is no less portable than unsigned short! - All should be unsigned values to avoid sign extension during - bit mask & shift operations. ------------------------------------------------------------------------- */ - -// Workaround for when MSVC doesn't have wchar_t as a built-in type. -#if defined(_MSC_VER) && !defined(_WCHAR_T_DEFINED) -# include <wchar.h> -#endif - -/* Some fundamental constants */ -#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD -#define UNI_MAX_BMP (UTF32)0x0000FFFF -#define UNI_MAX_UTF16 (UTF32)0x0010FFFF -#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF - -namespace Unicode { - -typedef unsigned long UTF32; /* at least 32 bits */ -typedef wchar_t UTF16; /* TagLib assumes that wchar_t is sufficient for UTF-16. */ -typedef unsigned char UTF8; /* typically 8 bits */ -typedef unsigned char Boolean; /* 0 or 1 */ - -typedef enum { - conversionOK = 0, /* conversion successful */ - sourceExhausted = 1, /* partial character in source, but hit end */ - targetExhausted = 2, /* insuff. room in target for conversion */ - sourceIllegal = 3 /* source sequence is illegal/malformed */ -} ConversionResult; - -typedef enum { - strictConversion = 0, - lenientConversion -} ConversionFlags; - -ConversionResult ConvertUTF8toUTF16 ( - const UTF8** sourceStart, const UTF8* sourceEnd, - UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); - -ConversionResult ConvertUTF16toUTF8 ( - const UTF16** sourceStart, const UTF16* sourceEnd, - UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); - -Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd); - -} // namespace Unicode - -/* --------------------------------------------------------------------- */ - -#endif -#endif diff --git a/taglib/taglib/trueaudio/trueaudiofile.cpp b/taglib/taglib/trueaudio/trueaudiofile.cpp deleted file mode 100644 index f98d6ad..0000000 --- a/taglib/taglib/trueaudio/trueaudiofile.cpp +++ /dev/null @@ -1,325 +0,0 @@ -/*************************************************************************** - copyright : (C) 2006 by Lukáš Lalinský - email : lalinsky@gmail.com - - copyright : (C) 2004 by Allan Sandfeld Jensen - email : kde@carewolf.org - (original MPC 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 <tbytevector.h> -#include <tstring.h> -#include <tdebug.h> -#include <tagunion.h> -#include <tstringlist.h> -#include <tpropertymap.h> - -#include "trueaudiofile.h" -#include "id3v1tag.h" -#include "id3v2tag.h" -#include "id3v2header.h" - -using namespace TagLib; - -namespace -{ - enum { TrueAudioID3v2Index = 0, TrueAudioID3v1Index = 1 }; -} - -class TrueAudio::File::FilePrivate -{ -public: - FilePrivate(const ID3v2::FrameFactory *frameFactory = ID3v2::FrameFactory::instance()) : - ID3v2FrameFactory(frameFactory), - ID3v2Location(-1), - ID3v2OriginalSize(0), - ID3v1Location(-1), - properties(0), - hasID3v1(false), - hasID3v2(false) {} - - ~FilePrivate() - { - delete properties; - } - - const ID3v2::FrameFactory *ID3v2FrameFactory; - long ID3v2Location; - uint ID3v2OriginalSize; - - long ID3v1Location; - - TagUnion tag; - - Properties *properties; - - // These indicate whether the file *on disk* has these tags, not if - // this data structure does. This is used in computing offsets. - - bool hasID3v1; - bool hasID3v2; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -TrueAudio::File::File(FileName file, bool readProperties, - Properties::ReadStyle propertiesStyle) : TagLib::File(file) -{ - d = new FilePrivate; - if(isOpen()) - read(readProperties, propertiesStyle); -} - -TrueAudio::File::File(FileName file, ID3v2::FrameFactory *frameFactory, - bool readProperties, Properties::ReadStyle propertiesStyle) : - TagLib::File(file) -{ - d = new FilePrivate(frameFactory); - if(isOpen()) - read(readProperties, propertiesStyle); -} - -TrueAudio::File::File(IOStream *stream, bool readProperties, - Properties::ReadStyle propertiesStyle) : TagLib::File(stream) -{ - d = new FilePrivate; - if(isOpen()) - read(readProperties, propertiesStyle); -} - -TrueAudio::File::File(IOStream *stream, ID3v2::FrameFactory *frameFactory, - bool readProperties, Properties::ReadStyle propertiesStyle) : - TagLib::File(stream) -{ - d = new FilePrivate(frameFactory); - if(isOpen()) - read(readProperties, propertiesStyle); -} - -TrueAudio::File::~File() -{ - delete d; -} - -TagLib::Tag *TrueAudio::File::tag() const -{ - return &d->tag; -} - -PropertyMap TrueAudio::File::properties() const -{ - // once Tag::properties() is virtual, this case distinction could actually be done - // within TagUnion. - if(d->hasID3v2) - return d->tag.access<ID3v2::Tag>(TrueAudioID3v2Index, false)->properties(); - if(d->hasID3v1) - return d->tag.access<ID3v1::Tag>(TrueAudioID3v1Index, false)->properties(); - return PropertyMap(); -} - -void TrueAudio::File::removeUnsupportedProperties(const StringList &unsupported) -{ - if(d->hasID3v2) - d->tag.access<ID3v2::Tag>(TrueAudioID3v2Index, false)->removeUnsupportedProperties(unsupported); -} - -PropertyMap TrueAudio::File::setProperties(const PropertyMap &properties) -{ - if(d->hasID3v1) - d->tag.access<ID3v1::Tag>(TrueAudioID3v1Index, false)->setProperties(properties); - return d->tag.access<ID3v2::Tag>(TrueAudioID3v2Index, true)->setProperties(properties); -} - -TrueAudio::Properties *TrueAudio::File::audioProperties() const -{ - return d->properties; -} - -void TrueAudio::File::setID3v2FrameFactory(const ID3v2::FrameFactory *factory) -{ - d->ID3v2FrameFactory = factory; -} - -bool TrueAudio::File::save() -{ - if(readOnly()) { - debug("TrueAudio::File::save() -- File is read only."); - return false; - } - - // Update ID3v2 tag - - if(ID3v2Tag() && !ID3v2Tag()->isEmpty()) { - if(!d->hasID3v2) { - d->ID3v2Location = 0; - d->ID3v2OriginalSize = 0; - } - ByteVector data = ID3v2Tag()->render(); - insert(data, d->ID3v2Location, d->ID3v2OriginalSize); - d->ID3v1Location -= d->ID3v2OriginalSize - data.size(); - d->ID3v2OriginalSize = data.size(); - d->hasID3v2 = true; - } - else if(d->hasID3v2) { - removeBlock(d->ID3v2Location, d->ID3v2OriginalSize); - d->ID3v1Location -= d->ID3v2OriginalSize; - d->ID3v2Location = -1; - d->ID3v2OriginalSize = 0; - d->hasID3v2 = false; - } - - // Update ID3v1 tag - - if(ID3v1Tag() && !ID3v1Tag()->isEmpty()) { - if(!d->hasID3v1) { - seek(0, End); - d->ID3v1Location = tell(); - } - else - seek(d->ID3v1Location); - writeBlock(ID3v1Tag()->render()); - d->hasID3v1 = true; - } - else if(d->hasID3v1) { - removeBlock(d->ID3v1Location, 128); - d->ID3v1Location = -1; - d->hasID3v1 = false; - } - - return true; -} - -ID3v1::Tag *TrueAudio::File::ID3v1Tag(bool create) -{ - return d->tag.access<ID3v1::Tag>(TrueAudioID3v1Index, create); -} - -ID3v2::Tag *TrueAudio::File::ID3v2Tag(bool create) -{ - return d->tag.access<ID3v2::Tag>(TrueAudioID3v2Index, create); -} - -void TrueAudio::File::strip(int tags) -{ - if(tags & ID3v1) { - d->tag.set(TrueAudioID3v1Index, 0); - ID3v2Tag(true); - } - - if(tags & ID3v2) { - d->tag.set(TrueAudioID3v2Index, 0); - - if(!ID3v1Tag()) - ID3v2Tag(true); - } -} - -bool TrueAudio::File::hasID3v1Tag() const -{ - return d->hasID3v1; -} - -bool TrueAudio::File::hasID3v2Tag() const -{ - return d->hasID3v2; -} - - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -void TrueAudio::File::read(bool readProperties, Properties::ReadStyle /* propertiesStyle */) -{ - // Look for an ID3v2 tag - - d->ID3v2Location = findID3v2(); - - if(d->ID3v2Location >= 0) { - - d->tag.set(TrueAudioID3v2Index, new ID3v2::Tag(this, d->ID3v2Location, d->ID3v2FrameFactory)); - - d->ID3v2OriginalSize = ID3v2Tag()->header()->completeTagSize(); - - if(ID3v2Tag()->header()->tagSize() <= 0) - d->tag.set(TrueAudioID3v2Index, 0); - else - d->hasID3v2 = true; - } - - // Look for an ID3v1 tag - - d->ID3v1Location = findID3v1(); - - if(d->ID3v1Location >= 0) { - d->tag.set(TrueAudioID3v1Index, new ID3v1::Tag(this, d->ID3v1Location)); - d->hasID3v1 = true; - } - - if(!d->hasID3v1) - ID3v2Tag(true); - - // Look for TrueAudio metadata - - if(readProperties) { - if(d->ID3v2Location >= 0) { - seek(d->ID3v2Location + d->ID3v2OriginalSize); - d->properties = new Properties(readBlock(TrueAudio::HeaderSize), - length() - d->ID3v2OriginalSize); - } - else { - seek(0); - d->properties = new Properties(readBlock(TrueAudio::HeaderSize), - length()); - } - } -} - -long TrueAudio::File::findID3v1() -{ - if(!isValid()) - return -1; - - seek(-128, End); - long p = tell(); - - if(readBlock(3) == ID3v1::Tag::fileIdentifier()) - return p; - - return -1; -} - -long TrueAudio::File::findID3v2() -{ - if(!isValid()) - return -1; - - seek(0); - - if(readBlock(3) == ID3v2::Header::fileIdentifier()) - return 0; - - return -1; -} diff --git a/taglib/taglib/trueaudio/trueaudiofile.h b/taglib/taglib/trueaudio/trueaudiofile.h deleted file mode 100644 index dbaafcd..0000000 --- a/taglib/taglib/trueaudio/trueaudiofile.h +++ /dev/null @@ -1,252 +0,0 @@ -/*************************************************************************** - copyright : (C) 2006 by Lukáš Lalinský - email : lalinsky@gmail.com - - copyright : (C) 2004 by Allan Sandfeld Jensen - email : kde@carewolf.org - (original MPC 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_TRUEAUDIOFILE_H -#define TAGLIB_TRUEAUDIOFILE_H - -#include "tfile.h" -#include "trueaudioproperties.h" - -namespace TagLib { - - class Tag; - - namespace ID3v2 { class Tag; class FrameFactory; } - namespace ID3v1 { class Tag; } - - //! An implementation of TrueAudio metadata - - /*! - * This is implementation of TrueAudio metadata. - * - * This supports ID3v1 and ID3v2 tags as well as reading stream - * properties from the file. - */ - - namespace TrueAudio { - - //! An implementation of TagLib::File with TrueAudio specific methods - - /*! - * This implements and provides an interface for TrueAudio 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 TrueAudio files. - */ - - class TAGLIB_EXPORT File : public TagLib::File - { - public: - /*! - * This set of flags is used for various operations and is suitable for - * being OR-ed together. - */ - enum TagTypes { - //! Empty set. Matches no tag types. - NoTags = 0x0000, - //! Matches ID3v1 tags. - ID3v1 = 0x0001, - //! Matches ID3v2 tags. - ID3v2 = 0x0002, - //! Matches all tag types. - AllTags = 0xffff - }; - - /*! - * Constructs a TrueAudio 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 a TrueAudio 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. - */ - File(FileName file, ID3v2::FrameFactory *frameFactory, - bool readProperties = true, - Properties::ReadStyle propertiesStyle = Properties::Average); - - /*! - * Constructs a TrueAudio 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); - - /*! - * Constructs a TrueAudio 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. - */ - File(IOStream *stream, ID3v2::FrameFactory *frameFactory, - bool readProperties = true, - Properties::ReadStyle propertiesStyle = Properties::Average); - - /*! - * Destroys this instance of the File. - */ - virtual ~File(); - - /*! - * Returns the Tag for this file. - */ - virtual TagLib::Tag *tag() const; - - /*! - * Implements the unified property interface -- export function. - * If the file contains both ID3v1 and v2 tags, only ID3v2 will be - * converted to the PropertyMap. - */ - PropertyMap properties() const; - - /*! - * Implements the unified property interface -- import function. - * Creates in ID3v2 tag if necessary. If an ID3v1 tag exists, it will - * be updated as well, within the limitations of ID3v1. - */ - PropertyMap setProperties(const PropertyMap &); - - void removeUnsupportedProperties(const StringList &properties); - - /*! - * Returns the TrueAudio::Properties for this file. If no audio properties - * were read then this will return a null pointer. - */ - virtual Properties *audioProperties() const; - - /*! - * Set the ID3v2::FrameFactory to something other than the default. - * - * \see ID3v2FrameFactory - */ - void setID3v2FrameFactory(const ID3v2::FrameFactory *factory); - - /*! - * Saves the file. - */ - virtual bool save(); - - /*! - * Returns a pointer to the ID3v1 tag of the file. - * - * 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 ID3v2 tag of the file. - * - * 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); - - /*! - * This will remove the tags that match the OR-ed together TagTypes from the - * file. By default it removes all tags. - * - * \note This will also invalidate pointers to the tags - * as their memory will be freed. - * \note In order to make the removal permanent save() still needs to be called - */ - void strip(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 ID3v2 tag. - * - * \see ID3v2Tag() - */ - bool hasID3v2Tag() const; - - private: - File(const File &); - File &operator=(const File &); - - void read(bool readProperties, Properties::ReadStyle propertiesStyle); - void scan(); - long findID3v1(); - long findID3v2(); - - class FilePrivate; - FilePrivate *d; - }; - } -} - -#endif diff --git a/taglib/taglib/trueaudio/trueaudioproperties.cpp b/taglib/taglib/trueaudio/trueaudioproperties.cpp deleted file mode 100644 index dedd74e..0000000 --- a/taglib/taglib/trueaudio/trueaudioproperties.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/*************************************************************************** - copyright : (C) 2006 by Lukáš Lalinský - email : lalinsky@gmail.com - - copyright : (C) 2004 by Allan Sandfeld Jensen - email : kde@carewolf.org - (original MPC 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 <bitset> - -#include "trueaudioproperties.h" -#include "trueaudiofile.h" - -using namespace TagLib; - -class TrueAudio::Properties::PropertiesPrivate -{ -public: - PropertiesPrivate(const ByteVector &d, long length, ReadStyle s) : - data(d), - streamLength(length), - style(s), - version(0), - length(0), - bitrate(0), - sampleRate(0), - channels(0), - bitsPerSample(0), - sampleFrames(0) {} - - ByteVector data; - long streamLength; - ReadStyle style; - int version; - int length; - int bitrate; - int sampleRate; - int channels; - int bitsPerSample; - uint sampleFrames; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -TrueAudio::Properties::Properties(const ByteVector &data, long streamLength, ReadStyle style) : AudioProperties(style) -{ - d = new PropertiesPrivate(data, streamLength, style); - read(); -} - -TrueAudio::Properties::~Properties() -{ - delete d; -} - -int TrueAudio::Properties::length() const -{ - return d->length; -} - -int TrueAudio::Properties::bitrate() const -{ - return d->bitrate; -} - -int TrueAudio::Properties::sampleRate() const -{ - return d->sampleRate; -} - -int TrueAudio::Properties::bitsPerSample() const -{ - return d->bitsPerSample; -} - -int TrueAudio::Properties::channels() const -{ - return d->channels; -} - -TagLib::uint TrueAudio::Properties::sampleFrames() const -{ - return d->sampleFrames; -} - -int TrueAudio::Properties::ttaVersion() const -{ - return d->version; -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -void TrueAudio::Properties::read() -{ - if(!d->data.startsWith("TTA")) - return; - - int pos = 3; - - d->version = d->data[pos] - '0'; - pos += 1; - - // According to http://en.true-audio.com/TTA_Lossless_Audio_Codec_-_Format_Description - // TTA2 headers are in development, and have a different format - if(1 == d->version) { - // Skip the audio format - pos += 2; - - d->channels = d->data.toShort(pos, false); - pos += 2; - - d->bitsPerSample = d->data.toShort(pos, false); - pos += 2; - - d->sampleRate = d->data.toUInt(pos, false); - pos += 4; - - d->sampleFrames = d->data.toUInt(pos, false); - d->length = d->sampleRate > 0 ? d->sampleFrames / d->sampleRate : 0; - - d->bitrate = d->length > 0 ? ((d->streamLength * 8L) / d->length) / 1000 : 0; - } -} diff --git a/taglib/taglib/trueaudio/trueaudioproperties.h b/taglib/taglib/trueaudio/trueaudioproperties.h deleted file mode 100644 index 126b678..0000000 --- a/taglib/taglib/trueaudio/trueaudioproperties.h +++ /dev/null @@ -1,98 +0,0 @@ -/*************************************************************************** - copyright : (C) 2006 by Lukáš Lalinský - email : lalinsky@gmail.com - - copyright : (C) 2004 by Allan Sandfeld Jensen - email : kde@carewolf.org - (original MPC 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_TRUEAUDIOPROPERTIES_H -#define TAGLIB_TRUEAUDIOPROPERTIES_H - -#include "audioproperties.h" - -namespace TagLib { - - namespace TrueAudio { - - class File; - - static const uint HeaderSize = 18; - - //! An implementation of audio property reading for TrueAudio - - /*! - * This reads the data from an TrueAudio stream found in the AudioProperties - * API. - */ - - class TAGLIB_EXPORT Properties : public AudioProperties - { - public: - /*! - * Create an instance of TrueAudio::Properties with the data read from the - * ByteVector \a data. - */ - Properties(const ByteVector &data, long streamLength, ReadStyle style = Average); - - /*! - * Destroys this TrueAudio::Properties instance. - */ - virtual ~Properties(); - - // Reimplementations. - - virtual int length() const; - virtual int bitrate() const; - virtual int sampleRate() const; - virtual int channels() const; - - /*! - * Returns number of bits per sample. - */ - int bitsPerSample() const; - - /*! - * Returns the total number of sample frames - */ - uint sampleFrames() const; - - /*! - * Returns the major version number. - */ - int ttaVersion() const; - - private: - Properties(const Properties &); - Properties &operator=(const Properties &); - - void read(); - - class PropertiesPrivate; - PropertiesPrivate *d; - }; - } -} - -#endif diff --git a/taglib/taglib/wavpack/wavpackfile.cpp b/taglib/taglib/wavpack/wavpackfile.cpp deleted file mode 100644 index 13b8c57..0000000 --- a/taglib/taglib/wavpack/wavpackfile.cpp +++ /dev/null @@ -1,311 +0,0 @@ -/*************************************************************************** - copyright : (C) 2006 by Lukáš Lalinský - email : lalinsky@gmail.com - - copyright : (C) 2004 by Allan Sandfeld Jensen - email : kde@carewolf.org - (original MPC 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 <tbytevector.h> -#include <tstring.h> -#include <tdebug.h> -#include <tagunion.h> -#include <tpropertymap.h> - -#include "wavpackfile.h" -#include "id3v1tag.h" -#include "id3v2header.h" -#include "apetag.h" -#include "apefooter.h" - -using namespace TagLib; - -namespace -{ - enum { WavAPEIndex, WavID3v1Index }; -} - -class WavPack::File::FilePrivate -{ -public: - FilePrivate() : - APELocation(-1), - APESize(0), - ID3v1Location(-1), - properties(0), - hasAPE(false), - hasID3v1(false) {} - - ~FilePrivate() - { - delete properties; - } - - long APELocation; - uint APESize; - - long ID3v1Location; - - TagUnion tag; - - Properties *properties; - - // These indicate whether the file *on disk* has these tags, not if - // this data structure does. This is used in computing offsets. - - bool hasAPE; - bool hasID3v1; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -WavPack::File::File(FileName file, bool readProperties, - Properties::ReadStyle propertiesStyle) : TagLib::File(file) -{ - d = new FilePrivate; - if(isOpen()) - read(readProperties, propertiesStyle); -} - -WavPack::File::File(IOStream *stream, bool readProperties, - Properties::ReadStyle propertiesStyle) : TagLib::File(stream) -{ - d = new FilePrivate; - if(isOpen()) - read(readProperties, propertiesStyle); -} - -WavPack::File::~File() -{ - delete d; -} - -TagLib::Tag *WavPack::File::tag() const -{ - return &d->tag; -} - -PropertyMap WavPack::File::properties() const -{ - if(d->hasAPE) - return d->tag.access<APE::Tag>(WavAPEIndex, false)->properties(); - if(d->hasID3v1) - return d->tag.access<ID3v1::Tag>(WavID3v1Index, false)->properties(); - return PropertyMap(); -} - - -void WavPack::File::removeUnsupportedProperties(const StringList &unsupported) -{ - if(d->hasAPE) - d->tag.access<APE::Tag>(WavAPEIndex, false)->removeUnsupportedProperties(unsupported); -} - - -PropertyMap WavPack::File::setProperties(const PropertyMap &properties) -{ - if(d->hasID3v1) - d->tag.access<ID3v1::Tag>(WavID3v1Index, false)->setProperties(properties); - return d->tag.access<APE::Tag>(WavAPEIndex, true)->setProperties(properties); -} - -WavPack::Properties *WavPack::File::audioProperties() const -{ - return d->properties; -} - -bool WavPack::File::save() -{ - if(readOnly()) { - debug("WavPack::File::save() -- File is read only."); - return false; - } - - // Update ID3v1 tag - - if(ID3v1Tag()) { - if(d->hasID3v1) { - seek(d->ID3v1Location); - writeBlock(ID3v1Tag()->render()); - } - else { - seek(0, End); - d->ID3v1Location = tell(); - writeBlock(ID3v1Tag()->render()); - d->hasID3v1 = true; - } - } - else { - if(d->hasID3v1) { - removeBlock(d->ID3v1Location, 128); - d->hasID3v1 = false; - if(d->hasAPE) { - if(d->APELocation > d->ID3v1Location) - d->APELocation -= 128; - } - } - } - - // Update APE tag - - if(APETag()) { - if(d->hasAPE) - insert(APETag()->render(), d->APELocation, d->APESize); - else { - if(d->hasID3v1) { - insert(APETag()->render(), d->ID3v1Location, 0); - d->APESize = APETag()->footer()->completeTagSize(); - d->hasAPE = true; - d->APELocation = d->ID3v1Location; - d->ID3v1Location += d->APESize; - } - else { - seek(0, End); - d->APELocation = tell(); - writeBlock(APETag()->render()); - d->APESize = APETag()->footer()->completeTagSize(); - d->hasAPE = true; - } - } - } - else { - if(d->hasAPE) { - removeBlock(d->APELocation, d->APESize); - d->hasAPE = false; - if(d->hasID3v1) { - if(d->ID3v1Location > d->APELocation) { - d->ID3v1Location -= d->APESize; - } - } - } - } - - return true; -} - -ID3v1::Tag *WavPack::File::ID3v1Tag(bool create) -{ - return d->tag.access<ID3v1::Tag>(WavID3v1Index, create); -} - -APE::Tag *WavPack::File::APETag(bool create) -{ - return d->tag.access<APE::Tag>(WavAPEIndex, create); -} - -void WavPack::File::strip(int tags) -{ - if(tags & ID3v1) { - d->tag.set(WavID3v1Index, 0); - APETag(true); - } - - if(tags & APE) { - d->tag.set(WavAPEIndex, 0); - - if(!ID3v1Tag()) - APETag(true); - } -} - -bool WavPack::File::hasID3v1Tag() const -{ - return d->hasID3v1; -} - -bool WavPack::File::hasAPETag() const -{ - return d->hasAPE; -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -void WavPack::File::read(bool readProperties, Properties::ReadStyle /* propertiesStyle */) -{ - // Look for an ID3v1 tag - - d->ID3v1Location = findID3v1(); - - if(d->ID3v1Location >= 0) { - d->tag.set(WavID3v1Index, new ID3v1::Tag(this, d->ID3v1Location)); - d->hasID3v1 = true; - } - - // Look for an APE tag - - d->APELocation = findAPE(); - - if(d->APELocation >= 0) { - d->tag.set(WavAPEIndex, new APE::Tag(this, d->APELocation)); - d->APESize = APETag()->footer()->completeTagSize(); - d->APELocation = d->APELocation + APETag()->footer()->size() - d->APESize; - d->hasAPE = true; - } - - if(!d->hasID3v1) - APETag(true); - - // Look for WavPack audio properties - - if(readProperties) { - seek(0); - d->properties = new Properties(this, length() - d->APESize); - } -} - -long WavPack::File::findAPE() -{ - if(!isValid()) - return -1; - - if(d->hasID3v1) - seek(-160, End); - else - seek(-32, End); - - long p = tell(); - - if(readBlock(8) == APE::Tag::fileIdentifier()) - return p; - - return -1; -} - -long WavPack::File::findID3v1() -{ - if(!isValid()) - return -1; - - seek(-128, End); - long p = tell(); - - if(readBlock(3) == ID3v1::Tag::fileIdentifier()) - return p; - - return -1; -} diff --git a/taglib/taglib/wavpack/wavpackfile.h b/taglib/taglib/wavpack/wavpackfile.h deleted file mode 100644 index c85c75f..0000000 --- a/taglib/taglib/wavpack/wavpackfile.h +++ /dev/null @@ -1,216 +0,0 @@ -/*************************************************************************** - copyright : (C) 2006 by Lukáš Lalinský - email : lalinsky@gmail.com - - copyright : (C) 2004 by Allan Sandfeld Jensen - email : kde@carewolf.org - (original MPC 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_WVFILE_H -#define TAGLIB_WVFILE_H - -#include "tfile.h" -#include "taglib_export.h" -#include "wavpackproperties.h" - -namespace TagLib { - - class Tag; - - namespace ID3v1 { class Tag; } - namespace APE { class Tag; } - - //! An implementation of WavPack metadata - - /*! - * This is implementation of WavPack metadata. - * - * This supports ID3v1 and APE (v1 and v2) style comments as well as reading stream - * properties from the file. - */ - - namespace WavPack { - - //! An implementation of TagLib::File with WavPack specific methods - - /*! - * This implements and provides an interface for WavPack 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 WavPack files. - */ - - class TAGLIB_EXPORT File : public TagLib::File - { - public: - /*! - * This set of flags is used for various operations and is suitable for - * being OR-ed together. - */ - enum TagTypes { - //! Empty set. Matches no tag types. - NoTags = 0x0000, - //! Matches ID3v1 tags. - ID3v1 = 0x0001, - //! Matches APE tags. - APE = 0x0002, - //! Matches all tag types. - AllTags = 0xffff - }; - - /*! - * Constructs a 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 - */ - File(FileName file, bool readProperties = true, - Properties::ReadStyle propertiesStyle = Properties::Average); - - /*! - * Constructs 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. - * - * \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); - - /*! - * Destroys this instance of the File. - */ - virtual ~File(); - - /*! - * Returns the Tag for this file. This will be an APE tag, an ID3v1 tag - * or a combination of the two. - */ - virtual TagLib::Tag *tag() const; - - /*! - * Implements the unified property interface -- export function. - * If the file contains both an APE and an ID3v1 tag, only APE - * will be converted to the PropertyMap. - */ - PropertyMap properties() const; - - void removeUnsupportedProperties(const StringList &properties); - - /*! - * Implements the unified property interface -- import function. - * Creates an APE tag if it does not exists and calls setProperties() on - * that. Any existing ID3v1 tag will be updated as well. - */ - PropertyMap setProperties(const PropertyMap&); - - /*! - * Returns the MPC::Properties for this file. If no audio properties - * were read then this will return a null pointer. - */ - virtual Properties *audioProperties() const; - - /*! - * Saves the file. - */ - virtual bool save(); - - /*! - * Returns a pointer to the ID3v1 tag of the file. - * - * 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 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 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); - - /*! - * This will remove the tags that match the OR-ed together TagTypes from the - * file. By default it removes all tags. - * - * \note This will also invalidate pointers to the tags - * as their memory will be freed. - * \note In order to make the removal permanent save() still needs to be called - */ - void strip(int tags = AllTags); - - /*! - * Returns whether or not the file on disk actually has an ID3v1 tag. - * - * \see ID3v1Tag() - */ - bool hasID3v1Tag() const; - - /*! - * Returns whether or not the file on disk actually has an APE tag. - * - * \see APETag() - */ - bool hasAPETag() const; - - private: - File(const File &); - File &operator=(const File &); - - void read(bool readProperties, Properties::ReadStyle propertiesStyle); - void scan(); - long findID3v1(); - long findAPE(); - - class FilePrivate; - FilePrivate *d; - }; - } -} - -#endif diff --git a/taglib/taglib/wavpack/wavpackproperties.cpp b/taglib/taglib/wavpack/wavpackproperties.cpp deleted file mode 100644 index 085ddf8..0000000 --- a/taglib/taglib/wavpack/wavpackproperties.cpp +++ /dev/null @@ -1,203 +0,0 @@ -/*************************************************************************** - copyright : (C) 2006 by Lukáš Lalinský - email : lalinsky@gmail.com - - copyright : (C) 2004 by Allan Sandfeld Jensen - email : kde@carewolf.org - (original MPC 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 "wavpackproperties.h" -#include "wavpackfile.h" - -using namespace TagLib; - -class WavPack::Properties::PropertiesPrivate -{ -public: - PropertiesPrivate(const ByteVector &d, long length, ReadStyle s) : - data(d), - streamLength(length), - style(s), - length(0), - bitrate(0), - sampleRate(0), - channels(0), - version(0), - bitsPerSample(0), - sampleFrames(0), - file(0) {} - - ByteVector data; - long streamLength; - ReadStyle style; - int length; - int bitrate; - int sampleRate; - int channels; - int version; - int bitsPerSample; - uint sampleFrames; - File *file; -}; - -//////////////////////////////////////////////////////////////////////////////// -// public members -//////////////////////////////////////////////////////////////////////////////// - -WavPack::Properties::Properties(const ByteVector &data, long streamLength, ReadStyle style) : AudioProperties(style) -{ - d = new PropertiesPrivate(data, streamLength, style); - read(); -} - -WavPack::Properties::Properties(File *file, long streamLength, ReadStyle style) : AudioProperties(style) -{ - ByteVector data = file->readBlock(32); - d = new PropertiesPrivate(data, streamLength, style); - d->file = file; - read(); -} - -WavPack::Properties::~Properties() -{ - delete d; -} - -int WavPack::Properties::length() const -{ - return d->length; -} - -int WavPack::Properties::bitrate() const -{ - return d->bitrate; -} - -int WavPack::Properties::sampleRate() const -{ - return d->sampleRate; -} - -int WavPack::Properties::channels() const -{ - return d->channels; -} - -int WavPack::Properties::version() const -{ - return d->version; -} - -int WavPack::Properties::bitsPerSample() const -{ - return d->bitsPerSample; -} - -TagLib::uint WavPack::Properties::sampleFrames() const -{ - return d->sampleFrames; -} - -//////////////////////////////////////////////////////////////////////////////// -// private members -//////////////////////////////////////////////////////////////////////////////// - -static const unsigned int sample_rates[] = { - 6000, 8000, 9600, 11025, 12000, 16000, 22050, 24000, - 32000, 44100, 48000, 64000, 88200, 96000, 192000, 0 }; - -#define BYTES_STORED 3 -#define MONO_FLAG 4 - -#define SHIFT_LSB 13 -#define SHIFT_MASK (0x1fL << SHIFT_LSB) - -#define SRATE_LSB 23 -#define SRATE_MASK (0xfL << SRATE_LSB) - -#define MIN_STREAM_VERS 0x402 -#define MAX_STREAM_VERS 0x410 - -#define FINAL_BLOCK 0x1000 - -void WavPack::Properties::read() -{ - if(!d->data.startsWith("wvpk")) - return; - - d->version = d->data.toShort(8, false); - if(d->version < MIN_STREAM_VERS || d->version > MAX_STREAM_VERS) - return; - - const unsigned int flags = d->data.toUInt(24, false); - d->bitsPerSample = ((flags & BYTES_STORED) + 1) * 8 - - ((flags & SHIFT_MASK) >> SHIFT_LSB); - d->sampleRate = sample_rates[(flags & SRATE_MASK) >> SRATE_LSB]; - d->channels = (flags & MONO_FLAG) ? 1 : 2; - - unsigned int samples = d->data.toUInt(12, false); - if(samples == ~0u) { - if(d->file && d->style != Fast) { - samples = seekFinalIndex(); - } - else { - samples = 0; - } - } - d->length = d->sampleRate > 0 ? (samples + (d->sampleRate / 2)) / d->sampleRate : 0; - d->sampleFrames = samples; - - d->bitrate = d->length > 0 ? ((d->streamLength * 8L) / d->length) / 1000 : 0; -} - -unsigned int WavPack::Properties::seekFinalIndex() -{ - ByteVector blockID("wvpk", 4); - - long offset = d->streamLength; - while(offset > 0) { - offset = d->file->rfind(blockID, offset); - if(offset == -1) - return 0; - d->file->seek(offset); - ByteVector data = d->file->readBlock(32); - if(data.size() != 32) - return 0; - const int version = data.toShort(8, false); - if(version < MIN_STREAM_VERS || version > MAX_STREAM_VERS) - continue; - const unsigned int flags = data.toUInt(24, false); - if(!(flags & FINAL_BLOCK)) - return 0; - const unsigned int blockIndex = data.toUInt(16, false); - const unsigned int blockSamples = data.toUInt(20, false); - return blockIndex + blockSamples; - } - - return 0; -} - diff --git a/taglib/taglib/wavpack/wavpackproperties.h b/taglib/taglib/wavpack/wavpackproperties.h deleted file mode 100644 index c788fdd..0000000 --- a/taglib/taglib/wavpack/wavpackproperties.h +++ /dev/null @@ -1,110 +0,0 @@ -/*************************************************************************** - copyright : (C) 2006 by Lukáš Lalinský - email : lalinsky@gmail.com - - copyright : (C) 2004 by Allan Sandfeld Jensen - email : kde@carewolf.org - (original MPC 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_WVPROPERTIES_H -#define TAGLIB_WVPROPERTIES_H - -#include "taglib_export.h" -#include "audioproperties.h" - -namespace TagLib { - - namespace WavPack { - - class File; - - static const uint HeaderSize = 32; - - //! An implementation of audio property reading for WavPack - - /*! - * This reads the data from an WavPack stream found in the AudioProperties - * API. - */ - - class TAGLIB_EXPORT Properties : public AudioProperties - { - public: - /*! - * Create an instance of WavPack::Properties with the data read from the - * ByteVector \a data. - * - * \deprecated This constructor will be dropped in favor of the one below - * in a future version. - */ - Properties(const ByteVector &data, long streamLength, ReadStyle style = Average); - - /*! - * Create an instance of WavPack::Properties. - */ - // BIC: merge with the above constructor - Properties(File *file, long streamLength, ReadStyle style = Average); - - /*! - * Destroys this WavPack::Properties instance. - */ - virtual ~Properties(); - - // Reimplementations. - - virtual int length() const; - virtual int bitrate() const; - - /*! - * Returns the sample rate in Hz. 0 means unknown or custom. - */ - virtual int sampleRate() const; - - virtual int channels() const; - - /*! - * Returns number of bits per sample. - */ - int bitsPerSample() const; - uint sampleFrames() const; - - /*! - * Returns WavPack version. - */ - int version() const; - - private: - Properties(const Properties &); - Properties &operator=(const Properties &); - - void read(); - unsigned int seekFinalIndex(); - - class PropertiesPrivate; - PropertiesPrivate *d; - }; - } -} - -#endif diff --git a/taglib/taglib/xm/xmfile.cpp b/taglib/taglib/xm/xmfile.cpp deleted file mode 100644 index d8373a7..0000000 --- a/taglib/taglib/xm/xmfile.cpp +++ /dev/null @@ -1,650 +0,0 @@ -/*************************************************************************** - copyright : (C) 2011 by Mathias Panzenböck - email : grosser.meister.morti@gmx.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * - ***************************************************************************/ - -#include "tstringlist.h" -#include "tdebug.h" -#include "xmfile.h" -#include "modfileprivate.h" -#include "tpropertymap.h" - -#include <string.h> -#include <algorithm> - -using namespace TagLib; -using namespace XM; -using TagLib::uint; -using TagLib::ushort; -using TagLib::ulong; - -/*! - * The Reader classes are helpers to make handling of the stripped XM - * format more easy. In the stripped XM format certain header sizes might - * be smaller than one would expect. The fields that are not included - * are then just some predefined valued (e.g. 0). - * - * Using these classes this code: - * - * if(headerSize >= 4) { - * if(!readU16L(value1)) ERROR(); - * if(headerSize >= 8) { - * if(!readU16L(value2)) ERROR(); - * if(headerSize >= 12) { - * if(!readString(value3, 22)) ERROR(); - * ... - * } - * } - * } - * - * Becomes: - * - * StructReader header; - * header.u16L(value1).u16L(value2).string(value3, 22). ...; - * if(header.read(*this, headerSize) < std::min(header.size(), headerSize)) - * ERROR(); - * - * Maybe if this is useful to other formats these classes can be moved to - * their own public files. - */ -class Reader -{ -public: - virtual ~Reader() - { - } - - /*! - * Reads associated values from \a file, but never reads more - * then \a limit bytes. - */ - virtual uint read(TagLib::File &file, uint limit) = 0; - - /*! - * Returns the number of bytes this reader would like to read. - */ - virtual uint size() const = 0; -}; - -class SkipReader : public Reader -{ -public: - SkipReader(uint size) : m_size(size) - { - } - - uint read(TagLib::File &file, uint limit) - { - uint count = std::min(m_size, limit); - file.seek(count, TagLib::File::Current); - return count; - } - - uint size() const - { - return m_size; - } - -private: - uint m_size; -}; - -template<typename T> -class ValueReader : public Reader -{ -public: - ValueReader(T &value) : value(value) - { - } - -protected: - T &value; -}; - -class StringReader : public ValueReader<String> -{ -public: - StringReader(String &string, uint size) : - ValueReader<String>(string), m_size(size) - { - } - - uint read(TagLib::File &file, uint limit) - { - ByteVector data = file.readBlock(std::min(m_size, limit)); - uint count = data.size(); - int index = data.find((char) 0); - if(index > -1) { - data.resize(index); - } - data.replace((char) 0xff, ' '); - value = data; - return count; - } - - uint size() const - { - return m_size; - } - -private: - uint m_size; -}; - -class ByteReader : public ValueReader<uchar> -{ -public: - ByteReader(uchar &byte) : ValueReader<uchar>(byte) {} - - uint read(TagLib::File &file, uint limit) - { - ByteVector data = file.readBlock(std::min(1U,limit)); - if(data.size() > 0) { - value = data[0]; - } - return data.size(); - } - - uint size() const - { - return 1; - } -}; - -template<typename T> -class NumberReader : public ValueReader<T> -{ -public: - NumberReader(T &value, bool bigEndian) : - ValueReader<T>(value), bigEndian(bigEndian) - { - } - -protected: - bool bigEndian; -}; - -class U16Reader : public NumberReader<ushort> -{ -public: - U16Reader(ushort &value, bool bigEndian) - : NumberReader<ushort>(value, bigEndian) {} - - uint read(TagLib::File &file, uint limit) - { - ByteVector data = file.readBlock(std::min(2U,limit)); - value = data.toUShort(bigEndian); - return data.size(); - } - - uint size() const - { - return 2; - } -}; - -class U32Reader : public NumberReader<ulong> -{ -public: - U32Reader(ulong &value, bool bigEndian = true) : - NumberReader<ulong>(value, bigEndian) - { - } - - uint read(TagLib::File &file, uint limit) - { - ByteVector data = file.readBlock(std::min(4U,limit)); - value = data.toUInt(bigEndian); - return data.size(); - } - - uint size() const - { - return 4; - } -}; - -class StructReader : public Reader -{ -public: - StructReader() - { - m_readers.setAutoDelete(true); - } - - /*! - * Add a nested reader. This reader takes ownership. - */ - StructReader &reader(Reader *reader) - { - m_readers.append(reader); - return *this; - } - - /*! - * Don't read anything but skip \a size bytes. - */ - StructReader &skip(uint size) - { - m_readers.append(new SkipReader(size)); - return *this; - } - - /*! - * Read a string of \a size characters (bytes) into \a string. - */ - StructReader &string(String &string, uint size) - { - m_readers.append(new StringReader(string, size)); - return *this; - } - - /*! - * Read a byte into \a byte. - */ - StructReader &byte(uchar &byte) - { - m_readers.append(new ByteReader(byte)); - return *this; - } - - /*! - * Read a unsigned 16 Bit integer into \a number. The byte order - * is controlled by \a bigEndian. - */ - StructReader &u16(ushort &number, bool bigEndian) - { - m_readers.append(new U16Reader(number, bigEndian)); - return *this; - } - - /*! - * Read a unsigned 16 Bit little endian integer into \a number. - */ - StructReader &u16L(ushort &number) - { - return u16(number, false); - } - - /*! - * Read a unsigned 16 Bit big endian integer into \a number. - */ - StructReader &u16B(ushort &number) - { - return u16(number, true); - } - - /*! - * Read a unsigned 32 Bit integer into \a number. The byte order - * is controlled by \a bigEndian. - */ - StructReader &u32(ulong &number, bool bigEndian) - { - m_readers.append(new U32Reader(number, bigEndian)); - return *this; - } - - /*! - * Read a unsigned 32 Bit little endian integer into \a number. - */ - StructReader &u32L(ulong &number) - { - return u32(number, false); - } - - /*! - * Read a unsigned 32 Bit big endian integer into \a number. - */ - StructReader &u32B(ulong &number) - { - return u32(number, true); - } - - uint size() const - { - uint size = 0; - for(List<Reader*>::ConstIterator i = m_readers.begin(); - i != m_readers.end(); ++ i) { - size += (*i)->size(); - } - return size; - } - - uint read(TagLib::File &file, uint limit) - { - uint sumcount = 0; - for(List<Reader*>::Iterator i = m_readers.begin(); - limit > 0 && i != m_readers.end(); ++ i) { - uint count = (*i)->read(file, limit); - limit -= count; - sumcount += count; - } - return sumcount; - } - -private: - List<Reader*> m_readers; -}; - -class XM::File::FilePrivate -{ -public: - FilePrivate(AudioProperties::ReadStyle propertiesStyle) - : tag(), properties(propertiesStyle) - { - } - - Mod::Tag tag; - XM::Properties properties; -}; - -XM::File::File(FileName file, bool readProperties, - AudioProperties::ReadStyle propertiesStyle) : - Mod::FileBase(file), - d(new FilePrivate(propertiesStyle)) -{ - if(isOpen()) - read(readProperties); -} - -XM::File::File(IOStream *stream, bool readProperties, - AudioProperties::ReadStyle propertiesStyle) : - Mod::FileBase(stream), - d(new FilePrivate(propertiesStyle)) -{ - if(isOpen()) - read(readProperties); -} - -XM::File::~File() -{ - delete d; -} - -Mod::Tag *XM::File::tag() const -{ - return &d->tag; -} - -PropertyMap XM::File::properties() const -{ - return d->tag.properties(); -} - -PropertyMap XM::File::setProperties(const PropertyMap &properties) -{ - return d->tag.setProperties(properties); -} - -XM::Properties *XM::File::audioProperties() const -{ - return &d->properties; -} - -bool XM::File::save() -{ - if(readOnly()) { - debug("XM::File::save() - Cannot save to a read only file."); - return false; - } - seek(17); - writeString(d->tag.title(), 20); - seek(1, Current); - writeString(d->tag.trackerName(), 20); - seek(2, Current); - ulong headerSize = 0; - if(!readU32L(headerSize)) - return false; - seek(2+2+2, Current); - - ushort patternCount = 0; - ushort instrumentCount = 0; - if(!readU16L(patternCount) || !readU16L(instrumentCount)) - return false; - - seek(60 + headerSize); - - // need to read patterns again in order to seek to the instruments: - for(ushort i = 0; i < patternCount; ++ i) { - ulong patternHeaderLength = 0; - if(!readU32L(patternHeaderLength) || patternHeaderLength < 4) - return false; - - ushort dataSize = 0; - StructReader pattern; - pattern.skip(3).u16L(dataSize); - - uint count = pattern.read(*this, patternHeaderLength - 4U); - if(count != std::min(patternHeaderLength - 4U, (ulong)pattern.size())) - return false; - - seek(patternHeaderLength - (4 + count) + dataSize, Current); - } - - StringList lines = d->tag.comment().split("\n"); - uint sampleNameIndex = instrumentCount; - for(ushort i = 0; i < instrumentCount; ++ i) { - ulong instrumentHeaderSize = 0; - if(!readU32L(instrumentHeaderSize) || instrumentHeaderSize < 4) - return false; - - uint len = std::min(22UL, instrumentHeaderSize - 4U); - if(i >= lines.size()) - writeString(String::null, len); - else - writeString(lines[i], len); - - long offset = 0; - if(instrumentHeaderSize >= 29U) { - ushort sampleCount = 0; - seek(1, Current); - if(!readU16L(sampleCount)) - return false; - - if(sampleCount > 0) { - ulong sampleHeaderSize = 0; - if(instrumentHeaderSize < 33U || !readU32L(sampleHeaderSize)) - return false; - // skip unhandeled header proportion: - seek(instrumentHeaderSize - 33, Current); - - for(ushort j = 0; j < sampleCount; ++ j) { - if(sampleHeaderSize > 4U) { - ulong sampleLength = 0; - if(!readU32L(sampleLength)) - return false; - offset += sampleLength; - - seek(std::min(sampleHeaderSize, 14UL), Current); - if(sampleHeaderSize > 18U) { - uint len = std::min(sampleHeaderSize - 18U, 22UL); - if(sampleNameIndex >= lines.size()) - writeString(String::null, len); - else - writeString(lines[sampleNameIndex ++], len); - seek(sampleHeaderSize - (18U + len), Current); - } - } - else { - seek(sampleHeaderSize, Current); - } - } - } - else { - offset = instrumentHeaderSize - 29; - } - } - else { - offset = instrumentHeaderSize - (4 + len); - } - seek(offset, Current); - } - - return true; -} - -void XM::File::read(bool) -{ - if(!isOpen()) - return; - - seek(0); - ByteVector magic = readBlock(17); - // it's all 0x00 for stripped XM files: - READ_ASSERT(magic == "Extended Module: " || magic == ByteVector(17, 0)); - - READ_STRING(d->tag.setTitle, 20); - READ_BYTE_AS(escape); - // in stripped XM files this is 0x00: - READ_ASSERT(escape == 0x1A || escape == 0x00); - - READ_STRING(d->tag.setTrackerName, 20); - READ_U16L(d->properties.setVersion); - - READ_U32L_AS(headerSize); - READ_ASSERT(headerSize >= 4); - - ushort length = 0; - ushort restartPosition = 0; - ushort channels = 0; - ushort patternCount = 0; - ushort instrumentCount = 0; - ushort flags = 0; - ushort tempo = 0; - ushort bpmSpeed = 0; - - StructReader header; - header.u16L(length) - .u16L(restartPosition) - .u16L(channels) - .u16L(patternCount) - .u16L(instrumentCount) - .u16L(flags) - .u16L(tempo) - .u16L(bpmSpeed); - - uint count = header.read(*this, headerSize - 4U); - uint size = std::min(headerSize - 4U, (ulong)header.size()); - - READ_ASSERT(count == size); - - d->properties.setLengthInPatterns(length); - d->properties.setRestartPosition(restartPosition); - d->properties.setChannels(channels); - d->properties.setPatternCount(patternCount); - d->properties.setInstrumentCount(instrumentCount); - d->properties.setFlags(flags); - d->properties.setTempo(tempo); - d->properties.setBpmSpeed(bpmSpeed); - - seek(60 + headerSize); - - // read patterns: - for(ushort i = 0; i < patternCount; ++ i) { - READ_U32L_AS(patternHeaderLength); - READ_ASSERT(patternHeaderLength >= 4); - - uchar packingType = 0; - ushort rowCount = 0; - ushort dataSize = 0; - StructReader pattern; - pattern.byte(packingType).u16L(rowCount).u16L(dataSize); - - uint count = pattern.read(*this, patternHeaderLength - 4U); - READ_ASSERT(count == std::min(patternHeaderLength - 4U, (ulong)pattern.size())); - - seek(patternHeaderLength - (4 + count) + dataSize, Current); - } - - StringList intrumentNames; - StringList sampleNames; - uint sumSampleCount = 0; - - // read instruments: - for(ushort i = 0; i < instrumentCount; ++ i) { - READ_U32L_AS(instrumentHeaderSize); - READ_ASSERT(instrumentHeaderSize >= 4); - - String instrumentName; - uchar instrumentType = 0; - ushort sampleCount = 0; - - StructReader instrument; - instrument.string(instrumentName, 22).byte(instrumentType).u16L(sampleCount); - - // 4 for instrumentHeaderSize - uint count = 4 + instrument.read(*this, instrumentHeaderSize - 4U); - READ_ASSERT(count == std::min(instrumentHeaderSize, (ulong)instrument.size() + 4)); - - ulong sampleHeaderSize = 0; - long offset = 0; - if(sampleCount > 0) { - sumSampleCount += sampleCount; - // wouldn't know which header size to assume otherwise: - READ_ASSERT(instrumentHeaderSize >= count + 4 && readU32L(sampleHeaderSize)); - // skip unhandeled header proportion: - seek(instrumentHeaderSize - count - 4, Current); - - for(ushort j = 0; j < sampleCount; ++ j) { - ulong sampleLength = 0; - ulong loopStart = 0; - ulong loopLength = 0; - uchar volume = 0; - uchar finetune = 0; - uchar sampleType = 0; - uchar panning = 0; - uchar noteNumber = 0; - uchar compression = 0; - String sampleName; - StructReader sample; - sample.u32L(sampleLength) - .u32L(loopStart) - .u32L(loopLength) - .byte(volume) - .byte(finetune) - .byte(sampleType) - .byte(panning) - .byte(noteNumber) - .byte(compression) - .string(sampleName, 22); - - uint count = sample.read(*this, sampleHeaderSize); - READ_ASSERT(count == std::min(sampleHeaderSize, (ulong)sample.size())); - // skip unhandeled header proportion: - seek(sampleHeaderSize - count, Current); - - offset += sampleLength; - sampleNames.append(sampleName); - } - } - else { - offset = instrumentHeaderSize - count; - } - intrumentNames.append(instrumentName); - seek(offset, Current); - } - - d->properties.setSampleCount(sumSampleCount); - String comment(intrumentNames.toString("\n")); - if(sampleNames.size() > 0) { - comment += "\n"; - comment += sampleNames.toString("\n"); - } - d->tag.setComment(comment); -} diff --git a/taglib/taglib/xm/xmfile.h b/taglib/taglib/xm/xmfile.h deleted file mode 100644 index ae48a51..0000000 --- a/taglib/taglib/xm/xmfile.h +++ /dev/null @@ -1,108 +0,0 @@ -/*************************************************************************** - copyright : (C) 2011 by Mathias Panzenböck - email : grosser.meister.morti@gmx.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef TAGLIB_XMFILE_H -#define TAGLIB_XMFILE_H - -#include "tfile.h" -#include "audioproperties.h" -#include "taglib_export.h" -#include "modfilebase.h" -#include "modtag.h" -#include "xmproperties.h" - -namespace TagLib { - - namespace XM { - - class TAGLIB_EXPORT File : public Mod::FileBase { - public: - /*! - * Constructs an Extended Module 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); - - /*! - * Constructs an Extended Module file from \a stream. - * - * \note In the current implementation, both \a readProperties and - * \a propertiesStyle are ignored. The audio properties are always - * read. - * - * \note TagLib will *not* take ownership of the stream, the caller is - * responsible for deleting it after the File object. - */ - File(IOStream *stream, bool readProperties = true, - AudioProperties::ReadStyle propertiesStyle = - AudioProperties::Average); - - /*! - * Destroys this instance of the File. - */ - virtual ~File(); - - Mod::Tag *tag() const; - - /*! - * Implements the unified property interface -- export function. - * Forwards to Mod::Tag::properties(). - */ - PropertyMap properties() const; - - /*! - * Implements the unified property interface -- import function. - * Forwards to Mod::Tag::setProperties(). - */ - PropertyMap setProperties(const PropertyMap &); - - /*! - * Returns the XM::Properties for this file. If no audio properties - * were read then this will return a null pointer. - */ - XM::Properties *audioProperties() const; - - /*! - * Save the file. - * This is the same as calling save(AllTags); - * - * \note Saving Extended Module tags is not supported. - */ - bool save(); - - private: - File(const File &); - File &operator=(const File &); - - void read(bool readProperties); - - class FilePrivate; - FilePrivate *d; - }; - } -} - -#endif diff --git a/taglib/taglib/xm/xmproperties.cpp b/taglib/taglib/xm/xmproperties.cpp deleted file mode 100644 index 45da02b..0000000 --- a/taglib/taglib/xm/xmproperties.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/*************************************************************************** - copyright :(C) 2011 by Mathias Panzenböck - email : grosser.meister.morti@gmx.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * - ***************************************************************************/ - -#include "xmproperties.h" - -using namespace TagLib; -using namespace XM; - -class XM::Properties::PropertiesPrivate -{ -public: - PropertiesPrivate() : - lengthInPatterns(0), - channels(0), - version(0), - restartPosition(0), - patternCount(0), - instrumentCount(0), - sampleCount(0), - flags(0), - tempo(0), - bpmSpeed(0) - { - } - - ushort lengthInPatterns; - int channels; - ushort version; - ushort restartPosition; - ushort patternCount; - ushort instrumentCount; - uint sampleCount; - ushort flags; - ushort tempo; - ushort bpmSpeed; -}; - -XM::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) : - AudioProperties(propertiesStyle), - d(new PropertiesPrivate) -{ -} - -XM::Properties::~Properties() -{ - delete d; -} - -int XM::Properties::length() const -{ - return 0; -} - -int XM::Properties::bitrate() const -{ - return 0; -} - -int XM::Properties::sampleRate() const -{ - return 0; -} - -int XM::Properties::channels() const -{ - return d->channels; -} - -TagLib::ushort XM::Properties::lengthInPatterns() const -{ - return d->lengthInPatterns; -} - -TagLib::ushort XM::Properties::version() const -{ - return d->version; -} - -TagLib::ushort XM::Properties::restartPosition() const -{ - return d->restartPosition; -} - -TagLib::ushort XM::Properties::patternCount() const -{ - return d->patternCount; -} - -TagLib::ushort XM::Properties::instrumentCount() const -{ - return d->instrumentCount; -} - -TagLib::uint XM::Properties::sampleCount() const -{ - return d->sampleCount; -} - -TagLib::ushort XM::Properties::flags() const -{ - return d->flags; -} - -TagLib::ushort XM::Properties::tempo() const -{ - return d->tempo; -} - -TagLib::ushort XM::Properties::bpmSpeed() const -{ - return d->bpmSpeed; -} - -void XM::Properties::setLengthInPatterns(ushort lengthInPatterns) -{ - d->lengthInPatterns = lengthInPatterns; -} - -void XM::Properties::setChannels(int channels) -{ - d->channels = channels; -} - -void XM::Properties::setVersion(ushort version) -{ - d->version = version; -} - -void XM::Properties::setRestartPosition(ushort restartPosition) -{ - d->restartPosition = restartPosition; -} - -void XM::Properties::setPatternCount(ushort patternCount) -{ - d->patternCount = patternCount; -} - -void XM::Properties::setInstrumentCount(ushort instrumentCount) -{ - d->instrumentCount = instrumentCount; -} - -void XM::Properties::setSampleCount(uint sampleCount) -{ - d->sampleCount = sampleCount; -} - -void XM::Properties::setFlags(ushort flags) -{ - d->flags = flags; -} - -void XM::Properties::setTempo(ushort tempo) -{ - d->tempo = tempo; -} - -void XM::Properties::setBpmSpeed(ushort bpmSpeed) -{ - d->bpmSpeed = bpmSpeed; -} diff --git a/taglib/taglib/xm/xmproperties.h b/taglib/taglib/xm/xmproperties.h deleted file mode 100644 index 9b6624a..0000000 --- a/taglib/taglib/xm/xmproperties.h +++ /dev/null @@ -1,79 +0,0 @@ -/*************************************************************************** - copyright : (C) 2011 by Mathias Panzenböck - email : grosser.meister.morti@gmx.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef TAGLIB_XMPROPERTIES_H -#define TAGLIB_XMPROPERTIES_H - -#include "taglib.h" -#include "tstring.h" -#include "audioproperties.h" - -namespace TagLib { - namespace XM { - class Properties : public AudioProperties { - friend class File; - public: - /*! Flag bits. */ - enum { - LinearFreqTable = 1 // otherwise its the amiga freq. table - }; - - Properties(AudioProperties::ReadStyle propertiesStyle); - virtual ~Properties(); - - int length() const; - int bitrate() const; - int sampleRate() const; - int channels() const; - - ushort lengthInPatterns() const; - ushort version() const; - ushort restartPosition() const; - ushort patternCount() const; - ushort instrumentCount() const; - uint sampleCount() const; - ushort flags() const; - ushort tempo() const; - ushort bpmSpeed() const; - - void setChannels(int channels); - - void setLengthInPatterns(ushort lengthInPatterns); - void setVersion(ushort version); - void setRestartPosition(ushort restartPosition); - void setPatternCount(ushort patternCount); - void setInstrumentCount(ushort instrumentCount); - void setSampleCount(uint sampleCount); - void setFlags(ushort flags); - void setTempo(ushort tempo); - void setBpmSpeed(ushort bpmSpeed); - - private: - Properties(const Properties&); - Properties &operator=(const Properties&); - - class PropertiesPrivate; - PropertiesPrivate *d; - }; - } -} - -#endif diff --git a/taglib/tests/CMakeLists.txt b/taglib/tests/CMakeLists.txt deleted file mode 100644 index 7a3d0bd..0000000 --- a/taglib/tests/CMakeLists.txt +++ /dev/null @@ -1,76 +0,0 @@ -INCLUDE_DIRECTORIES( - ${CMAKE_CURRENT_SOURCE_DIR}/../taglib - ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/toolkit - ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/ape - ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/asf - ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mpeg/id3v1 - ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mpeg/id3v2 - ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mpeg/id3v2/frames - ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mpeg - ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mpc - ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mp4 - ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/riff - ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/riff/aiff - ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/riff/wav - ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/trueaudio - ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/ogg - ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/ogg/vorbis - ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/ogg/flac - ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/ogg/speex - ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/ogg/opus - ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/flac - ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/wavpack - ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mod - ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/s3m - ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/it - ${CMAKE_CURRENT_SOURCE_DIR}/../taglib/xm -) - -SET(test_runner_SRCS - main.cpp - test_list.cpp - test_map.cpp - test_mpeg.cpp - test_synchdata.cpp - test_trueaudio.cpp - test_bytevector.cpp - test_bytevectorlist.cpp - test_bytevectorstream.cpp - test_string.cpp - test_propertymap.cpp - test_fileref.cpp - test_id3v1.cpp - test_id3v2.cpp - test_xiphcomment.cpp - test_aiff.cpp - test_riff.cpp - test_ogg.cpp - test_oggflac.cpp - test_flac.cpp - test_flacpicture.cpp - test_flacunknownmetadatablock.cpp - test_ape.cpp - test_apetag.cpp - test_wav.cpp - test_info.cpp - test_wavpack.cpp - test_mp4.cpp - test_mp4item.cpp - test_mp4coverart.cpp - test_asf.cpp - test_mod.cpp - test_s3m.cpp - test_it.cpp - test_xm.cpp - test_mpc.cpp - test_opus.cpp -) - -INCLUDE_DIRECTORIES(${CPPUNIT_INCLUDE_DIR}) - -ADD_EXECUTABLE(test_runner ${test_runner_SRCS}) -TARGET_LINK_LIBRARIES(test_runner tag ${CPPUNIT_LIBRARIES}) - -ADD_TEST(test_runner test_runner) -ADD_CUSTOM_TARGET(check COMMAND ${CMAKE_CTEST_COMMAND} -V - DEPENDS test_runner) diff --git a/taglib/tests/data/005411.id3 b/taglib/tests/data/005411.id3 deleted file mode 100644 index ab2e0997a0bcbf27aa169a09fd3f730d8319de9d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38402 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 AdjJ3c diff --git a/taglib/tests/data/64bit.mp4 b/taglib/tests/data/64bit.mp4 deleted file mode 100644 index 0bd7f9f33dfa28317996eab962cce5cb2d2afc0b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 85 zcmZQzU|`J6&o5(u0AC=*SejCj2<6*?__?WYzAjW;F*B#Q1jv?5F38LQ(t;_8U^Sv3 Gc}4)(BMUG9 diff --git a/taglib/tests/data/broken-tenc.id3 b/taglib/tests/data/broken-tenc.id3 deleted file mode 100644 index 809040506f29b83c48e055251e164c807d3b2997..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 400 zcmcJL!Ab)$5QhKNDhg73gj{+po36XAH`8gLrDn4%1ManlMT@WqrFWmnC-A*I)X6sX z4f=<ld^3LtldKlm2%?KI+lmAdmEg5)+t5P-F!?&PWwEbqMDorFzKgs5ZOi+<@{NN^ zgR+7m*y0Ft(*KYJ&}Cus2xN!o!H^jsH|1=Iw0=xaAal4d$E8?<S3DEA6Z7VyQ@&TO z1J_nd=UQykasxIm^H}SrG6y%bmO5UsXu@;D;bTa?6220b=?;hA?`PoV9_ugJfZNaT Q2S}!pD`4^ij1FheA4Fn><NyEw diff --git a/taglib/tests/data/changed.mod b/taglib/tests/data/changed.mod deleted file mode 100644 index 13dcea8bc98054152611f31515822de7c1254add..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3132 zcmYe!NX$!5O;ISxEXhe_fPj#U%wmO{%)C^E^30qZg``x4lA_W)pqv8`Ga_Vxs`9h- zAbMc3a2`6t0Vu$TE(qt3%EE&J$QTWc(a=B+0c18fZ7|j&3k?L@!r8-bAnYBrb2J1- TLtr!nMnhmU1V%$(U_$@^D@Pm& diff --git a/taglib/tests/data/changed.s3m b/taglib/tests/data/changed.s3m deleted file mode 100644 index 37bd49cdd47c365f265f3f56bf53f0cac67be090..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 544 zcmYe!NX$!5O;ISxEXhe_Km}3)3=B*RtPG4mVFh6(hG6F)UkA2Y1A#wC>NprVnYfs_ zS$J4^+4$J`|6>4720jL11_=gPBu%)O4Gp+tK;jNSyjlTBAc2sK%wh!~O3YKp%quP_ zD$PyJD^bWx%uQ89QiYxA02D?y&o@7%G$&OdEfYlK7v(0F6l2$nMHHKPiAkl!spw84 o(nzf46)WVH=9FaSWagzRB<JUXyj!e?#W7ffu$iZe8-Ps!07j!oy8r+H diff --git a/taglib/tests/data/changed.xm b/taglib/tests/data/changed.xm deleted file mode 100644 index bb5db3ddd45e3a5bda8b016e0ae867179f26b4fc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5471 zcmeH}%WA_g5JktP^s&z>5YV!#en6q%O&5V?)%?IDR#Jf_6-$P0O7rLKjODm-Uu07V zcm`V!&sd<ty|V9LqIRV&)xwuerEk^x3Eh_F(Zotais=%!4`$WPy6!BSWB_!*CAB-c z&*61gGQ!yv@3{cTcM_u}a6!(PyAbQfY8RD5t3&699Im_3|8@l^mg3Q&s9qgio#(Cl zX`3AHZ>j&QEr5;*ctrbL=>d>0FQq!HwF=(qXg<jSFjmgsstI&T;hrfik&PNFR>6O# z!noGnvIK)N?hy32Rk(+8bBJUxE?Tt?9`%zMjcohDR2xHL-uT*L3~4b=-u)Pq;N-6% oNkStK1VVC%C_$7UN=O7m38Dm1LQg>KAa>}*ApZ$shZD8K2XpUN-T(jq diff --git a/taglib/tests/data/click.mpc b/taglib/tests/data/click.mpc deleted file mode 100644 index a41f14e9ea2175684ff2ab74d3682ddbd0785765..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1588 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 diff --git a/taglib/tests/data/click.wv b/taglib/tests/data/click.wv deleted file mode 100644 index f8bd1a8513ca97bae632a2a144fa90c9582bcd48..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3176 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 Gx%FRQMM#za diff --git a/taglib/tests/data/compressed_id3_frame.mp3 b/taglib/tests/data/compressed_id3_frame.mp3 deleted file mode 100644 index 60bc895633b1ce32894e54800f6aa65d4e2cb546..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5000 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 D0Kmmp diff --git a/taglib/tests/data/correctness_gain_silent_output.opus b/taglib/tests/data/correctness_gain_silent_output.opus deleted file mode 100644 index 00972c42f64f285610c17ab548ac0bfa6960bdff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35506 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 diff --git a/taglib/tests/data/covr-junk.m4a b/taglib/tests/data/covr-junk.m4a deleted file mode 100644 index ac80cb29d2585e9d728a86b5027973690f51d174..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5108 zcmeHK-)qxw5Wgf{e{Jnj?c7gBwr+EX>$Gmjbg*@+oe|w+6ciC=)}*ekX-1O`6_MhT zBErBui7@d&7>dvOAXFF#J}Wo};-i0nuM+Rl)U8DXVW1EBw8`D~^8Mc3_ru*cEdaD+ zj2lbp(ohT#B(u7v0@S@$Wy$#B0?1|OGm?}Rjz(ic02A;~aK&J%3&d5n6(U7PaY%3~ z!RZ303;u^L00>4@O<TdUJg2TK$aJWezMtB9dsY;InOlXr=Ka6`eRohbKy%G_d}rqG zG!~65SxwgIAzv&OJuqXMjiw3UGK_+>h~~@2qLmBtE0;<X%4Zj>&^7V@oR5oF<*bA* z1XZrtFT6+qd%I-2?^=*^g-R%0Th3Q>TXOHzY(9enURTSG><2w^+1?=+6naje6dRTc zIiaj`_jO}Fhx%3B&@Ix-cDR6VR7#Gpvn>{QGGKayV~SoTk3;gh(cnTE9&Z9@!yw-P z>gVgw!tUeUC>Y{f&<(@l8+975<02Fkf-T{-hH2a+gN-LB(HZ!h%i-W3)j&ViWEx`= zsAj1h4%?E7x5L)4w$mEw1hNY_^$h?g;_xGl)77<)eyrNZ9w7K4%d#P%Y*!VM7OHw5 z&x?Yzv_$P%0lSvX=?0FT4j@o=sETAA5NS<~(qtu?O)cjYYPxV<QWaWBmg$+<bEsa! zAIlUBlfev+*w}Lg13XJ>D|C#_*%5;j@!t9Aser%Dk7__XotQ;Q6tiBs|M>8T(mo(2 z;;HM8)3?^&mk^tDD*=Rj%*E$-w=KrSQ`3o;6IbqFm_gfp09S(f$@~iZnWUHmhG9U) z518992|l;S>v8+MUa#Nps}D9e1_Oa$N4P1}+}#<8bae_s@1fy=-h;7zL5PkG#*UAS zj*j*WOeEtclEWuQN5~1|_xpnl!S=?+_K`lJZ{)9GmLTNC{jwa>4Qz<vLX5cyO_(a> zz6%~ShxuA7&}7<H6<ltb9ICP6wm(Ay$6y#P1Y_`^_^Q?1!i9XLCTu5>jreQ|_4eI$ yky3O+h!>2kRcc)uhDNNn?w*p2$0zN7TJB4kf}&tz4jcv?1{?+)1{?<VfPtT=7Y1Aa diff --git a/taglib/tests/data/empty.aiff b/taglib/tests/data/empty.aiff deleted file mode 100644 index 849b762da5a8d2b1a366ea8f9d3daa87be7a194c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5936 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 diff --git a/taglib/tests/data/empty.ogg b/taglib/tests/data/empty.ogg deleted file mode 100644 index aa533104d6fde177772775137cb7660a3be11418..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4328 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 diff --git a/taglib/tests/data/empty.spx b/taglib/tests/data/empty.spx deleted file mode 100644 index 70572b4587f26b1dfa1b93035b65a90f47ffe511..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24301 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 diff --git a/taglib/tests/data/empty.tta b/taglib/tests/data/empty.tta deleted file mode 100644 index 9cc00ba8156b8ef1b16401b0efe65b6d64a1b1de..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 79538 zcmagGdpy+J{y+YnF~(qMTpQPhh7cN~gf4qrBcnZpT)ND-g(y_EZu`73CJ6~Kx}70P zqEJM)JqWo}DvDGml1l1yKYQ=9_c`C!dXLWee14xlerrGW%)Hlot=D>8p0DR?t@n(A zg4`TP7#U+=o^==|-%ZA>nZ<$pa10BC|C#Xr{RJ2%R2Of;{&%CXFcL=l-+kzc@_##d z80-Iz`~T^o{BO}b%KsU!0ZV~keD;O_)WI-i#{U?{BT;5M7&we0!z~^fWyQlVH3kM2 zU=+se4PCf^OB#$K!9W2I!x+$oK4Z!h9*)Uy_=I7&;*I!Bqp?`THN3D`AeVuW(Rd7_ zA?@MC3cbr%7>y!eFt7|v4c$adP)K7~!MhvWX3%(MvudklKp)P)a#`@sqQG>VA@d=* zXOJy03$eRu2FUZol(9lgnWv0ldTwN07zkIhFPK0J{=><bP#d%nl8fOkGKPfvf&pY* z0mcwuGNMy)3)2<oT46FCiRi<y0cAbiAj|_Jy5wRrL8vNEgsCCDm0=Mkndg?#L4hlo z470>^-~+B2t!<^tnX89!R56TC*8Pu-gh(}*#jCI+;pT9|i-gInyhLQd4zfU3Nan+A zZA{9S1%VV84Yx5FQxHK+#Bi<<IkSX>alUH@9SXH$&=7c$vw2|#^m0J2v>$JyLuWMn z&uL3cbtvw~q@XAmjz6{(Y2#cpr4Rf<ykj<Si;k-jf(TJTxUT`|&kS@@1<4!(#XuNr zDbT<Snw4dSm=0(egOvnCfFIxnr;QHcY%rZZ5KM@*Bosx<3L#J>q?jNjh(sR^KB4g> z8C{CkAuTaXTGCFzgy*Sc8E}nfAQiYssbb_s)C8ah%$dE4!HP?cfOPOi48{XRF?kgo z?~M^Sp|Pl+@4iG~BV56K0Tl!H%ILyCs<M22zL^1h23s(mGA8U`AbpW{<)Et7F)>mb zZd+mk61W}7n@Zpdu|BCBRs)Mka*B*@iTbe;Hv@U{D4|ygNkG+MDSH1$kYr>570e~n zB~*YBM0ioSKpIDN7<F*g83n%cMa!Ra$PkgiiB?Kzq%SBUjiw2l_-GbFB3x52uyt)d zIFMKlf(lI$-Wn<&Lc>uNB!TL(MD5dtItl7QI2s_Q@SI3eh$&bKdSfglBn#s$A=XEp zEg|ug3xWT@GbCbpDFw;46i_(=?<JN7<SHlanr?RIFpCaj!TDITvehZWASEf1k3tHb z1V?g6(^#<?UuXdSQ{{!h0t)r8K5(a0oB+B+*OEA3KQw`n^*Jg8Jm!cQpIeoeprivp z2%*v;t{eeX&gS$&8lhAIXE}meOtKQGgCR?-B|+eWFed01!vF!Y7O)Hg*oS9u0cKWF z?gkjR76S!i1Q~5~8uBN|!KA8ut`ZAfS@M>!;7t%h1t&<)wGSgZcm@C#OvmaJ9Xu$N zCpRw`H*5AMSJA;RLWG=x4XJ_SbTFI*z`=cmMI@$--d97_0d1xdyq>GZ6w?7kR#~dp zz@!?Rm<8a#n7A2T1iHyIF(rZ1dMEJ$l2BTOf@p)$u^8Sce2NJ=rA_ldkVe1`f}q2F zIfcrESdb8sD-7XAi5s&6QzHBg(ACDbDA`a&vb+S8CmzgM)XL~Y5Fz^*rR`!f9*d6H zgF>5gk4pFG^I;0fJcD7y5QrOq!IDD>BUYv#)<Pa77jnUC0#XMk!x!S#3J*>t)Q}81 zcwtGZ^F35*9g0a96~HQc%%)S|6Va@cz%i(SP!J79EU#!0lc?|+v#g+7tyL1Hjt=w| zayY6ebO<u=DOQ^WUVvEwZ<AwOJfYcwzr+$r5m1MzTufe!iLe@`xST@kWb@LC%nSml zaxs@2q$D#$Awx|^*ioV^%R8rWR)dV3rs$Q57o5$9kFds&qNfI<01L*#x&SP(8x=5s z90!UF7)zpI49=xtF$2S~+Lm(m+I%xWjo6IN?_fxpAge6PeVK%xATkVUN0557CB2tZ zE@wAu&5F+l!KjtEf&DDHh~|jG0$|KKry-(wF#A}*ZS-CS6+DF#L(xcFl`fJ+GN^qu z-3;L^9!5orA~C2T#9Cz`k$BVUSx0xV;D($c=?AlHLhLXdW(OJu4K1K(I_cV$A|b7F zSi(U}siRm93!--rpNlzS;1T;Q1T)YH69H;}EDDICDTyFyVf_*}VNu0nK4>olHc6m^ z3@HYqc?Ro~rq11FpQ4g5OA*R0040b(I-<rAo9&`?HXr8R;u%!6xQL2W$U%wP5GN_N z{xrOCGR)`#s)(2hj-3r4K&B38inf*t%j3R%G^LVu&^!jf50^M_24oQ4)EhIW*F(xr zm@n!eAS9!ocUqrh8RH>+mB8ofM1w9;gd~8Dh-#Hpvf}u_@j4CEQDZmE+6C`cS#;i# zlf~tbr+DsR2!Wge=qn+K;1yj&XAA&ALp<mm-~uTL0O1JYj7YbjTR<hHYxj}MVJ_FQ ze8GNSFkD6tbZUFdml|*xrgwPK$?-`PJI=aezUgF8!&<_DR8qVR3`?U=@-h2k(YP7k zKnxz0aM+HZbNbYf)6P8@O^JvS(jBQRBr{Hf7T+(4E^QWM@J;qD)_?~y^}3ei1DhXn z)i8O=g|5>#6&+pX5B>t>YBi##(0&1UY?J|T2TN4>LRv!ckkf*-5qNLmW0p+c@>Dn5 z(U^*|9Meg6Ue5k;iRI>#Ff_v#SO%E?q^D6YNWr<SkC!iSRMnBui<*_uXpHBS0l5JU zY=|k0Q|CleE8o#KTZ+gWRSzjF$MvAnkOH``^oj%cBGw1zkRawdfUUD*b@~Qut`F!1 zXowM!(eMt&6!f?oupQU?cb~n?qis)6vNuYddL=J*oKqqyT96g3n@~7F!E8ipPL2;4 zFDJt~Scx7*3f}GI_p!=VbrQ~X${7+Fwbz5$0j0WV7kTaFatH@6c8w{w*zvAa7`@N{ zJD+sN*PJ6(<-uCf<nr}K>^YFk$y^<)EKUN$TcZOEv*d`|=&4D?(Goes63jJVe-?L; zn-B9wizm(GP;DU5%2f$|j@4A+(Dy?bZMNWu$Ot;jJAA2ld;pln*%9Rkyh@`bpBWNI z9RwFLXD9fh$ZXg2*mB1O2TAvnlPH!RQWttJU3L2s8Wd2jP9N(Qi(cl2O18ksW%*~3 z<>nAz8vy8JQ}4K$U@SS^nU36xbO20q*4CdimT(|&clcPJr1+J~X45=Pq$kG5iB4Ib zOS!LiKD<bQ{h8)j98d-(7B~5(JM%3Kipo1FQc5!q1qC$%F&%6o$bFV)m#&ehLe~P0 z7|dZqq;b0R-0jKbKf+L<_KuZC`whsv(a8_Vv4MbIZs)j*f%Cv5JGWz!4Fcsr8PS%- zr!<PpII6{t9vzd*1xakU-@&H8%8(xS1SvSzN5b!zga})TQoS`&uLty4mhbPkocHs? z(t+bN-lfnl?HNcf?s{tZVSh4xzu9JR2#|X*@+&k;gVgJ{Gt6QN4W!4*SxS~?^OZc1 zuvl_2$HkFU2phHDpsZ+G^Wgz8+V&7L0iegrF@DDfaIqz<9|r^EY)2Rm*%J+YFo}T% z1!N6*TZ(>Nxb5@T%b%^4DFEc&b^VcQ0wq>wIrxUjRZTG9?#w&B3pTy{z9BVkFJD+x zzBj3u9!*At1PMbdEycu~42a@_zrHe{ylQ9r#HMOzaA|YOdjV09?5*?;h5^q&Yz8u+ zP$|sAxh%(~MMgBGzb+r{JKt>_`;;4PIq<Tmd^;#IdG^q<-(BXptzLWp!-l-M;$HUW zfkFRM6hF|0B}|R!U$uaNS;7KsBMb?Kb&ii0pD`2z(25<4xmHGGD0p{VRuN9bK<D2R zf9zmD`6}~Yb3H|BCTGuCFvk)~95Zm+XP3Jq-6WUQ*!cJ<C2$ene$S_~OB$=QR|P5K zgX}`>6P{q`0!2Lpa`^5_kd1SvCU@NdSCPuiM9AsIdEt^R$F_Ksn3eQ)1PP*Q-J}VO zSk1@hjdUdcorwFI7VV#nFi4Sl9yjV8U_bseEQtn3Llk@YcV35{;5RSm^}yTm5<Jqi zCB6w!caG1OGsR|@PVBD(9tF>;mP?KO&7-`?9%v41{`q(KGI}Ps8eKvjtf!V;pMh5q z4K}IN^p&r^rcqV3A^IX(4ESvOXyM(@g^oH<4u0g`bve_bs!PLU+AkbGGlVn+T5wf( zhd`ngKwuTfhCL`uG~>f8=p`0~gPy^rce|Y(0fHqC>-J2&Ev09I6@}&7V>>!msgQvo z6iP|^CEHIfAV7e0geIW68G%V~M8c#TK)sZ+{b{VG2P_6j)5++F4jh|w{DEQ<vcS>6 z9(58c8ek=dzkgQ9fkJAY0j}|W$CC)WVYLKxip23Q$^h6>Bi9fMaQGdZM@dsK7vqKK zsy6#~6skI^cCzzY#3-o<StW-*FtBKzf$9$s27)XUx@{jl{x<1T@8QfiZLa|~y;vuK zy_}#U%K?<)SRd_`0g@5JUM_BH`uN+x9Paizd~*Pawy8q$K#b$7yFaY5)1YDQHMv@V zD4UR1d5O-;DSbZaG@aN~Z*OkNZI?fAKoS_?0bGdUAnaKFYWZD|1TIS0e9J>dU->m6 zUvC}_3*vNcx>!*=Uo2oTN>~Gvlk}Q5v>&I2&Bu8dXhl1A_xKN2x+|(l0BejrKhuk+ zyo3-)|LZOWAezt|*1jb!C+z2SId2AC!S+MpZm>Qaz9rj#mY~20?e~0nJ!flJO=DK$ zHvi0on~?@Df2?<?t?_L#D!mwo3mtsY8GSy#`cCcAU6rX#>ML2hZSn&P)A{nvnqFfg zh?rsrDjduaoxHp2WPn?N@xxN%tE72(QeVQ2Q2A7s6nA>yy&U7|{5g)px5gK6+VWg> zaktB&+oF?MP?x=EcaJ+3t2+LcaPK(}MN0ud3~x)E9^2(Sr@e63mxb!rxOv*P4kugy zdC)8eJ{xSwujHqE;9-S%#$caK>GqTRao?ovD?c{Yxp96fsFa1$bnv#O;lIARV$HyF zcAYdl1?(Vax-6$*5VgNdJA`;a&~iQxF~9a@_T0#Cp1=X&u|<KGgFXg$A^i=CA5ZO_ zQX%_zv+pL~p|5lLSKW(33^Vf#@)A027mx2s$UEu@?81D?UA69*TS3XS7GbiC=D1m# z1Yv#!2tsdLjyXD`{1tfLm=QHd^O&||08nar?cq)jFm}LYjzjUGzHX&eJj|xXwV1}2 zx)jr3%kLuUtJ$_W%yJit7}fE~<rNS3i7u7dE%-b@P(Nlhe>3&u-PVv`G1TmiPS}6| z1gz%o-_H?EiOWF_Sn&DWz942C-O!jIBA$WEatg#loM))&SUhJAf|2yYP`=Bnulg>k zlHygc_V&@_l|5#5M@4!Cyri%ok<1}3>Oelu(~7-gj1?dB?>J;*PU!U6$7Of2k3&d) zBXn@68X*OHs<z+x5iZ>^ENZY_$xRuYVKBef@wiUH<ZF#`&UVDmgj-O4O*M_*ZO!!= z+xyTNp1V~f1SP;`)VpZ2Gpd<7u{R9&ieBYBW6U#d+&Q0uGkv@@@9u4spDHMHs40|A zJkNj)vvBJ88NdXPIAHwvA9cUVwa$6dFdjFuAxG75^BM}ry5;i^>3P9fx$(nHn8;ya zHL`>u8Zw+{{PbV@&VO{KGMaB!swr`)dQ@Ha+vPeW3<B}WAp6z;lq=v$a4M*DXBVpG zu$0U4=#JNEmQY4@yf1&IpATK)j`6a~9p_m^PI>ag<&F!;5L+aM7)+5Nm?DX10lj;l z>d!Mc_p6YHM<*wD)hboim6|;WUWEmW*~V%=U;f#^PwUn|Z{*;J20+Jr%dUSdS#}BZ zhGtWf8>JDH&%g+I7$n{gDfz+kDe$al$*Y}I>pJcqR+_Q|ah_;JUdsZU>7i*F#r{pz zJH3!l1sPz2_1!8r*s-j5xd5yHq&4on@xG{(;gJIym<Gx5-JNvUlL?FfCul{~rUt;& zKRjO=_@WI5CgeW8v){%ZJklGeIleh@S>AnINVl=2!4o~fsiFKV8?x28;~bBg{Jlv( zt|Y*ZNgW+u{lTmE>p_lk_UsZnc}U&zDs`WJlG8946f6T1f1Lk79tUz6YU+i1aP z_!5a>mYNbudG>tjK^fQa)o}!3%dbv<?Qs@39o(7kLB<*8wca$2#CbVQR#)VBx7<Yw zrzQQC6*Xjdj~S#`9Oe-5Yd-8q-+pH;sRUB5CLaPKKVI%KF1kZVMYOWF`L7PswV)w1 zACtY)wWp{KaYDC3SLf;6;Q3-kX3K$xO9w`l28no>tw+H=4?VPf#UI}qH-j0R&9R>z zJsk`_R8u3X(>G@^v#11LDZCC~4PE&vOl!zn6S7WvYUzm;anuqj%&#f{PVhkvM_$^p zs#*_}M*?RX((;vcX8CsTkbwFZq{?9UmqkAvy{<b+iRXa=(I09ShU7CC?w+b=U%oP2 z6(tbyI8?n5U315s#R?^6arj-=A>bF-zaYuwKo$cB^2V=-3N(|YE*HWEM&f~Br0hjM zeGuMcmAg1lF%Br*QT6Q8=d`q-H_RHO9WL+$z`%a%)AAP?5G3BT_f6NfQ%}c3-)hCs zZSqE%2L0v<Zq{lw(QT^g&WdRSoWS}Y+6Ok*F=UzLKjt&=w(t-0R#Y-N3a2?|0x1;W z=Ra=6rflfJB8MSG8ScXY^K}PZK4<M`G$t^Vo;9i5_>!Y$hHi4GNf-HEsUZisGV`L( z4^HMkTB50iA<Hp$+R<QI86#!8k~%0BB-ojFv8Dqc`bKK8E(4V&o!FJHRN>T<6@KTH z3mdtaJzw)jjS!QlY{A;JFNaK{L^o@#VZ%-nb=7JC09ghuUyY&~7<zT@F7g~v_%U2< z%Rh~Sw1C!IR$WfKbRuSnPoCTTSI^H5RrO|=2kkLshteHuP8%58QvaNs^G>aU7X?Z{ zz1p5mZ09h}c=_E>Jtz$59UL0;0r>^9NuOG)f*0zdRI7P6!7k^(cER!0=k+La;CqCx zMu%JlNGHrDbnKNZ7in^LZ?_tWWw7aDZH6+55R`}3V81Xnt<2l|>4(M;;j+%sis=g1 zZXk=Onxs<Sid+G0!QJDSbNfKTUw2LLF!S~A5Jxa>FLzYYUa~iV|I|~p=JuS|k~7IQ zw<lh?YPvBS6T~1D)2nk;d;r$@(IhGu^}&}Kd3%37V|t`1bc^xjrxg)tA(v+c)BxTM z{OpFUaZp4EuYDiukf4Rr!L3n)wy!=g<l@aMUu1gQdU>9F6c+T7rx*p0r9!Mu{+1U^ zIajdS-_f~zGLQUbkn_jdAG+@cT)tS7i?%^x4uV6sAX_Wu@*nGa%t#!GjZxT!oyOWo zOp(^1-Cbj@Th=L)b3&I?I+X07*BPE7oB3+NGXvGTdlSUw$N!j?gct*q1>G*6c|2v* zNoY`#a>us+x9Ml~OH3c_&g;+2YiHJSDv9Obey_7h*!s851blqDnYNkHJM+G_PCJ}8 zG?Q~@jScLH_ttp4)mLN>1U{65YE!_PlP-rH2A(Gzt=<-zZT%o`U#E?+0uj7v=i4>R zM;*0V?m>5cJ9{X7bo1{qJq)u`vKTG>`62mn1M7PyLKp5!tEV}bgXLH^hiXrhb;v$u z)<Nizbyr3*f=Pw0-OpEd=e+%!<md4RqeYKxL(F1AJ3K7BXn4%v*i8A2>G>`6U}v#| z{fh1wEpO|Hxp|~)PGr*NMl}`P4(679%OB>RvMCg%J)r7QXbl5Tv?F<VOpSYA(0zx7 zY0SIM&`g{fckJ`?lKQe0v5zXVWVSw-I{<{?p+|)*_7?H*$|$-%bLZLQAy*vP-9T^d z;xCjq3{CPtPpl??`;^(#<Yf7r<eJ$bJcsV;p4J4<sHsv0!TM;NEHn5;tNoasSSwqr zxj+dOcQji#oZ@;gIEBY)yfW=P#7yXqZI0yeXy7CUCg=KQoLU<E5*_`ZLB>rDce(t* z!hAyBiFeU>2CoJN2F`#WLAUSER5Sw`KYhy4elYD(hn9^OO(6)U{dm#^_A7$!-)gVg zn4q<3T}OW|HEoQsp-g+iq?qH5Kfr98)`{nj(+=2~Q4KF{)p6{?-I<rpF;+5ACT@C~ zv2O3pVC%KPiXh|BdF`-iKX}TURwL{R9Q6P96Vp+@C^<Z&L(L|1XI`)yx4TB2jP){4 z*|XxFrik*a=yk3{QG$t4*YKRFhQ(BhpxtoYzPxh<pa4e_o&xc4ZLE2ezIcC8K}PVL z*Ml7uZ=GkRBkLXF5m|^i6D@bX)S?Y6a>)bR%496ktNw*t`!@NPFFomDEQPmvnX5Jw zI!tKIOBtpaIQ|rWbIN@kzkEmjeuv?O1$GC6UBO`ihzU@%QJUn5j8k}+Pq*`gS$@q< z<C@%_&<p7}<Ss30@Ai4WW*=y5XijF7D5ur{bP_z*w%9Lk$Xs7%*c0xC^n$Hgcfedq zZfMko-H@4PKxff;^EJ2E=&8W|c_`&*1%h~0!N-#PD-&jUhy;ZO)A}A4KISN}&_I8Y z^BpZar)_?Ion@TRMe@2wzwqcI7+YEqGMin2J<ikStetuD3ql<thaGb7d<j1k8Wofm zx|0F8F*(JFwD!JP3wx=X;H>U*E4zbNDRPTY>6ASgc9}s9)67LTbA#u^5hK5A4`u)& z9nPzvw}4f&()jI{p1HkEFQM+78`FB-=tTz!2x_4wAx~DRPwM&A{9)RK-Fc|EApUYt zn_uef2|)%6cjk34*X_F*lXa7skbkrC#<WU#<j9qrY$Y<de6jiK>51?|9^^c*3y)N2 zkyjnnc4cNXbe-`OEV3AZf#%isF#E6+JVC;Q<xcu<cP<B_VsvzXfl-8Sk?*Z0!g~&- z^N{u_Lqtu1&LW3`D>Rz~)Pbw%7aWZZR(mTs?;P3hy>EDq_WrOxgAXZHg(vT9z8G+j z>P)YT!&$mY=QM3XF6=fo7e@+*J9VG_vau)2)5mJC$&C!ybZ{8XMIn+&-*;dBMg51P z{J~n|BfSoF!cVz$DsqYgWLdz$RVEd2qcw~Eq*;5f-{~1Os5dWdU4ZjISHw?){VQ+5 zFleyNunvObu^nyY2OO?_LV8~O8v09zQl`UD?t!x*#sNT3uyw#0nombwT>j~Y4lfBN zussYz8Mzq{Qd*ZBe8BXmca{k}Yh?3v_utsLwk4T|QiPZZ_B#)hM|@?r;)Z5S4?EY+ zE8~g#hE?2d9@8I*eIIyKR1e1$4C@zE_Y6k-BlN9vh=w+72kW)8E=2^OTe#t+&PQ*f zSlxc}Uc?+QR%xEVyt?H7ffE4WP>L91M?vBMZ?7_D;JK~czZ=dczuj$oWtv5DSDH-N za416_+*6~~=(54ElS#x83q_Fy@k0<Hqyanf+sB-q04O_pbAScFIr-tO$atc$cE+dC z6SS%dQihaCiaD^_kE0j2nDjJj62(z55GBTv)=SBCJ5fI4myERZqR^+BfOW>L2__YS zy!7E!>ka284{NzwQSI~HM!z<V)}3c+2P|^sArU+)&3dV;Npk@MAIur-uIkA64)(KP zBlCgXvWJ^Ks`zx}l&y#xW$kYde@%a+ac4SaG)#{XS_sprAtsRc*jsPW&^LoW-|J<N z+HXGGvh2?JG7aKM0xdV=oMvh$kwAEE!qXSo4lJ}VYIwBqstpuDK$-sOtrf{Uj^xxA z<`u#TK|>wEs}@U$gFQAhRR4AOXZ;I$DhL5YELh^~a|JkOB6!}%+WFDtY8Ajf-3>q& zd5Q=JE>){=aK{AgU8jI#ql~kA27^~w=_)-+(|?5U9M$TgoOeVGcuMWXS#?_l&76G! zEQ9o#9;*NN<NN(B9Hz$>6g8|yOKBaL*+B0x)XE@e8(WevjtB=gYzE(wf#sr5zG6W^ zZ%r5F5s!F~B&=r8<cF1}b5wbPyw-<@dRhV`zSbpj5%`0FiIblbDZTLL=L&#T<OoQL zl^~}SsuMzPMWeS~=aX07woc&aGml$v%04sq%0%#Ao_91p1O=D}&lS9Q=X&wna?3Cx zWq5eOiz_cQ>*?)@h348mkm$$++@TJ!GitrgKo;mj;EqFcHilbw1|MpisoQvF^QSA4 zvmKe&r+Wmh_8Zpyj@9tDcy%*K0^_<$;)gmIYo{?FA5Dc%KVChz@rBX_ROCE~=rqu` zbY+x^>ZROzSc(<y^sww_Pg1GqX>4QL$1A2i!Ac_G!Zo9h49&LCAL%jaHim(mS}Hs+ zj{>h;qVKH!Yu7Iidm2hgeDyS75nMoDPoNuZik+vqn>X0)cKUhGPd95<-2#q6S^%>+ z7ZBNd$tWxLURtyMiq7Wl9C`B!qeVthNt-X(Fk>Dq`ls7MMyw@UpUu!CTmkd&Tt(91 z(aUeUA31sbI_vc;05L(7SBcZN#-H!~^@zF{gJnV`&94p4d);lgl#J;qJ^E&QKHsQ0 z4oA!5HO@i1Won1ghqe3@uTML)g&&0QqE>ii@v^F~aso2E>FI!;l=}G;IXGs&3vv$T zbS|)_yEW#;x2-FDg62mXJVfA>bL+hBz9#sB5W<_Di1%JGt^T(wkkuf!w0WyuB#-un zx$W-^b(QebM3#WV32FlnPvEwlFdKRf?Z0vV;+2Qao>)!f^I8?TyxN((&V-Gm=0IMa z4tuH=>YNu}?>yM_u-=_c!wA<zK^S{N9SB^*K*UKnJz=OTYW+Q=S+Zgw1LSq@YnmH& zQf#Q_i9Jq0%JbUz(}2V92X!I$1a(AOHrSqbE!cucf|0w*j{j779LKN<=j34}=ZWyY z+<ffZ8qF|E+mO0k*yyQ<CT0~d*K}u|o{B;$oLY8%teMX;Zk=ZBhp^s!wy`@19Ut;W z8(VHcGz>*sH$3`MeqL{XYD<V2^=Rmy_vgK+btB7|;7+xCGx5gso4HD5k^jMwk4cZ# zobjBppKtoj?@qZM$>@Bjto58z2LcG90{2DT1foerjzX=_6{Xuy3b9?f8bHg3gaeZJ z>i0t>h9RrhTEepxB6>oDg6|0ivpoLp{4Dl|hnrH(;U`KCm-H<~@<0g-{K;BT@K)QB zsRY7T=OQ?IcHKNbw;RU=#;uFHbJqPSD}%~}v2<0=AB_!1I|GQa`^Or+p72$)3hBt# zri&>Np6V-~qZD9v)|1sC)nKsetyvuSh+fS3Gv(T2o-Fx!y;IP#%uJ<x;#O%F3XqDb zJE%Qh25|seaM;4~yf!Qc?xl6j5?syThCe>;Mq7_Ok=<@dbvBggS?;KMy>jE1a{JY) z5HC*mU<b(zt?UlA5R5*Rcv;N>d+l)kLOSeh71WPufBW_E%KrD~mxl+eu}@<m!?DtZ zUT!gB_;B_hu&0@gY4dC$LpN&z=Au%I=M8nG=z4pCvWoOzcy0du>+ZcdXv}OAoU%84 zp+-9UB9vfjB3g*qmP}6s^n|9|^!s5VCW}JU2chl8ug>Rp7K$f`LV`0+G+)^ChV-!O zwT&x9vz47M4^}x46XCn)k1QuYHim=uY(RuOCX2U2vZ<d#JW+&hj?h}g1pov8>zr$z z;6;TVJlVJ<U#s)IKB_9v1Zyupyzp)F=$3nKUMlO~(cksqWO&$TrHR-KLiOxQ)KxC3 zJWN0vGLIsc66p`5@p}yrMSRGXt^+`ea14LzwCo|EiaGK%81|304;0+c@<8v<w-eoZ zKL{^+k`JEU_(sLH)CVmMNt=*T=Pavn{_xO$x84K;)}+{=h4C7#$%i{le#p%U3OqU- zo+5*guBrnND2Nn?isCoVW3Kn(4MXEOL;~_?D(ByYUDG#VfmoIppn4Cb6<JYed6#Bd ze||GhKn=A$jOZI4%OhAthuKlizo;N+&rFfG6SL3;|ANm{qM=BTNSwyEemzmIQ6W`e zeYgD1hev6P7m(Q^`F)G6VSVGQV;28ozjN4u9)q?UjCX4;GUx0QBf<cn%p1En%SyAQ zAhf3u70SS#l$)YE=Qj+0{phg~e52nP?hvzkII7N&4FqVt=Q;~Qf+4n)cG@i0yq<7$ zI7v%ilg0}IrC~FcczU7fyJg2Vs5?Y<b?WEW8@0TS3msbY8~m_mw!yaShZBFsZTrNd z;(`vmKDzC`+HQ$mwzi%|^FoesVaA4E`pf_{;v^?v0e909_bj)-EvG4q>8P}I4TT#s z2(m_{bh%yb7Bgye`MdLElbPnozS@m1RIVi!Dpo3VJz;{-9oX}6@v?`r=aI87n0rlj zzeVTB20n5qHdLdIO0oO9iyt5TrCNmpa*?jg#4ATSS%}F4?C5r|wx>xCDm8)NrvT>< zwOLKIIj#k}l@(7<fFE<M&jHnDtTVZZc2!W4#x`U#VVR(t>*^LxxUPBsHPeA^+7cIp zSPII9%0^V9feM3H$tD!_4*H=%4n`S6$d*iZoGajUfy4@cC5kwt!rr$9yNPWRRywZ8 zU0|WT#Bqidw$FIpgQwYW{L0BydbE4*>);djg5#_-YKfYwAX|_x^Hxj{Pd8n4htk3l z9oqEuW2p0oCQowzu$oo(?iHq~VZ<XBkaNMc(xGmNCaq#t1=)&a|N8yH7mSL@BCE~L zR>=g*KP>rI+|r|Rk>E<Gjk*N`4(JaNl%N5x%r}LneABs${?xira$nw0{SHm@7wOX) z=PZQd5CVpc=C$d=##sMI_(xQUKjKJPm2e3-RP>X&UX-xT@V@JsnMX?`VTCVbxu#Ur zJ=cX4TA1;NrujCR1C%(Y^S?~4ja|2*J6J^(Q`KmlAtHxJ<HpWa*C&8(_dnIM@unm9 z-BY3fWv@FC`}LvLlh#Ii*P1wa3`|orpY9hq3Oa%<PQh+By`AI1hY;m7PasWe)i3O( z=&EcSyZ9lztNY4p3?T#>@W8J%aD>JM*QaxPcCK)bY7JS=g95H}VK+fuFeBY=H;#4J zH80#-Rj<JYH&tiDO1Oiq-SMVo22`o;<a%^Ig~Bo`1a^3>A$xsPHohzwZho!UO4ih@ z+wigVyo!sh@&nmzsy45t>BaAUrnfL%s-MU9$02dwRpLeSJw{o$c3<Rm3rhIXhYL*w zyhA<P_IRWh|G1+u0}+U>r23xm`YUZ;Qp@4HDqg1V!o@gdd%8MXRZUH)g?pG$5@_Xj zG`4x;i#a2SEK+tw(l{kz$pQ^pxM6f7DSl8*V|7+6$07{wu~e0ujDSmp{C;gqn*M_( zu}3>&<I6*$t726OF4nenDulo^T#7F|QP!tTWnehwf9krQ6xl0hmRj%yf?FeLjg3Ps z$(hyuS!j5n%ppDE<mvh<hOkkU)zP967<lv&d2Q+zWjYnBpd1u4J~U-fFa}gcgwELq z7)4z#8Ub^Ga}RA<jzOGPxOeZ^@B(5-G}tH|>Ji-!IXx7&=2=T8n~bsJ_#252aG$28 z<W#-*d6DU3g<?ckaVf_xNey_DCt!9gS|L6Lv4h~n`07yLt^P#d!UYT6a{KR{_Z}RQ zwp`-iXdzbYU{jT9X4j4lZ*ERssoeZ2VO$Xx_bAUJJ0S6)34n%Qz+Pgu`E-9w`7^`M z;ALNPmFi7!i9d^yt#siNi`3m<`$oVKUPLkD2@C_WcN^ChAquN-s8rjzyzN4n>5n6i zr~#U#`kKj1sIm8j_0Bv1W#g|?r$;YXU{+#AZs#*QUDHB`^^Y7TY8INF`+g=abY1z* z>U_2Xmai3jUrUW}7*dF3aH!{3tK|UZW=(QeMwv;#4tZ@)XUK|`eeND@-rK)5nOJIN zyKNC+BvwUl$dkc79<l`dVi4#P`dC!dMb&2YXuR`UL0xzK{1AqV9)>e{7|V*@I>J!X zXc*;@)h;%7u?$BZcDQ-XX&V_y4QRV`DSkvDhoNiw(QggF)KfGV&Xl8<nnCPf6>T=P zamI=Vzu51G12Ycbh&ZMhqw4XtJ1!p7LE1yh$&2?@iSMZ9yK(ee(xffi!cJK;2lJst zhY%aD?&RyY3%2;_=otzj8E{$pb3YvoQ9KEij|vBY#R}PiZz%IogM|DLd}tDV1Xfu2 z(sV2p34}{ZHmNL?<7B%nx%<e&5$VIy<jP|!2D>CIZq++|OT}!4Shb9MxU-3_6cA@| zHl9YtDAgIY37bD&DNv&B+YHpxoopAMiOZZn1e>}6l*8v0+r}71Uo>M{jIguuGR64= zR;#H|-{jgYUsoP@p!0^K)fa(bsf95M^hI-Y)=y^Gm!=SIhOwv#$VLnNnWy{xq{xG- z8N!RC`1>df@HG9BZM?hQ!iA+b>>osvQQ8)12If~^-qxw3t8FN}n0N7E2S#8M&=;R6 zr1#q|wT)ojiuM_^<Fh~j#$()m)Blp=Lj0H$a4Ai`SEy|tqejl`5c`#9LV*p9&w04! zmylN-k7F6yv_i4!`)d`piU{Gd5AtgMS+UBET8Hp(DQE2b3_Q^z<RaNN)7gtmqMo1Q zPY$+>lk9;Etms$mEH9@@bJ^e$jL1O%DWIv=-&cCNpU?>sG}(G>Vb^L8f$`tcR&7YZ zAzqki&m+iYoK2q&&u}mH%|x6zAbsq#Tn-RLi-DXbj@>=^*2~F7G0e$6Bg9Vv=_P$& zDPRQq7)tZIz%>i5hIWS`xT6V_YzV1xyA+a?aUlM3X#@Or==7UZbshNAn$y4xG%PB- z)a+pOOZDXf62?-UpLTVEoT#t_&DOe_RH%(M-0%pX`%)D;7GR$Gr>*@7#ITwY-wO(< zwC;|Es{Qf1;^Vmnko=x0AuOra@n(I?0oYCg6$t5%mY6b#(<Zih=-|8<^Zf)Vbq|() z5Vbz(ppey0)f-C|Zj0lN=4+nro=jTCw<Oj?!6zd_P^f;QM|7I?#wwu-=q5r5LyS3` z9d95hOuSH$tx6U;tbc6%SSS6W%4B<pcjvSE-o?@vRm~jyU|5Dw|M0_Slby-dN~(qT zz6VCXv-*Ujp3atGV_Vah@GGPsC=1|DXcZ_MvTZ`1CMmzcE4y>Tt5rV8%lyl)&7_Aq z`m$j}z(+Z-Hhkdu%tNumZ28HMqCs>JQSE!RN~JAm`z2T$!zYjq5aTYe2LJ~%d|zfG z?6GS0Iqm(Y(_Wk$y;!a=tzmt9&Xd(iZiabBBtyfJmTVG5zjJ5x{*Jzm!LQOpf?P3M zp!KzJ;~9&L3aNfsokGAF&s!-G@E1zIYMSkrp1jA7=5W_OSuMhdM#=9TOOt|ex+?YA zB(az}l1OHv6l<7Pj$4dlVbbT39#)F=3p;X>mbzwxOVqN0HE41L%K?n$YQ)PoBsKZ% zE<EP1c5wHm$AvTs<`akCrlv9p1R}Grl0k`J^&8k<!(*&NFAgD0D1aChTDlnGHT%Y@ zNo*}q;zV9n&r5|LnaGo^Hua5;gix#8B3??;eCMQsmFV}~oYOG}3ff{EXsQ4sBEMmc z%(yjwdw<7&Y&K44RYA*#$}=A#5j0p<c_Z)09+|nKuvuP!C+Zb-GvmRDuOH$TeE5~t z>V>ZE9LZb5IlS>xd#i`yLLYmwz<M233{v0TX(I7EJ4cNmr88fz|1DA_{s1MY&bIK9 z(XuDcB>U5rEKORPY_0}dM>%iqp2~y%?LxsGYIc4Gtk(GMwkG@`2Wo@_H|eG3QI~%< zov_qFeUzXFPZs?<^NzZHk*-rkehffK#;G|90I?GF&;70NNp9Z7>TD7(uE~y`RBky| z>+)DZg*?$nDF?TbB&jOVz)t?i<8k3Je}qJiBnee{+Mwvlb+Ho7iXNd3Lx{$ztyVpI zP9w=rheD7+e>1f`+?*tgyl~-KR-##ec*FbF=zQ+I(z(m%Q_f+qlI{XOb)}t88un(d zxa4Q}B=q-Be!CkIE1hq)6OQTXy$_D%>1&5N__A$48H3oX8*zQ=(cZr#t?EgH0LCa5 zH_&Jr^#sB=D2ljGTZlB0M}k8$;CL`zu?XPQWl7LlD1EHRa#mYVd9_W1^AQh$6(pAn zCEHLX;Rx&?SXGA}{Pgc8hPIx`huV|(hP8{wQopSK?cwQY07h-A=pUwZFDip|isa;L zR<Yt3?C*$%7xhW}TqtH%{Iq%*@B?D=dSjZJ&Q>QgjTXe4z)lWH<Dy+I##>)%{dAR= z%ZUh=@~N#OpgGRT7L6fuihHr2o(<|7<_B*Yv*N!Agg?evpJ;AY0fdjf!XTR3IQQwZ z`y^0@XsfM^w!Vy>N&YR>`Car(|5B$&Z+xOIL)L(x)@4clpL1dBD~WKSz*po%6k&dV zoxe{#{p@Sb(~bWXX;qQfdc=dl(6xNhN9>9fE5U4w6OuRgH310B&f)M5eQ>4_`P9ma z-x}|ebtP6{)!FxO<anYTorUp`@t`%wdyn4^ei`_nC>cNK?~_&C=rW3M<|C9mbuuuW zMEL*>cS!U*%2F%^n-zEGZ{wwFJm5DSt>M}&oPdg~$BtIOA*e+eqjbp=Z5ihrA#e$- zy>4q<k?W#nwDN3&-;lSwGg=AdMu<dXP@&SKGm(nb(AHLG>q`c4+$bB*x`yI_*@oy> z!NawKJGaDLPOiivT=*?VI)mOB=o-pJ4X}~z6vkTzWFGWq^W49ygLgH+Rt4Blfi1DN z<@(YG(GbNJ4qiBj%{_KYwdLBa#TIS7I!_acGbEyCn4@OLPre9W5B1xiZG;GZRO?Lm z4UWRArO6BTE9_v^dTozzGZe(6|98tSIQ{<XgMTE4#ubTLuT?40@ChLz5|-+MwyHDd z9$8^wOBbk%`}~rK^gxTDBJJkNzg)JsGchdx<x$E)qPR6MTP#fImTkUjz(xpQJgazG z_+t7`%@s-36CIzFPs*Tz%>|U>dDPaR?F~e6nRPGm#tTy4e->&qtM<s+J<_c)<|-ra zo3(LmXV`fI=o^^lAChfT4QB#PPDQwAl)Yyr+VQDMiSIb0C?^HD-J&$ZDzRtveZHCo z3knOMorK9FAEWF=Rm|>QTZ>x*RGa^-7Q^h2MYy1jgYgmfNo03bm8btjDU>^H(>}B2 zWch7H&Lbw+fx~FVu(RzOj0BV*i}-2HJ3DU<Kc*sUNpS`RuU#KER~Q}_VaP+{&|^is zXotpM+J0|r+qAK}`|LqWKe0I}ly43Q!SgI3Wh*0_277N*&1q^1mD>3c^DuZa)FOT$ zMBXCW!T2%B;V0j^)&N7p0~DG?-blZOgaR_4v1(IBB&uY3;y)`ptv3IyWq&UPyY*Ta zvH0@!dmdMgsKz(h#$yefoa|I}6$UW_y?}L*|4=LC9L{>#mpOE$EjjEyFWa)s2Zb+p zw5iH1zF{Gc*G0{k4JYPa5%qh_G7~k}E~px`Tp#r)q+Lzouo;5mw%@g8l_bmk6=0K9 zDL(QF*F5O=bA>XY*<x|D_?&)p1&M;^X(n9I3OG~U;<dfWjwrU^OZ-@VWQ(mwrTBdC z_DhOhq^Q`v=gU~CGyCeOr+aW>=+An4!q2CZ2<qiAPJ8T%@5BnSVtnVrR)IeA3AxC? z|BLy&=Uv?IPeZVVhU5s-({M~ccEdu7n8O7GGO@El*!}EXMyL-9<x)~7C5%4iL}x(+ zstIBw*8j%wb=&@_e>mzvbtCqjE@4BHWTdIAvh%JiKmsoN50Bo0*w%E9H}D03khvzA zP))`pS!Z2Z+g#o^Rh{jSyi?yR?epieWzMj}z~M)y{>jA$jD=&zPEd8Yt|Jy2Wn43j zQVR`WK5v~T(ST!68(Rbh$Ro!eno1(d6~F*88sm^Gj6ay`a1-}jd>|x$mk739d9vd- zyX9^qtjldovS8O?)%XTmYslIAvc<3}#`I6#zI{jh4(5#IER8{~oS%{;`4yja`7LIT zln(Ih1t!Zaj`7X9AN@Z^qJ$X(%t69jd(Bh85O}uX!I{*wx+iH-gztDM=Pxs>0Hny} zb3x<(xRkNl`MK9DDOsIe|DiJMd}4$lmZv#=)D7_r+<*PhWZC+kMe|NA{fTyLwI?Pp zemZPAIhUiPY!LH>y#2{}GHJVEP%t+Kq6oIagcDB9b{gi<I~w{q>#sy5E7Z-nM_KAZ z<AZl8nC^o9BB~bm=yPPR!O`Nsy;~tSXL{<YK==2&u(CG(Q0alL1c9?Uf{lCXg$7jV z(26X5V*b?BbI1>PP}Q$}yS;t|{qNU+;$DPj)$IBfXi6ovOHdLljK5SCWV`D;VP%uH z7Is9JiCRlQ3tmdoOgA_=i`D_pW+ETAEXE7(xozc|`4jO*^MJ6ko}!>5)=G+JsEoY4 zy~4?-LUk*FV8}9ju0a<Bl7&2v7Bb&2h$}kAXY=%_!57P3E-tsyOuJ4g`%-a@-r42d z)^smxPnTbe`kZO|xi@V0qwR+eWNjZOf<Rx5bcxSGyZUcMGpP``USTFkLSBUi!oeRk zh(u`snBoKCJj-;8?fpw#j59|YHmte0C9{IE6k>bJy>cpHO+;=Ln?S>VfMI(&slVV& zOO=~EF7+S$aHc1Qx%-ACwmrSCq>FKnPR?Ra*w!>M^8To=0aXh-IQs0!$mug*yjG6d z9lLtHQX|Iq0JW{xQ_$7a{I?+v15)2=O-qbViD;1#{eYT(sx@+#8ju%4E6=<5+AYt5 z;w0bV5z+2ly#>87zQq~7Te<!odlp(7a1P8}xa$30exiuc)80bQa+bF&`o@tWTMb+- zf7y8o{hA#1SMk+HtV^7#6+6{Xep%9Lv>aa*+23QaQ0ab4m!xX(NGWk-ZD78CSQIh8 zZFSUG#~qEbzm4b!kPxB)_+?8^$c{_K$~qT}9>~+BD*9=;JLKy^gObKMBL@k0+l0JJ zvb1*Lm&PzDwND!U93F}4x1*R5qis$n^-fJT(X(h+VYcs6opnAfoE-2%nfHFTXHO3K z|2r*(GgfZ)<g|y*C63u~>s*#Wq1=mYu2>3Q#YLLw4@jcnXR$@vc(&@+my3DD)B_Y= z$`#vAj0|BmnXER}{ARABicdt3-Ok^T<g4#YN7on@+?M!mQH)e<{yy#0nJ<x+NUF?v zG@Q7f(Wv^*elM<v_xGjLA5^YhlXcz48y@~0uPocJm;pz0b<6Y=gUf9V0nvz{hNdhQ z)w)gc$ol4HnYPT7Z6?va$m_bovPIlnKBUO~;Il4mgl1UogAI$?>|!_dbqXP<2D6ze zkGzujfTB6`Nm+A$G~z|nkdct+?!GGNhYt`(F-$Hu-B-`9Cc(49wxdQZ{Tw~%b1$go zEWZOs7w1H_*ma^D;#s|sEzOyV+a<!AFMr}lt=631?F$}$@jT?DL{Wr!DXC!+1;Gm) zHniMxc&Z3JEbEpoefCT;pO4!b_r<717{X2!oEQP4amt#`{{Cbe&V!B7=4KhE+AjZ+ z<13^TDi>e#u^l)cp1Oq{fii+<wx|1@{A(j2AS|J%Xl^-U>Y-C{2@l=lF-&h?zfM<F zZ|2BLBjebpmzTGel*2tM`4x2oFH1CxWp&?eThZYc#M-C>a&2i^`qv2emmIVw&E0<8 zh%P!~QPsNTZ|%KK&dP&TZtz7g)*!X-=UCCVzKl;lTv!CzGYe6e&#KLS;N*H{j7t|H zanLHmos%Aj$%+8zuXeq4kYAA<Ff+#0IL77zZ5~hT=isC;>60agy9?T`-)37R%pCtC z?Vlg2oXpLrfL?F~@og*5s*@2OCS-Y7y<tNHL!Chq8-sYq7*IK|kp6?GTkqT`R?Q0u z4ce1oy<QaGMpuF_hEdah@N#;jA!)~IL7f}yeLtD&7+^U0{WmXDYCQ7Yty>)+Gh1Kt zC0ApqQCDJwBqN+DS~OQ$)B(<M6E)e5I<(n!!uKqS1^}okOLGl=q(%vU;&3%Ld(qfE zm#aq@V92amvjg#>$Ettp*!-kSoliiPW^w$BrA~(sMO!h1Rr&3M#+mrSMPF3YinKx* z0U`};NTM+3UN8^+`M5l?<+9zlM|$G{3T{gm)U{)2M*%;O+Nj}O$)l&;;Ni))>5=_o ze;c7#VXRZWTf$=3#Zh(P;C_!6Qgj$I(1^A$I4}{kVY7B_ahLhB2K8Pakz##9h&gQ| zb?#MR(UFz|i`%0?ewrH_&(6qA9M}5COY&(2N28JQ)EM>7)7G<V*L1((_-n)Yqb$jF zF;bY~t+ESJ35|r!PXBP@n^c3-WYp)G(m>=6&-+a3F$to{+^l-99?L!7hr>Z>eM@{1 zkz7?voeSlRtNV)gw|l0f4*RuayNM~L_v<yhz%~CL4+G}FNjVAQJEWGX@O2516vHv~ z>t_~Ap&}AZH(~see=$7AfX(%N-)(7{8^-v7+Dgie>;4{ASXh&tbxrOmK^P*M=aMyJ zi_d<)vO4?pgU7F=8*)!7JN4)@dkrI7eK!_eR|PO0iA9gI7I6-LUkAm~|Hs1yg@i=v z>|OZn4ZZAKl<4p!pYLZdq=hqV9Lp?>HT#ncH^x6`%I=I_6iM7?sjKYDI6%=|04of3 zoLzrgW9jU^zM`u5+KbaqixSo0Z>7NS5)tj-5~&YD!Hzapr^LVC+1L7Kem?tHTrLa# z$N(ufOLh7WVvZ4i00nRYCUhf;E{0irNc;7Z#WCIF!nsRtyXvjmkhprnd8Bma_|uLD zX;H=I8CDVZo_ss#Oqox(1G(Py^m!;d2jKe1j-t7+xbFUbq^H|PA<~{^abi+gar~L} zU}gA@nV>dnan`eB*4$1=RxLvH9XD^R7p^wX%}QFjbiIA&^VTLocr*)nlCj$LjRuIY zfjs9Rrq);AcJ;2tzpGvQU9&v1Xim4E;u(%4t(%z{b*%YlMpt`f*<8DpPnG@VJNa9^ zXu>1Qp8Tvjhex78!oms$)auy~LApFX?Mnu1I=QMW8k=+RV6b+v0f-=4!=+ejyM1rH z%ZVO5`%RMx+5c0)vC^{kj171m9SzbICvA<^hkxP#6xHqZO)G@x%R6?Qy&rG$A0)6! zcGPYxE)~If4*c<js-s#X-P+H|$(TSj892%IG=Uxn+{?%M5`SPLm~wwz;~?9PE7sS1 zf6~XVn4qqMZ$72|%Kk<C;|JyFXhKID{$-10mY1J4j;9(}Y8^iFyxL;n8|!^-8ovC_ zvUk>P<(`C^n9Sy<)<5-4FlCqpd&ru=&givXgwPu1R=+ep(g%zXl!2>^R`T5RHNRCB z+^g>+`+p<r1RJj}6=_3WVXS)(zQmMi+yuiH9JDc%`fFTGS0AAH+$6JaVqu&@J%w6A z(MV8$<t#k{=>fdO_L4C!KN9>;yb;P1FOX4vMr)K;&GajKN2Nwc@-Fss`GQH&@1OKd z)~c(j?_w-sX=yxvw!vuNC1=BWa|yGg-G1p8PrC=gY@Iw+q!nVt^k%-_p4Ho&6xoLh z?w`GOHYzzn;*0FJm5e#T+R@{}MI5udjeQpzFVDT@-q->d)0T?19XoOI(m%xU_oGD( zPc{EK;2l#Qj*Dk&1?J|v;8*h>G`6PsPTi|~Z^I;6+~WmP4sf7e&nR0$&FX63U^MBp zw`yM)uN3(Z5}dj9YMW?}%ibn+zynnC056x@=mybvAysJ)jHqz3g2tm_yr383oZG4W z`Vx&e=SyQ|S3@Sbdz%&sq0T|>@5wj-|B6UTa+t*T=6$TokgkY3l$@X&xh5@F+lau= zj=R;-4tWPI0i4a4EPZ!gWBwf|&K)yNbOnIm#){TQXoy~C5&%Yh0m!$}gfRy)CZ5A6 zpCiXM{L|0igpN@LH+!y8*UbHqs0U+<+Lf&1w6{%WjYy+ALXNQ=V+-q?e52dtf$rKU z%4)*Dk41c&6RAT{FJ|pG-%dI}crSPDo`}OG02ZOclNOQoS_O=nIGr~hD_s;>B{$8L zGN@%S&brQ{Mtra<Hw!{P*wK4q;`BSNvD)#Oe0uWHjaz%G<Ze%?r*7LE5PK^f@wg}3 z%Es@FjBS!zF*Lnmm9!(#hO#ZFlN}k4M|OGNZT{s*yxKHXTZ;^*_6S2UiP(MhieL*y zybzGUZI91rSk^kX+KxKBi&3~D3tWxb!SNOiolD8l7oOTDFJ8B?)LItxY12?Zpz|s+ ztVOg?`sE}kSO)a8+iH_lb??TRFM?<A{*3TH{K{{kdbJn)dpvMnne)xt+W#9>2MR&) z^>$AxPk#-%g300{Q&0j1*^IY8d(KL3T6*giA>NjL`5hy!=|XG#Rl3gN-Eo&YznHv} z?a|7^S1AQ+vE4h%y+gH%@#5<vZ)96pW*x7iH;spqio7f{im$tQQ**Pt^zu1ZZ9Ca| zDrGT*o~SBxjD51c-uxhI-~3e%okVJ-Xg>ihNPP0*U(RZB9WlLFb=QnzTMK7zU~XC( zgC+UM3VCE}(tcIf_q2buoRAy@5JvA%D66~b*!!916Xq^z_D;TRh5wLHmQ@icxB5iK zL4O2T{mz$ZzXt8ipvMo|Q5SS6`{a<|iO$hmSE9wE;Cu%(1ITzx;>%C@a(`v@(qpg( z^SEjvnd_*fgf%7CZq$jm&;GvOg0VIFrY&z|WN={LT&comu-p77`Ymy$A2wHXBIK&! z0IX^bfQvora`<O!YI03B{!810N2DKov!ZQ!Wl`n6F|Si{P+oV{xhZyALmnR}vXbv9 zES<@%vU=dL%i&Dcl?+e1gX^f#Y=kh{l_zgrE*i}-A9J%E&<|dGfK+&|7x<s)pQxgg zVV3l0bdp!kbEg;HyP3veNJlie;6}pEY|#S^t^@a|qKhY>%xTG@$2ZhOKFD3Bd-*B* zVD9dLe^oQREJ9ma{k%cZoQ&@BbzN2tM45)z9*GH@5C&*yFW$UOR~ax6U**Iyn{^Jw zVtI+8P7-Ss^^JW>bNWY1rma>0{F=m#jPOB*_;OwE->_x*d1BbDxX5L<;0UgG!=Orq zGMx^(O)U=H5oSrY8E{&CjLuf5?yfrLrMe~?K%Z{42^Dy;w&_fl=A4&MpjoE?+(6z= z{^sy6>H#{Kg~TKleDkq4OGy>a9dGf6jS8G-+i%E8@yVmH+u?aj)6%8PpFa9EI5vw8 zFknLT;zso)^lwLRvO*^^3o;W5XQFxN)Can_dl%o|BMj!cbZ-6SmYa}57?_v8@STTO zM4)}VHVIVN7w{_4t(R(M5!W=x1Aj#mi%~EU8VprcUTMdNpR9an`D5`P<iA+iQ{%Lh zjkHL@TQ}F^@NX}6^;Y&%mH9JdDzaGS90to4WO<dvn1jm%qAN)c*yP+|g^eKYgWyJc z2B8PakIpxP*F#b+?em>8r~R_OZW!lWl7(Ze%kuOKq_qufir~nyYk$}okWdM3dS20T z^x+>J$CWjiCFOcKInc+;)-$m<;mM9}_x)LQjcA>ok2D!iI)4*cT3B)5TURjG-5bUs z4>1d0MBj@kr@>|6E!(T38q_t#NK1I$cNHfcn25gD-|vaxt3}1b$J%LDFzkDC)5^<@ z;A(_yC_MlV>p_NdLCEd1t;aMy`S5h$UQL*P<%wHJ9gxg%nwd5^4*x)yM*LiLj*x7A zY9>L)%UvOgCz%?(I&GEGIeBoR*X^eOI@5O`mrY?7mFxNDU^n9;=d$M$fJMVufKJ|F z-E$L`Ov?98+HiWh^tj&AlEd(H*D09G)Sc_5YdoW_fu8YOR{uj@J9PZox&FQwsV6Vx z^)n~`HCb1ajvlwXOuX11lMNpJw&AZ0kv`_I003zbhc%nixJ-QJWxvN4OC^M;?@dsZ zT6W`UL{d>0OW7oTQ%h@Im?yDuCI%pA8<~`dF8u7Dd4J?X%U(6L=E4kPl?$bvO?xA^ zv3Oa#%#0Vc{h^<alX;Z~&iiVcq4QMlvuLi3y^rRj9qh-2Iv16+7}{q_cV>GYK%r5z z)oLL5I1j4IOD>Qyg3#<8TgjRJahAOVjsvG2=_8~?Kn&5%=yAbJ!@gyI`0NQ_s|xf~ z(bJl(8=N3ylMiD+X@TCd>wj9f_T}p3;NaPmrZ-J)B%L<*&5vD$xh&#$OS}x*tB?In zW!`#hmazS%y&NZi3XEr-Zgry_ho?88J0ZadUGz^6M;0Ea;auM_%7$#)6<l`Ys>cjD z9=?-+ogR4H6AfdPe3=D&1>Lb_??0Z|{^P#pxH<X)2NX;F>3vV`rtwd;HooqJP;J)} zEt_fs*v0To*DPvu7aX$(U@97K&~VSMpJJ0SWvew#fXCTx;tdyseOPQT8Tv7`m#7X1 zK(LWq`x|wEHtc<RZ>S%$FN2itYEM#}WSSQHHfB?`x$q6?qG8`i3XgO-?HHw$4F?#= zVMLBRuiZAAUh~wT=!Mc3jiG=22a(a)eLznCUAi*-%gEVy_(d(vVtM@yY74!XW~I5Y z1(t$8v}%sXOjFyIO0xrwO=blcKY{)RAOX381Zt|ze9D%<7yEIv{hv&>Ua_-=V;5?; zv}-1<-pA?mb%?&ZzG+_>N9^&NcA#_ZJ~z6_kh*~);fS$9hii%Z;W*Eu<6R^DY0i2; zwf}uc4u`bn%ilECOgisAx59tVD(`GwyQ~${(u!`cX=Md)1anzMLO_G(cl_b9sx#j- zfU}{6@)wPLNKUvR#{dev>^If@TrF8(`b__}TfVwA>N_ISSY(8U{}m+|sddn3!?pgE zYVZFaU2g)`RI>GZ??4Cv0t5sNlLiEg2p9$t5xc`6GO0lUQBV^GMFd4u8mI06VUR%) z5JAumf{3UHsNm4r41!GBI18u;oX0-4+8%p4=lj<V_Icm$-doQD*;7@mTD8`y+B-YH zatX3T&H}ZnM=Bf<DN*Ec@34u6|AwBpJuuvyqWODcB1Pl#a;7_rOXKT2WY(SEZ78zc zFijsnawZRV>TJi6IY*NuczY!SS}#!3O*V9IFma@4J47SS=pN5;)I%VSbo$uvtUR(r zfSi0SpU!&c^@$rM<jYkqH~0z`7f>=tk;bXjsQDqcH`=Ks{e5c<?USPM=$zuo2_G`u zJ!d|%JwN2V=SvjmY^&)-*^b7B6Pzg&i;dZ3{rk0yWsu1zKZk6PP*k!Lf$%K*kYrKB z08y1e;<4GT*_w1;8fJ#<jqzV>N}56ra5qIQT=|f*Ku+?LW&~@NKe*^>{N}WK!<tUD za+~5Muf(SUtlO*h?42#0`Na3FZ_cXo76wzoH<~XG$!?X;RSoy^V~b7im%J2@wBb7o zxs#fP3=TDLF=kWXw(uH1CgS0>(<{#}ZDQ!LWtyjU9TM9+6Orj8nCiawAMKNRXBrDQ zp&{ct;zK%jt(ji_=JH!#CS?DTZ2Rxn8F#)vy?ie^N;KXyu;i2A(^GBMPSvoGL4_iH z>D{WNvTu{tTRKS;pAv(XSozTwBv|lZ__*n}vFm)9@;skTwf(FM7Jl+Cg<@<!x}yqT zxgfEZ|NQcs=`4>4(H0^L^}z>+*LckPWq(F?X#>@Ao>3+G+sF8Vv?GsNMm#on&AJvE zQbJq=KgLq3Qz(D?^9bLDDdU*k*}k}6e|K!c@xg#{cDL#`<OYg{M=J@^%DDAKkpK0` zr6eL5>0h?8<N5#VEOtan-1OMT|Nkr{`#&;JvQ~_yqW@kA+_FfHXNF8_5vhpc$|ycI zRJfGpSZ4edk5BgD{4gPbh#0t<FQ3vNeS(a*Obom<7ocT|LH=-<d~o@cm@ksau!j#7 zCN9T@2&Y9JB3wg0L=2{i(!XVVijOV4wunTw(#Qtr(3F7+Ly%@5B9{qpP-a24_)HN~ zL5Uqj1_C{PF<XH{R56#b5RnZTNYjRUC{4VjKoY@4&lQuWGt^%99!q=}C~zmI4}7t# zM@=A8K`RW%S%}0S57VsCctNXD<ubo#Duyh90_++zKw>XuSf}==0pAR)G^M5~P~am_ zMMxP02SW5#ONzsg=o1pMrU9ikwUtRW1p@pSUWGC+C}qmhRM?v2N+kNDHKG=9zcd`N zW^gqrnP(dj5Xi~nzCn~hj-N<?*ESfkbHS8CAPT}MCH>c%G%d#wa8w*QMCt{QS?)*G zLJc@ogtKF*)v_a|l?zC)m}VlA{G=sFy+jGhs|2dxv>KCogQLiOur-5+-@Bnu@`n@y z)!;UdNL&QwG_)n|vgB~4rrXHOMQ2hqKnw#57_?skWlkVDfXO9gqYiAA${~|Aqn91b zV}aE4N^FfwdnGE!q-+pq*X-LkgWX!7fhjL2jb_Tyhj5f6pr|FDGI~=8S~cj!OO3or z<7nxqZb||GFwI>iuwy!n17{PDRfIr3;!?=Wu*MEfwOR(I4MpUSY7(U&L1lq-j#7Z& ztifNTnahwyFs&TAvYv|nq$PABA_-KjX^jx2v@#{i{zS3j1f{16qV!1y@*xBGE{0sE z#9%9>g(_v|hA6;0l_~-;iY^-#tH8}0_}F`cXvv^>A|m*6gUX&z%Fqh>AK8itY^VBf zkHr02q9B)(PC*NWQ&p8}2~<(GkDS7J<&HQMyU;xPhY*B?41ozukXhRW!m)@2Nn4)) z{7H8WZ74ExTo3Z|v$(}G`J5QkM`e;$#Hf+uunXcTM4F8=tcAiJQ7r(my;NpjCIMBV z5()UXDxw+BG{^Da3^K=BhD~u0ivvtKTa`8{Pn1yGMfA+*1zOn4h;$!qc*0ai8Eqnt zI0s@gW7Lm|9<y$m+Z?!vMa&&nLs7*ZgNa7BLDI&{Au;qJF$+zO2~0DlodTE8DUg!T zR>y<bOxz6>QBXMsb5VjCFup?IqRC!heLk^Ta1n`BqJ9ajE>f2WIbi}+FQ}U;F%bYS zYJeGQL<zwbHsXuUnB$ru6b$mJYD^Jdi&L!E%i`IafL%+dzyNc$lOk~yM@ny?WROw^ zxi!Wc&y2>w_-pe;Gpvbn#uDi{IF}=_y;8Zk7mwW<0~wV`2Jx+F<Zv&*uUu+Vd|_Gi zvnB{n2)Zbxs1IKP6f+F@#I#@|fp{DlNVS8(&UZIQli}BLDM;Vw0%CpE45fHLetSGM zcL!h85d{-X0VQUp{5}D?j467@&7>K_#0YNl7KO{=fV-sRsTv|)FV!o8iF|2-*vH68 zozDpz@mrNNXvu+M7NY*W9uCzH*{Y~gX_=6Y?oA3W5EFsL+RvKGyiF?OWlb7Jn5P+S zJcEWg0;1c_Jt+2pOlRXk%k3ETb7Y!T8GFH9RnY<hYd31=vaI=i1w+;oRE_u?^qE+d zjxS<huQ@$|nZO|TD%zQKq>D-Qfs*b5^Rgbahz2P4{_XBit#w&ks!+qJhwgXup1p~R zs1vS`7y~&|f&INTUPUQ5$|A^k{Kr24&0D!J=yd3V)M72|E*SEpB&4%cm8Kv_?-lXb zs)4nv)N?K>us1*;aV1dEFG88By*ZjH68&2$Fn#&auA=^eFWw+yzz8^qZN+<X{V1iG z0PGA1C1DOrORMt$p(XtVYxZI(j1ev5Q$XoOu;Ft=2@wgtHO5?)W3=zHS!Hes>^@>C zrEV_tBj}jmD0X0bpkr%{`>YSj$6$a%_JZyy6&$mZ);V}|fsxxC3?}I)3|ZL@6btuD zVLJhXXAXI+N6)SMz`VtBgxcFhrM*6m<8Bd^Ln2TsDKAIhCW+dmb%Y^J_}4^F)10J; z6;$s?ulp1PHfWK%3jdKL^<4l@OEdij6L~~O#E?mLu%3lrmL7~S(HM77ZVuukWJ1)Z zx@CSTNh$OrU0g|Pm7wV1IgZdA4k_W)bXQQ|b*rA)FypYpsCjpi(dNf~tS?oJvz9&! zJkunfg18_zch^vD<z|{Y$)}V}S$$AmX&ha5^+|uV@ok<X1-Um3CGuo(xPW+d?<>=8 z;Hd#N?dA6)JXwNp&4OQppskAz?uSbG{iGEXvKHc7TfbFwhhZPBmUN>GUVFh1yVgPa z>^y1_PbxR%B*skMH^(;<-3$-dlqYAvq;5?K*U=S56HjCs5e;V^oAayP*A-<E@qBm7 zCJ`bBLME=y1g-iS2bg9@>(#eZ%HlRYNJ)A|&x+zEi+H5~&JuZwwSlner_0)+Pkg<I zvt-+=^?zEzW$0pPNI6uW39FnUtsfrh#*jmF3XPr_a^>{E41EU^4<r<p31dK^28Wsi z%XV>stGg*;S~Nw&h7tZ<o!&hG#~MKFF=JJh58VUNT3ALAHgbOjN3Mb0c4(hb=fRr6 z2E+@Uj+cuB=>&{S1xIRp0AmddT{=5Cgha-B(3Ei$;9vl(>py{<9H=}8Yj^aW=vV;q zF(R!UvmGCj_JV#>>v6Cd&rEY*oEbHFi#gK5vZ6BN3FM`{!P!>k2xz?fP##@*G~mV+ ztJ&}p-_l%<`h=wUxzXzjON9)?U`TN$gR}2Ma;dN~62JA(@Iu^f<=*0BOq6&gn6gyH zL;+#iOQxZEJ(=%R$>~O0F%oAAX##X>giF!Mw|+boP~L%bRlz8_@S1xMAn4#tL)o4{ z1yka1_Bd-2yug~}bL2f>!$X-OqZp%J6(ju89;Qj&!vcsFdV>sot1hkkX`}EqAFubw zFl}QhIF79aXe8nou7EuS67@nOz$kZ+5u8q#))DBa-?LFC-6?%aL^UxOIoQ5sq#H1t z040m6V8>q=vHT*Eo$%Z{Fhd|Rc!7gnv3dcyu-7{4$X9m86|s06!E1ka`&(D14}MIv zj8L5sPDoaggH&G|@3(3}LQ#KW!cSM0Ie%WNbG>MH$!y*ZrU{Fo%j{8J{CA$S@nBA) z;{zoS1PtFkemAbbNK)}!qqyx%P=f29i2!0RUGL<}x>6xpg`ThQCXJ5hs#yC+*_287 zGeo|Kn6z3*peT)tsc1U7-o3&|pSCU-KR!hX8i8@?w_JLtj+mb`bXN{rE*^CKek1F$ zTquPu$ovU>f5?HcF*9QQ<|u292GLIs1uEQ!UtK0K$005)8ny&qmy<f$XT485OKEHX zZM)BMT9OxC0(v`Xe@u)yP0z*p9uuz-s4zmIH4IER`dib{Ph~xFKO=b=>ZxwtOB{nF z%<SBI`Zq`EI5A{RP0UiE{Al<@$BpDVrT9vCdVe*%@Tc#$dKIdtX>gu1u&e>Fy68@c z>(HWn^D0(Pf6QDJCk6)DvgfV9&C{pJgac7UD9v=*h)Vq+B@QWIzq6c}fC&>CVAARN z?H$)y(r7<;1QuB#C}%iXw+^fYxNUcN)=wXv<j&nH8}cpf!Gi%LLdrf!XxZ4N`O&~} zSFy?}o88C_f#BE^fa2N38H?9j<}KUP+HY9C@fij+(wrhAlsL~HykYt=sF*cs{-MHY zp`*|=bI7&7zmuP5jD{C`uu3bIYLlvnZ7Heqj9R-?^a~v0+LnWWWm>OJ!1R@G1P@ax zAKB`SE)6+7cb^B<jhfTA<4j?N`(hT_37)mkgFw*7t<uk&@_b7Y%o)J#>#Uwcc(%2> zrSA9MrHcH;E}J`?HXib00@3f#!<B%wTuW2l=|+5S)ZTw4!zIvhqXXQu*Lrl+X&k7- zmH<reB$@?A6Yyjj{ftPp$mO?pUeGqd)YFV=+}7GX-&$T|q(b*CZTDn!><OM0AYrw? z>mhV%I5*ZkIGHfGq+F|f`@zZ3z>p`ph7P8f5joLnhhj*R@T$#mtQV3*pzhYK)y+Lw zlfDEjx^IbJt-=wdDdE<*r|h}#r&-Tq_1k!sUc^klaw-#&&IpVf_gzXWriy&rBF@?w zf1$c()@r=4fh;{nmiw7?fJLj5vT?v@hVQ{RZiz?AS<WJ-9!~86b6pYzfVAEIm;1aF zN8gXPeKk1*1PoL!VPN~r1j<+D*v&zoz$<VyUG<P>%2G1s+iwFj+6DkZt{@$>YFOH; z2iJb;fl|d?rUyyjp=Sn8Wvvl2uWBH&UgJoCFfZjaC4QdQ%3Tz$Khb{jXjyt0!UJ*U z4;B3#jKL#I-8Yh^LEt61a>!20vkyFM!Q@eMfRH<8{l|N*b5A5t&-AIIb{apWtIh|` z7shpq@6NO)U~DIVv8(gsS(M>pxjG#&QQ(%d&9lD$on_u0cxj+|;a6o!zd+@5(O|qM zpDFl2MlsmJ$pj@an~=DBQ7Vkq{dV25XHH*(2rQT^O{jQRHASzLneZFm1J<s8Fi!q~ zGixYmhV>TO{sJ)>DO%ccvWijImiqo)xZ`Kr@$MgHjrB92sDpJ;5ncq3>lI$O)nc@V zf9qO-`q8j!J*kv%pZ513{B-o~rwV3Ampw_vbjLTv8j?V^-m}Z*>$ns(SyZk{3Jd@I z&K>M#qUgZ4I4g5}AETSK8kLBQdbVVqzlsM+lgWM&q2LQ6hM#=>`#3e+%v1c%q-zA1 zdyAEIL`C6}lwwUbznAqIC8&45+g>Xn=I5icHsG2t@LG5GDB@aZMJsAB*WI4-)$Q{Y z{gcfEx(Bn#&`w;Ic#jwCln$tfFY+=H=n$t?5sW*G74eDK)Ioyk1<w~<NgE}}Aa;4) ze{4r4V6wuF)e~PFGt=HREB2iT;G@Y94%gBCDbuJ*#x;t_iVuH!ue#<ZAJUhVeLaf? zccbKM{hi&T9st9FQI3Wd{pW?A8dc(_={?`teapw40qVx-E-np1KGnrl)gp!Z`f$cG z#NdF3t!2;6&tc;bMx#B`x82D11D_iR+_Kw*dhHA5upFOf^D3m`*{bfp6sx$NdKfD8 z&F(BnpS07_EL&vVU(r*>=bmjIb-JtV^jqv)c6I@6|1i+IZ%5y8t@DPAc%`qCg|1wf zVWr*OOxtgS@HqOb1zORxE7HtgTu_E5Dg<VXcDqBVcZVw`%ua#mB#rT-t=%i!w}(0t zh%hPvWtjY5J0A39NobFB;+)A$!dr&bc1tfFh<0_Vq@m+rM!Nns8fFg7>U^!|w7SkO z9Ug`*?C8<Gawsp`y{*h!V(;?j(I^Apk;~_5lg>gS_+jY(lToe9hf(v){-4%lU0FM4 zSBM@mcPW~d9=DtQ3ZNF*WktJ;23hCS85^1hTJM&>u-l%P7owNuFw*95Cz&-hvQrdN zkj}bdYI#6nt;cmBcx^&DhOK=qJ-FrC5qmQN1)gu=?fbDJ{cednc*xA&r{5-uls)F) zvHp3~sq9InRd)!~mmmH1&xprC8L72yRBxPlJBq#MvPXw+IoUM&nKxCyApNK$V50_I z2C7mAz<l9cTEC=eFx;O`@uKpZY!80FK}30$bZ*R7CH7%cYuq+&%SZL;ggr&{?(irl zN)FFbJF{y;9wAuEj2yz)RN-yj+L5ibDsfBW%{*Uc8WAijwbVmL7b?F~QnB^1sXGb~ zbrww_Ge9J3r;XQ?TiB5~etvgq*Pd02q@teej&zA5A%H{OySczZ<L*FOIBQ`6CXlVs zrP0@HXRlt=@|<y|e?;OCo7iuzuFIriKE(X`(-|%Z!a@7<3nmJTW;r=kxNo%}O+c_% zH)B>m$H>|oE{KHya0nXs9*gPpOz{A<-O2ak6V*At%sZT#d##~<gQ!c<&Ssc%oM)c4 zK*#&~<kd;v@6@fc@Ekw;^WemncV^6@iv2S5RK(I}{j<`cVc{xc52w|Mj;^JfJ9c07 zIpG>d*rX!%hvRNtb$SF%Zk*1-8Z*Uw;KeZuKAP~=ch_KYHiLm*q1wvf_%DoIS@h+R z96}pc#9!+<awoe}(Z(?Fwt%7plUIIv(lL%yhu++!qraojj|qLq-MfdzK-k3pPvQA0 zLe`}>&q2W^;9+=5|CNZ5x|_#?U9{{>uY_D_wDmObnxJG_8V2VZKjBWcaH|p_1{F#5 zv3`wZ>-noY>EMJoQZa6BY0vZRiq)pI##LM+t1+xP8IPto_0RgriT%L(hC>!{vT>{4 zZ`l?0ns;oGHCVDl@i3n)&z_`C`FFZ%zQ<&hTeTiK1pO~U94S42cIe4M0H%aK9Q*je z+LfPyhdyKz0}DVlguE<8-uA(9lky54y_iJXp3R~qSFWU#s*++McI}}qp1DGaYCmHY zw65aEOY<M-!)tt347a5-U}GdktTwdxa6X3B8Lc~e>saUzxApgcCSJw)>Ia%XJTN}@ zOjngbP)<6H#irx)wLM86b)g}dW}Q!d!3>Rp=UYv}K)_LCZ+Y~!D__oaK31SJ6~uUc zXlvGYq!=QV<>Vs=-)_7-t)6#wGYHmc1X_<0cKIjPZFY|g>8);;;VJ;Mf8v>!?&(Mu z=e_PSHIwyMeFwkp&u;Uida{FtM!x=)r$$vO2G2KUXV6?+%3S<SL^f#>sK~(C)8<P) zFdDsOW{O#pzWw%5<0Ar8@7`Z6c>zQ_9nr}6f<caq92FmG$+88#BSqiUZyl9MY(qPv zUVF}Xbi=Ep^H*bC_!tOg&JBEMEhyyirtwy0sl>NI6siO87H13GB5!fd@348#7bSeS zKJ{M}tLGHvTDhHHvc@#d2<sG_N>iCT`f>NJE6XO!YqM$4I2BjE8_TzN3LCb>f$1E^ zqM_^kWn~)=hF!fs*|NJLeX_Z(aAVE76nU0^4(3k1{T0OBg-?i<skz>_*=@X}l>WBw zQ!Wp!3d&$G8aOrxEJ_kPCAo%X1yh{6!^?hrH(9e%S*z@pw%>yZ!L>HCdv4i%9udLQ zkG!#T`hL53vjsiI`~-IT#%}YTpV}5rmJ52|k$KVtSKWV$ztK*uus5r^!v@IwVwV>< zkzkUeR5wL-orlf|FCTT!;^=1;evTV0D81U3leYVu&~wauYCw_O0r;My?uRo6{!E{D z+$~RU+wv$%h1;H8r<Y%;Ne5CY*kG?0rnAL+biZEW9?C%;kz<!c4>(bbz*KO`vx-TF zHa}Ni%wmYeU;k2fbLj~WoimN86D9)JE5h_V>ay=Qp;q1^K!C|o6bdYt^ZdxEd3K~E zB*T!`4!gkq#SEPLYM0jJ0U)pW^qFAAy6sJSR|R=Zw&B`b4io?`&iyu+SLd~s!=7BX zfXQ#~34Gw3t_u4CNZXw$Jo=B6<C8-<ZH|6=KQ>+2I;#4QCh0yiDZV$8<{g{(xQU(a zaUm_9#gOfMImRU}bYSIzpd0p*U>x*OYtGT1@BG;OwN_{Qlk6Cbj}lG@k1L7Xdi!x> z=>DUc;Q58QCFZNHEzb|(nZx#Q+B}M<I*lpQ49%aRa~zLZ!Kmb=8>)!(*5)Hvb&0iz zJwj=(EDqIae-~zm=<9T&rBJ14GG#dXKex>qxzfQ8T`Yf%`g%8=8JRYD1t6E_g}Z#b zI_HsLM^odsZR+n^Ig4s+^0>BMc6nUx3~r%;S4k!7_Q#<DkJ_itzyDZvr$l=>k>?Nq zy$(zuKSR#$U-eFdaVL@WJ(n^(_?y7z30V{g4_-Ft5Q4Na-KqsL(aZdJ*o;h14`=Z% zs<q(xnZFk6O=eB`>2>`5(DASL9&Fp(X^tg;?M&Vt&_1dv=la-oW}iMrrVdErwz{a} znl>pf!ZSXmQne#Tt9(SRTb>nkxV!Q(OWkbx%Z+JY)o*sYFrN81I3vrMjyMicwc*Jx z+P#c7yk?culs#C^bBHq=$PSro(2jq~04#`H{#aF4X(6PNh^ZG|8BTiZ7XDqEo`s~W zS~OP#95ho-FTOz}0k-=}m?12)O%3+I-|P_S`oa6)_ge|uiX@tI&G;`#o*WBK+>n@$ zNr5c7;+ohC6QJn4bS=$BV3`N%J@-4_ZgM&f2r|5ZNF}Tpl&%ib0<And1jOe-qdS0n znODc3FrF7dgYwbs>h?;BDQc?4Hutk7Oy4fx*v%S+u}jR&h}J=^KFbD#{_>25I6TC$ ziR-+o7Uw+SESVqCDehJ1pS8P#2<%r&UBL^wyFqdrUp68UE##TQ_Z|hEJWDc5$_xxA zXWFh^;3{Mts(&n6enomg^Ch7F8LIh}q2AuGMYeRHo=+-Xm8YuC1f!j-n@}5ctZTC= zBK-s%0rb}u8~N*v6z?BiIh4#*N)LeVNVXv&_;uc^60`G(kt(z_=$P6dtoi^mgEco5 zn|avP?Anm%L3SxB?$w=-r`)P5U0(sHMRS7*j_%#{hqujRXM0WEuN8sm8378zFoG|; zy~<czbN;HQVJ&H#ui4{PFJ7a;<Vd=$wGP4tZq%@LgvY4?0LOE3AS72-%ljpMb(EcQ zI!9NDf1nKOfRl|8Htgh?u2{)%2!nH)a|Y_P?YLtee5G~hTGz3zs063FG%tzw@+i?# zIVEh^dV7OJJ1;J<P=_4^GB-pR106$<hSfG1Hkow!&{tz!-B&ZPSDpW%O)b?}c`<#m z)(I;Sm}x;vL?5)}sKD&<0L6!v?j)Ba2UKndzO8E2$>k=nmiu#P1}^<<$mYhnzkYdp zYWH0`H}&B{mVjFuM#f>nH|H$PJUsc^m+H&A9FNXbC*2{;bRY`|kg!4k&S&=I?{?GC z0Kd9cvH8jvm6&hzxHea2;PRF80;eBVT=9a*R>u7FQEPFWl~5ZjXaiNvh^-=00+P7x z#vuREBA=oB%7Ha5cXB3=CmtQPcU2v@knsx`wJdlk=@rGIA3MK3`M3(ZzMZc^c2mVC zw7NirQ=*}XJyvxQo2FxcInds2cP32aN;qd;a9ZpSZ4!xsIj`#3&J)hRps9&?mzURQ zb2WIaxA(=1*SfxdVrzZB`Sr2!q|}fr;?wajX8wz@{yqg|P%7D8Cuh)TahTt@V@u4k z3=E@wcoh}l;!9dVEO2Yy>&AK#FSxJ}g5sk4p=yQRiEZaq4PfasT0RE6>w*|K1)4Nt z)0Hc)QzX}oF4cEs-VmgcEJ%lpA7^Jd$F}h2myI<J^9Be3nDl178F5m;MnT(7>0Z^? zd@5|(#QglNCnja>)z%ji@H^O}*`Pi*Vu&d4+z>lj`<kCc8i(#AFh=EvaQqUp-J1zc zmhQz36eLyx%=MwLM=~4+dGpn=Z}U_nMw>e4{QzhzppT?WZsn+oImh4HhQ8boOQ@$v zi>{>f?mGXdGCA|)U00^9&v7?j+JZ~H_D;<Df}e#gR@t+$1Ox#nE0c!Fq{p8EUzeC| zhS()b!8_&SR|$Cp8u^7<AJ>pF#$`7=zBMnQX4wX+U8+PB$}=9n9gO;`?yG?E!<EMY zsugbipr7!Rn<w{-NbarIvM6SSI*Uk6K>weZy{VItkqC9PoI2~j+q{pJDtuI@9($R< z0SOP@AcqLXk6!)D@P&D{JpLDeH-b!U$Zj`J6axv4qk9!;b5~EZ@sYm`H9){hT{}A$ z%*Zxg-1So_w|}{J-aL0vsI~8b`d@h#q;3%NAHnI{vyXLUpN-3_%$T=4ok`_Yt{Ws6 zVh1okfao>INnLC9gy!Re(Y|@kL?yqQ$hH68)-$WsL&3c!x~}A%z2m%Ci4L|2OF158 zz^dO2kQ;x=YqyDo4)>EC?Ef^M;2wXt%+U0m_UtEfrz|BuK*Vc(vUbJkg3eo^;Au4+ z_m@71{U+OF_N$yM=P^JrMx;3KfsH}&qyRPEB^IzA-YNUG=QDp#?X-i*b3GaWK|ACl zcexX0cUgvZf%;5Hw-n##iU*+?Q=JVDXmq5r;O6W0c?R6}F$6Aub5z)!hkjrU`<8Sq z?rh)i!yVnTx19dSRGVtx4H|Lm(z=yvnXr9=aAn5a)rz{@p1Rpgcd5%ENh<;K6832} zxU=r!D~*>1oWka2b<64;JXaXv^Y*Guud_8l;lFc8b^pEJo1(HInz<Y3^BcJE7%J>| zZC9f~744RJqhZSOMPQ>nW8Lvx4zj!{xLJ64hIjD1V!?)}c_%&%p8a-ko)B3{0+>AI z*5p^NuTH*Gw<{U@v7*RNI&xz6>5shA#V`k1Oz1H#UCh0vpzk(*{X~iPR)Vha6oYS* z`L<+MCkE#d>E4N|Cx^eEvtnJx%^N=FVydQ|*6%!S;Ko!bp#h+zMsd}6;D?ujBdv&( zET5zras$plBZtA79<vNW0l$(wA?R0L6FNn9uPOMu<&U|ZgTJTEBTQC;Z}Q*mwZx2Z zz5Cn0=4SC}C#5KhDBl$AWxZS`U-9_trFK;nnS!?=Au4&tpo2Hn^=Rl|{>cPa9y6}Q z*Ef4ZLMm5;_U}A#@;%Rz>KZV<DqS-w18sP;S!)?*WrA_=7bY>N?O1?9JATI+cTc5n z%Zwc!VFkZh-Ub8+2gu`l@8;^YlxkW`SPRVFT~5b<pvi~){ZE0)jA6yQQ+?kHqgS_C z$JWl#>2bWDoSLC(2NwI45I75_k2IB)EEM%vvHI-TdKNa1&V!8{=^1Rg%)y@kooO}k ztI@VcUXsWqX4M5Xr(UmgvC`vLQMq%=63nJ93?tJ(BwA!UV(Wxr{^WQ#jb){3vxgsG zDFHIhS-$yP`Plj9N%|G!*4ClJfkYDg@Ib#LDens=oRYb{z4K`{=knuaSGcxL|GL3D zVRH1|?^oy4zVVP)VRnRJA5>hrAse_~BB8SWf!Pzs__F{vW4xp>y9}~S!j(pgtC#9G zlw$e=h`FIU6q(#2{?wnm#N5XgrhW2??x3w2!_j}hHUni*{5bDmzbJMPn88sBC6RfI zhTH0PaGlY&ue$`!^WFqpxfk(**gBFDe|uw|!r%A`adx~`(f}y3>NG+(_9pCVfm?NK z@ZtWtSaHy!dMzJ;Hb~?;Yp**+d||Q^6zzsN6BE9fD;hRhXIl?+I04%eA!tRBYOsF7 zUjs)5?`E2NV9$e`Qo0-VWCqE94*cT#`Nq`cwtB?|Y5rJy00>r$n=lwr(<YZt_b#lb zz%`y6d_xbg>9Lg-C>l@Q!1*=dQ`BDpI&I{~5Q%1O`^?e+Vx{@nbRh)}!zWY@NH2Ej zes1z6Z(b`?#@YHS8d;UgrU^>LHPUm}nf%n+T4~7zTdoS}b0k@<i;fM}k|Nu_T^nxA zrE&RIW*C!{%xN4i$a}md`S`SnHy~|+(hEF)88F-paV4B%F9s{WjBtdIuFix@+yC&2 z-PU?%$qv)Pn6oEZ+Zh=j^<HaY4L+#r?^Q8K$*32m31gtME?c#B$+2BtO7|5IdOA!H zrG3@Bdeb+Cks@Kk@DgnasO*3hUnUYG{k{AGw&QMveEsUmXSia)#4EqH+!K%Y=PO)e zv1$TP!+%?&@4a8DzS7Z9iXsvKyUS)^frH_}TFtTNF}G@SF#?uI4JYp2-1+#9c6cJ^ z90Ct4k3f3aZ7|Y#$5URE%pvQ5;3y&NB0ka123B^E6`tZ@B^&pvyMBNBX5L>`Q=WKC z1tNe({35=SX*f;NrKNwQyg`!Xq%7aPa&%ss?8I#AtDVt%xC6lEf8V2}^IKZF-k!2k z6%XS5Es$46fYIeuz=m1^!9oi}2h7MZY^fX|<%#gbu_TLr`Nm<eJ`M!mScDbg4~j$0 zZ+^wpH44$Gam6p<<KsQ)8z@*3n1eufulN<?9GK@VKYjJ@Go}kpFdg_MMFC|BroO&^ zLzo3Rjps#RdV5WJ)4CLf#-}$_ecQ8>gSTW_c|-cvNp#itxuxqXHAc{t#urO}sPFK) zaGf*u?JpHHeY36YzL$Jrb=h$oyTb*EAtsyrrre{KprBO4*F6>b;T+qFa}VJgOsQp~ zQ3Iiwd{VH?c=I4V@KQ5qWVCI^`9}<N$ut0O5kANVS<>V%S=<A*vwfr2jNqu_u5Z>= zzLOz4ZYr*P*8A?I0Zr;fS8z^TH!TTS7i*$T-AG-g75qr=?h>A**~x^`l0sj)!hx$@ zzXvRc#x`L58P6JQrD>?5b71`bjwZPV?m9M|yY=rIszyfI4Ixptma)AX?umA#-=HDH z-0CYE9=xDbsPSIm?H)0JJ)K%ir4cS{6*E`c5@ohV#s-w~Nkx>Rx+zhxxR!1N=+DZ) zOrJq$0Vh|rJM!d&CI{O9*T!W_+`FIbDbaFUHGfg#P8XAIMoW0MamA2hK|#>vGg|Y5 z)_3kzF%Z$2g_$7%aaW?kmA?-M&9ix(y=_1WPPX!v<*GAbF>B{^XDl(fYBzzMH*K!( zE2^yNuGM3&6NZkwVpg+!5<wOp{_^8AkJ0SAzh7xs{$ivdc-?zZjZl!!;_@q*;YLtb zRM;7Ab7JOl7aFUG=Q9Z~6013_p)7qE%~~mWi;qrAHDX4EO3Y?AtRPP+X!$ve9g^oY zVZnv95x=O%$G|+8ovC-XV#LQ92oq&pY&+%rn{cL&ZoAbo7<Dn061%>$!S6~CY|l)D zI@1zI!V~H~wQC$Z^FqGn1X-5~4tja+KZgvkN*RFKeAAROQ-g^okcA0!6)`t|K51u? zZb7-$muy&6^Hspz`4c_Uy~_{8PF<tfm!Tu^T4wJ&RofptEa<EH;nVR4V~Z+Jn;ZBx z6sMBL@J>Bk#AUHbQ#EwENfmN&;G5xZ3fe8T?+wXKhxBzURO!~_RoY24?R2((V1>u( z`!$3eDz4Wu^Jd+9acf1aN|wh|K%{MhoSU~dc2F5KD;mJpAx~A=BF)2!nD2Y~98J?~ zUAQvNnsWn8%>JSF!ye(WV&fstafs$3fwVQWMjR71VNTSr=Qz<Ai<(&YYt7wZ4x<m2 z+>E_eGF~O-<H=;VVr!*wW5mvECPqw_&sZ^|t9A2^z$QO7V?{EFce1N-YhrQxf=3A{ zYw}2RAT;!?a;!Iza(gmb4{kr<1CyBZm4e266OBAR3kdxB2URP6Q5?#$-TLN-qKiGM zn|Z}Ps;<{^m{V0nX?JQo#+$I^`fpD2$5)$Dsw-RyK=rEM&>jb1ZAXLsRvF5nWVc^c z&A-`X#yZ=*^R1zcP<fDV+%fzVODco~&OZVi8hnc+=3xW>JtRU{KHiWqFMiPZk6(=! z9raKFeSG?CU#c}M;_el%ZIwq(KL8V!&H=j+99F2U2`iZj^+m;oZ*4uS?dvt%u0gQI zVC_znwq@^)p*tRr0b(@9Mcc+F>~D4{D3JRZ2NHZa*MK#=HdvTCRvzIk+n6x@LDP33 zPr)F}vE7e9g4YDm0mBt$jAzA{c*>T{V#{?>_QHIy@>q%4-5;Oq)TE1GYo;$BpL`*M zfF3|>c9|bw;%i_XP{p7Uef#ulwbM_#XgA#xd3tJ$H-WPuu|wX3{iofFx@Viabgi=t zFk9J)K&B>W=~Q83pT$dRf{Cw84r@xa3<IH@&O_67X}CFr#3W+HQxBa!{T-p9w~t@4 z)P9tNwG>=8Ewh>aUZh6(it(c?f(R#1LO|99fY#A+eER%FY!VZI5vEHd4B}#<MUt#; zP5bJ_z2pv|2vpS$u0A0bJ5V0xxy$W&EPNfA!3Zx)lkrVI+brgiU%{fo^0Q{yf&>|M zyd;yp?IVu{e+eRnl{i8MGxlif>)%TWusuyUvdE{xjxZnjY+#8siDWYU2vQhWz<Uw> znWKP1cT1Nx%@VLxn{PX}{JHL}>T(H%#_Rhg9_@-<B9q%pFD+<4eL9sXLNwhkN^6(g z)if+EZhYD~MpyN?Ub_7CKvbB}g8-FZ?pm`a*xxwYe-Gh>Vz_^$r;<&SX%lx_03>bC ztEe5@|Fl`yka0`0Y)Hf}CY*ASG^|9p(~>~r;S(J|q2p<CwT1-?w<}7TG>s<xukQGc zH4IGFhMx|&%n3YwzrETyBzz0s%JkM56*WZID~CT>>jtCJwD#cTuAiHClxniAl%<0* z?SELiS|OB|AK0)@dy&eNunU7yA%oH{ZfI#q)U-x;@EnI%F0<MQU=`jHyWf7gbdfQk z>+&_onIK+CNIb>h2RBN8Q=zLtO-NS7`KOX?0n-%G{ci)SEFZQf;O2sMkMa9Ul%Phg z;`;rk6J~3(JoTDEb*8$7@hxL+!HwSdIcb)*z0dmLn~S$?NKFMFndzy4;TLvEsKUxb zp3EuaO^N<63Ob3RIa#05U@90>0I@pX%~gSz45%ylM264Cq}!9h7nV7Mhu^4nK2ahR z%m;q*u-{s#!c*gqW_1hmRO(Al(Z$u)PQUmlD!hhI?~#8p{a53^iwJK{^tX{-wqFt! zXskVUQlvo$%C!v-0<?0p!%b=y1?tb@gkIz)@R|!PMy#e*{W?8Gfe5^Yn4t{F^7Azw zE`5=Qql<S8?9;Z?+;|c1Uyn6|5bnQ*x#Yb(-?j7h=EImDlf+%>KJjI0&gjt78URd3 zgmwYIqoQB(RSiE+oAY=@iL-brBD6tG41m16o3I-uy5{lk`{roJz_uun6yd~(vuTg| zrV}D%hzeY`ZHv*wMQg2hiU>OSi)RKB&!qc~)GX^Rt#S6C4Umc&I-&L^>0IcdH9+b0 zeOVx2j65wH@E!bpc=jLhYgG3-BGzDr+|u}b<eJGerKA*tSM&ZxrpJwjv4Gkd30$EE zs=&35b#{Fdb|_SA5H*#*TBDC+vKP2Gyb++wH0(!XZog>Ib?;O*xU4_NEgpttjwc?1 zXABDGLnWK!o*x7Mvw0R?xA$*27LGM7Ow~aTMwG!qI-`qfB;>oTu{y18X@NyfJd#cp z0lTkAmSdH@t%DabFpZ+w@?_<pX$sdBcPF1n0c_hcC;e~+L)5OS<e-u=51DJ9jrCQ% zzs2hd-<iLvt>jEvZ2xjJt@5(!N=G?!x}UUtg`>qt%-_pp$Zq|Tl81gRU>rSlC2G3? zt?@BQ1XU~k#FVb-^ZCD)zBz1GEoOuI@9Co&U+9TGs`gtuO5zepw`wO`>NOyJgk>8t zc6+TPu?^Uu`d?(+=9Evr2W)ZU-Ur>D_87qe8n#Mj#JBbr5AV1+DRW<VsfYq!V65|7 zTkBUWYYKy%$S}wgAiJl=IC~eqc3+`>Z_lu!SsLwqvPY+Fr9=pFmeeWN-~Bn@%jy^a z)4o~er8SNj#(7(~Bk)oJ!IqLbVm8MQJsjDoS&$)GWxcZ%m1Y73Y+ufqat>Tjni>lh zZh5|F?fUo9^Jk8{Y_4RI#t};*A(!q${9G2F(r}%k1OlT4cN*w!4YCx*d@;?^XVI|a z*2~Q^XX9rRV|lxch?O9UiGXtWr2SO^*3=+0=t^)}T1M9lU%lSktKHYND<rpAd%-Q~ z>AfABrY($i(!07WYU5DIZfQVz0lk=lNQ4CeN;$0aZBvUQ;cOy@WhF04n`zn8+Nb`p zwtUf40^f`2;T?OzAL}N=U+car{ttU*IpFA8Mymo)WK;E&b2N>bZXR6Q*-q_x=>=lt z%)^Xj#rX--iwkc^)=C|HB?qh<28!;#p&VQH&OEIo7n2xPJ?a4-9TXNmW8Q!H+63MV z#5AedKXkbMQp3?6DvdI$={wd~d9HN1rBz}YXu1R~PbVxt(4PC%z}2zw5sF6G=HorF z_-)gU;MX(;ZZ+$N*VHxCv0}0g)E3C)Kaf^amF<nkemp&S0SV~?qM2I`(KJPcFrIdF zZr#1pe|mo11_CmsGs5dv55_L;t%}P%ShRA#tphqi)*gJaEJu4d$=E)I+!`W9vJXZ5 zJe<5Af*Ew&X_q$S&S&a8EBSH8_l{O%B+|3BwGiK@Cit0OpMUU$5>4+{dTU0Nm3#X- zlj^qUwAl%<;XILVY#M!!gvml833_CD-+E&9c>6ENXIZ!Fo35I-`m97=Gl372NeYOP zvy|-yB079ls&zzf?2Su+MYPdOdD0F`g2^WFF{-)QkYiv{e<>(bHH^MrV`gZyIHnIj z1jY>KvBVkdGpc3&&Gh?UNY0d#PM@=cJ^gpl7$3}IG}wOeve<jQFhRQhacmE1`~1v; zkyYa~3V^hE`|3XUpcKa5FOyYr!_(myh`EG7JN9raKkLNdm%@nu^0?WWSwAmppRncf z-ouBP=?Pd6gp~c{?3yh_x{C*UUzF|uDz9vAU+UFHhAFGhX5Sr`^a7|$mTM;0-`ktM zsAhB#-M~eqiKnKP26jBPIuOV@KgOdL^8gjSeCMHy+kq$Z55~qgT43mPJz5t{G59n) zT)=7exyheUUSQo<n4emp<Utd4;OUcaG*rg}TcRHLp4OaHjr~P1Dn~pQM^?wjq?7Wb z;qB5JN*Xi4bjQaof3@7DEPt>`d*OTka+sWy%89}^Z?DcufAd)=HemG?I`%8Ms$_P9 zUL&&tvb-Ec?Qt+0%6j=U;WK|a&8rrGy3OM1?<dNonAa~~+L5~}Eo6^*N8R4}7UMEJ zLI@66CRYXyQUIM4@+7~Xx@y+%%kt2VxNjN{6f&t51sRXf^h^?tYREzb1UpHRDB83c z_xZ4gnPzG95v)>yJ66P{H!Iq(ybos1I>{&Hb~_3PG#5Q-npmXTO_3enb_UIW^#Ck6 z5N?CC3Z)g|e!DrL)RH2{p~SRy#y?L7t#{g+)K|jNqr|+DzIT?>lepat!!=F7NKZ_& z1d8}xiFweW2`Psr_?oxPw@xax4RD@9RKN%6`0cC4bA4U3;iC>%-H8KAyej6K&D!Mk z5)u<kz8V13kZik-bea{Z-RMo~n=p$5*y<ikrUI^AyqhLY+7CQ*1#UIg6qr;O(Cl55 z$hHbhxemtz9=4q2|LUNJR(dv=nKaQ>A{pNIsxkJTk%g>uy15vWfR0Y^qX+zkQnXZr zBF0j2aPy1CG%GWIp6B8YJklX)#;g3lHn%w|a-_pIs9lS<<@%-=KYS3-AZHM0FHQR; zHc%-y+I9}iI?8s{HgM7T;I7}ke{T%?jABH7;1(Z{d!?l70<esQ7621A+RzM$avfH8 z@MBV~fX6147Sixp8kLMZf>G|nC+S<Y>xMkO4O)0VVRch$m?>1?O-n`-rY+ON?TjxZ zKX%5hmo0rAmTFgfrVo?XaYQ~w_bn%5dDCE$iO?dQT{B4J6!}bklT>v?33{g+K^KXC zLHQk0Jm~>ndA_PO_?;?rHIxdl(<Cqu+_IXNl6$PoLZHjn%<P9dP?%C>$edL66%d@h zU}+N!d_x3bM(<>H$1b|dG%hbn*a-k_HC%wk9s{a7HvIzkJwf@D2}JR<;aB%xz7I%A z^MtI;Z3W=I;Ese+25&HdFTPOrkoUdOfGwqg0ICCj43XFw*Ft`5nQJ<zuQa)_LeU`Y zaZK=z2Xf23ww-A6I{QCHL(&pOb<(I`7L}p8ViOrgyBZ>DbO8fReO&YQn>D(fx!&<t zk7qz;B(%@y;1lA6AV9Nr<`Zp)>J$7nC^|Iz{A^G5slS^=vRFJ$<iQ;!1hP#c6K0v$ zrPGY@NCuBeJ*K-c&52}zmN^|E0Znocj?>D^tNQe{fooonZm@sEkPxZGI2u?j#FUf- z2X7hYK+!+y50={plv-cdNh_aV;0d`H##68$t7YE{KG_bdk1zeX;mEO-<(5k%tl~$C zx<dA{h&#(GRi*k3dVqi8fI;X9J0-i3NY}vA8BP?q(R^FEz7ApFQkA)8%`4l-8SpF9 zm){89l2C-j|LFEc|6KZK^Bir**7<Z;f=)nUPBpFBx9>%CVVjR*wa3Pp|BCom+I*Qs zW^}`zJkswW)2AOV95@s*J!4IDxW90q{CCqo4;xwffS~7brrHD4`PfDO^2Wr+IwfO1 z9eDr>NtBhBrxWlt5E026uUj1TqsMY0APE2<s9C?-+X7@YX#!$%XCh$sc7$lIA-7My z_pRT;TR>a)yAm66bQ=>FZEd!jU4v+)=V%Nrb2MndYq+$TF*7EAN=`*H^G1_qxHK=% z2g`U*v!P$l8mu@lKe<S6_20QTex`U$!?C~FO8b#(n0<%(zxMlTrMm)DuZ@8VoJqfQ z1Ufpw(5~kyhbKSqoaw+#pyTti_{8NEGiPaNi>up2r01xT*IR7@3KwAzF8*A(FUf5T z@C+-TIPJUCEb_#XB;=1=KY>?B>VS>kD95A~jG=YqPxKMA$+UUO4?RRhcsv+a0hX$5 z=3B?@{_7J2>lW0jT<q?MT=)*11`OMSh;>D`qWR`k>2Q92BF{fO6bN>0NMCS$j}qdH z)ff)VO|vc7khpf?;9Bbd{{o`6C_>b`@9<l|Y%5ic*%P&~F@<ea@jsxSV$X9gwb4#x z!u+D+qu)x)uC|yhIreLoo-v$|@Qt*wS<Z)~Vux`4+ta5bGCiPKM-H_3cgl{d(79>J z;IjxCe@(g1anND846<T?i7C@MrP6@4CFlwOhJUM^<TS!7?!orkTg?^nqKA^pJ<S}| zV&Q-aV?3`w+BfsJaTm2a=J%xrXn4^5WP}#LnmgM7B^A6V{WE4;Zy?Z04R(XF<(Ikz zm`acYwB@=i-6X&FTU(Y&G(0S)b$4$Vn9=4us1;Z#XY6<8`QjotxZir=9+24|N^d49 z8K*GK!Aw|rC6Q%pLW+=pp1DkDt=|kEteO6v@kZon0DND4j)h=T0pY2VWSe=Rui{@P zQnJTp)L}gPVP`z3J!`k{=7irULT@urUv4;8sj$}e#1@wqg+38W`EMJDG7*FcniYWp zAX!4*^~xM<?j=BQqgBI&S9``FtaMcp2lr*=z2kL?E@B*r-Xxp;E`58?f#wu*>r}nV z1-`c4X$IQSYK}=2b;tVWUO!<Ru<cmkfHxg-5E=eg2hiYL@^uMSe9OglnNW>ER8Vs? z>8$OWdx^gde{>3)Vmt$U!fxTYy*F?9r^8q=Iy`86ZvUNh^2l}35~g3O>UMLd20e{M zmg?ald<l4QK+|$S+siJv&UpAFHt}|TVZI+<b?v9it-%7Wii|*w3oXG90-fDxRk&7G z&x$8}VUJcI)`}{+Fr`8Jr_(LkZrb16jn;G0DuB-y1X)k(=CWw*DFC~b;#f5yTC;g( zy$QzalDVZyv*>9qHyO6?7!eNA*N}G6@LWrMf7fm;Q>M;S7wws|*@5p>#$nljl`m8y zL_WI~Z$98xm`$!#CM?b~fBMr+bwBSs?JTNHzyBt&;Y%lzKu|q%GhuON%T(h3u+UAP z1>bZ|re7NwGfvt??DPqe8m2UsXhlapZJH0`mvzSfbCEM#rvWx%K0t89xGHzFsrqL0 z-&jD<Q9)$Y*mZWjo!Mm<e=;|q8N*a}yC3+W#Lx+&xZ_?7(H{=*wU!=V{xDPhMI=F{ zlChFpkU+!7A$H}(z>e7or;{E0{7jGBsrQ~%Qph$kyFX_S9SISrdS<U%wnAsp8!g`d zk{n`z2#E6p@JoDVg`hF&>C9hGC!d<Svwf^}bR@et%4L$PiF*@T?|c<2Q|U^VQhfur zZuG74QpBB)nMDIkv*rZ6Y=B8(#fa99LS?H#A0)v+*1Pvu*zZkq0u5Q=TF^)$*LCl( z^z2dTjdji+B6ar6r%NL0P`}c=GP;<)*}~|bdE$J3GuALLd(x>hWjIKXaPQw%ZsTSX z15zf5G;C9l<ssKixnKi}d=9zZZr)=%*j~6!@31i3{>YT8<A2y}G>{^BJivFDS->~c zd88fa-Ti{UzJT-(RVxHx7lje6mTH<l>0F?`ZO^FmbCaKiIXQ1+HnK!IC3mJDD`V&E zeRER>Wz4kHu1W#Q%2sRK*Rm<rS|mJsM)!@iK8gJ#kyQsU1N2C7{ox`y|L=;Hmq-&! zL0KnODRFpkVt(^sVoJFD*v-UqoW-f>KeS;w0Yrat7Gc;5SBgAoQxk1i7JOal>7@ML z*tbc4ggY-jxGBV7XF=ndPc{2vFqRYgevqXKxdN$@;NC46gg4EK9p$eVW^_$l`{VVF zNH2O%57>4S0N~Sq2+}N~tCb1SZwE%gKQn2*q_Py08vGc@ZYJRf76-5UJ*_CQa3+t< ziB>nl56zGogcuJB=}p1W`ybWFc!L3O2f*33OX?%9x6C+Sd~;xA<ma-SjFl(mlxk^t zf^zoXF-9iN^qQL0XXoyHZ{6DoTm5H}?+iiseWG21x!OZPh96?KIY`{;Qw`i&Ti*F? zXK3hQq$mrEKl_(e8D(`{a?Gv?3y6T+$6sIE{^X(SACU|DF%hmlcF3a@MJU}WH)P+{ z3lHvXZ0oZ!HnrXt!@Eot20(;v=WH96<Pc;l(Xb*iW<r2+DIPr3Qs$<|r7xXJS;<>E zT3TL`i-|Xn6;CT5$j&|frlmOu(j>HyvnwUVYqbtfvrX8yMrIEVwACD{YR|d1Kc=S3 zkLDK-oIfyQmtCDDcl`X|xtg9-B<ZKAqxS!}JkCiax(%X>)7qL=1{Y~Kr11=PYWvAB z8MUpm%@{n?Ye5Ud4&D*}`^le8)N&=!p^HpknC2cj)OU7{R1;c8qB$M};|)&@eyY>* zV~mqfOXoey$aTT_t0SUeR^VQ5o%D-Ms^3fqlzp)rs^re5w!~Bh)6+<2)y+?irrvbp zY%}-u>7FXjwbWN31nK~3b8QoQ8L=V~1VGk(dOND)yQi}kuP@{{G@_G8t^zgHK@T4l z(RgAo=#%K6m_6*J`W{6Y)_XdnztzV-!!jxGWP(~x*MPATAh)*8#<lz2C!RfxsS%?S zgXGnogqc?#e5<F+w0vZ!J8RnUmQsQBIx98WK@Fzt8?UqYH=E>?rC&8p*aPPRCNzod z9C9+%PC2z?TY>5t^P7PrZGGF6Miq@l*QLQr0Rz+l3s`ByL{xwOBk$GJ^|3@j!fZrw ze3W4}$8Nv*@o7TAK=gE%vRX6WY^uO&&-*vwPFnm^GrQADSYgt>Rg05KBTAH2H2^Q} zO#GWTcr$HLxceBnzkYg$SKKEdV7Fh8crrybK@$J1bbejTbNjhB`E8Ns6S7EH7?UGx zLCdkIjqCf4Jjumm<9{a4i|-oDbnM(u4^Jgi2D;Ly1g#D=<uny|<ggVBUgE~7DY0Pv zsQPc7evV-1`pRrw@0nPwk?%NHyHVN_BZ>51-{Oq7JLuGu7}uhnoZwI2<SsQ<oSRro z=Gf<KZxVYS6KdC~3+Imf<KHeuMp0tR<ap~)zBw^q!GcXEiia=ltZHoH-Vu@OmlC=( zu@0(at%>%`k5RXO47Dn-)DyQpxO8sm{hwKZrAoJ2Dr_{1VFRx_*MeNloa?snAL9$G z=pAwZDJVay1J6t3g$GOaE#9;+9#ee50((1Cou~QqjS##o{o-}+T>x2=n*ao%naNv! z>wB@W=~y9HY($h8T9ja17vv+^R9HUJZ7-M{B)y~7!@~Ol0*wF8*<>aaNXEL>q__Gv z$Z<>?v)+^GX#;Paote&CZELQh+hDmHYdYQ20-c}ZJlMZh)3-7F&UbMMg7C3t24oSA zthe-gE0|&XtUc25-R3uIPW4!1^&IM@?-a0{iS8$s5hf2AFPlw4d{-JI+T!(_it;P` zmzCR7;TTw0V7P{!cmSpQ?9y`b^yBX&E3Et1(2sVLfX?7+EqJdsG5VWwftpju9%lO? zM9MTSxt(j8xnG1i^@9c9=V%ow-!N*jENU;|wzoZuRiXQzri|iEg0X@{*5tLZ>^S#| z1LZ61$1H&E2{Z~g^X}=RM?SguCtEO(Bd2Ql27~*B(p;?>Cg;q+p(SZ&e^YtDmg{w{ zjO7J_kOGP=8V~ljBjmy2V|BLrV^&8qr8_K@dwLfa{$oK=#^K2Kq2H$677zJ!)|{Kr zDTo_AbX9vcFF4@lKyD<yNFH}7j=}0@W38In982z)$gN3Z&O<6cv?ArK+sx%FNP~Nc z>(sJA|2EQ)X%@jo9z`ZCt;suuXk$T%9^4y!JH1C$Oa+(TPktUd)%LIX2O1Cf@=I&a z#|I{dL>~{juDGQh*rt;BLfpJ_xwi%C6JsHgn|yogeZ$v(I{Kf;gAE7Rqk&5-Q_(o6 zdn9@`T_@SG4V?afpHvziYWL##NWf;N+Xc2sCWU`bV5pLskeS)u<Vwkg`TK6DRYh!B z>T~5u%q*r`@yyM;E*+hGy6JuEp=?3%H^11=jt!=+2d9cvRV*mO(dhNc(G6qK0BtiQ zp4lGxX6?;82lIEd1O^IBoX6%Lcp7M8?R;_nA0OYYTQ?M^s&9=T0~TpdO^$X^h@pw~ zF&izW!D#Tq>Ww3ZXN+$i3$JLXhHhWX{^Johru?B|opkxZw+yERtI91j<V0eUN{-bp z_n*C8$)(18MrUQOZrg+&e0`G9b7DU$tA~!H)ZS?UY%Pv-M)L2kw#BlWT1AH<lfr46 z7Ii*p&f9hL?pP32mMXfXHR;UJA1b~T{G+p`&xLksn`fVzExhy@jw#09ZeEX3AHAq7 zA~^6%;FUf7h}mjs4yo0_FumpJ!mNEZ#T)-|-`q%*3VK<+P9l6#y^h)FcQI8?KToDa z1DRRxSydGmZM+6=j0j1$hV;Kpn44+I!fOXu&Y;a;ncLo(rJh<x-Ye<x6kcB-Nyh0N zSTQugv^E#-;<#Cph(L@OuP{&z6)Q?UCdT1jv^dcQ|H*NA$;4ihyrlPs|KvW5E{5%? z<@SzmS5XB`DW`4Udn`duWAJO`S#LkJ)-PSNh7@FjE*X&kviwdr{z%5T1>Umi==FPz z^6qO|UM4coiM?!V-1>qH@NH?FKRL!f{qYtSOA)twVPusihU=uRdbnhp|EX18`Y6?K z@$il7_nHoSR9E+`dAct-x&Bk=q6XPecn-(U=8^q(Uf)^F-osUuX=2d`?a1I8m2I20 zX{g4IdOTo9(Li=(y;R?5OnHr`?kBrHqbFFV1tm3h^Za^T%(6=d5+#c*+tS(+%F=|W zE`2zOJt}@EiJUl=5g)SJD>su%gC(;r#^1#BvY|2APnw#_fu3&P@7VWa;3N^07EI(f zT8+yUk?#<ic~mX$2MkB(8anY`{c`&1wU=*iZ=5&tn;y0R2Mt-}Hhr2P%#tNRFbC=J zNIuicdIT|0r^0VlCxGw@3)c@1U4*`u5fyZw=6kx`Yx!8TRA~{SxhaD6!kj@E(9y_5 z*jJu^%FsI97Z&;s3jJ$8w3Kh!^<b}}`D5EfnKz^j=B(ITiD`@~x~lSrHo5RD42Tvl zEc@c0c7Kk0keye}_UT-5wt5NkZWz~i!MXs=cKm>SB;dEyhnKxsbQ5=0W0+A|S342Z zGhpFct-xqXWH$$<*G&#lm2)SB|NDencR#j+dGU4k9JU;5^5q0`i0zZ6QVj)ve0myx zKXOVskqi#lR@Z9*ssC#i4W@W|=ZSE0!c?K9UXgCc^y%rTLdwv(CC*rBPU9oj|5$s| z^L4ZPJ<SELe@@dAlY(J~Ctegv=<cDy769U$&Di_y^n;1*xe)S8k~so-OfSt5*$}b$ zpEsURn~3cnExixdhJN0h`?UVHM<fyLzeyGuyZ)^fE0`+jKwOTbPr$5ZW7!arVtk>9 z`IQ;!e^~t$93hkQYLyCBM1DN{r}qSl$yK0gKNR^u<07?f^`HLba@{w05i5Cap+G1$ zxg1u#&eGhcck^25A2GkDpXY19b47FCiGSF`nE`7SS+w8Vc=boas>{k)fN;0R-Ee)e zImabr{4Ck9V@$<^k~IZn?G(3~i+1YXQ~qfzwwtdM4LxGA?e|an?ytEwe~)ErW$Li+ zmK#l;J7ok+$Jc^gSvz7ZcsFn<Xa32ObNK!RHVAGu0{h;X`@3<+2J52N#Gv{z)<2!{ zyG5h$LdeZPC(>@&(|1j?XZ~Q@6vz?j{VPdLeUA~mkzk(5S)2NlKAlf@<~A9bp2f73 zv8dG6rD$A>DrufFH8`I*Z#%Baf@iogBma}VT4v<{Jn3&U+q)?-?6<>n%rs}Qr)kAF zY+G96S4SL+i3#P*LZvm4uY2a4S$Shh;|cep+ZO$rsj)0279)--+V*z-f%KLb|8}}E ztQfJa3ago{C|RSgDmFzibm)9K@zP&0!o`szE|%uT+Q)M&_3#kU7DYJo7fYWOdQQta z@>HASjUu|+7jH{fZ6Ap#19QCT-K~e7nnynQ=&;lG#q7UqppL-0lYw=@p3dAKogSxd zVL{i5Wz&#r=h2S+({s)_ms6M1f=;Dd+<(^Iue0B5r*a0O)CIIDHd22e;j55+_L<xD zb6d*eS!(oIuEEPSTfA;cmME$II2Oixc;3TWWqf7}YR7)=C|1VKIvRfRL2uTi^O)Q) zuq;Bz(!8SFM~tOAF^Y)B2X2{Q!m}h@L!Wv^h0b^6h0N~F7(5sdF|JTZ!3T#-%;3kO zr*C3@f49zT%4<!oRqW`R3kL?Kg<&z(cZpdoD-V6~Hd->=Tp$0`bzu3$93O<jZZuEz zoG{$5(si)jSAS&S=qBx2{X(IB;`AR=gUGut3Y&kudpp;;FkTX5xkshw#*C4drEAS; zN+O~S(XH4a1szTNPcmzJh|j|qJa9i+dZBqnxAohEGM|bE>y9i$mnb6vu4+yC2>d^3 zmTgwcu{GC+E&9gJ*=ny3c`rQrseyrKy;Ru#WU#vtg3?M34w;yCQ?mZQ!an968|)_m zSqTbk;KzTXuD*wHzb1Dl4*tKAjG`mi|NS(d|9?M@qip8irx@(NH)VXT48BNF3^w=g zga2bgMsoQgH-!x-nUY~cnO{r+WzVF<6hlO*;2aZ7Xp&R;LH`$s$N^>2q{~;x$OYuL z6aqdrl^<hLbH^mmWGdxjFcczGM+z0-oEno#g$#U>i~2GNr{7>QV2Vg9C@vG<!imgr z5m#g`N)>r{kV{3lhr%%`hwNz5RBWz_0Bk9_7*jAN<xQ?3l_1fR&SIISO!;;xX}U;7 zq$0p6(Oilz!#3XOkl~+(g5Hp*s0k=*Ri^b+iJAswpa5Q$u&0Z_-=j7%3^`(v6kmz} zc8gTX)I>pno(wgKz5v-<Eh#kvfdZwKj#aN98Yam=0Pr5s6mh{KTq#Ob0f3rLG%&g} zTA#*HqYQGk5*^?%RZs*mJy3)~LFI%%Yjh48bgdAh7z4Uhl6FgMS>w%%35FCkH}#OR zSjs>Rs1XA-fhPEw_Iowp1fn3ti)x&O5WP4DNdV#vM7dG=iada6m1thD0#PI3#Ytpf zg_7&Wp@9hTnSA`inbK;GrgbXXQySr-A!JB=ji}oa{W?agWh)vk0<0AZMH0bP#4HF( zBUi~0z<X7IFD5zZ8AB1!C(tJn&yna%iRMNXAcYmCiez!YG-aA9*vkNKwwOUjFyYu& zaNr^TozMiZcac$os%bto1ZUtIPzX<D7CTgOYC#&Nf=L77?JwjJjxYgQOWMbbw6``C zl4_7nBnd@ilI=j1qE<^UNs<w12)2mxi&@~+5}a~o&H_!;3Z^dEkBJef$^0@wIp(5m z1l~yU#GnW?2fg~l5z;Kywg$Rx%qnO(d%^9Dp_FYZ_LxCz3s_)t<Pe%u9C}6v1S$PP zA?mhbh?FhSmmTc_Us<TJu$@x=Sct<=7z+b4k&8o#wRz|RG*!Z;giO*=rOdI>US{5k zUKeW<e`w{F%KdnxUrE9l^xAD1gCfXX^xUnIIMmfktpeIr705?&5iS;_$59-Z1PmW+ zSfUO9HBlH*+bveGnte1X5Y2#;ge^^o(E=~}a$ExtH@D6Kdoi~(<bK4kh(&ahpL!D` zInzc3M-fSgQ_<AwrAA~1fh1-HTWiq8LJo<F$SROWj0B#D?|c}PX0WQvT!ii<BL07b zy?Izu$<~LvGZ+E{j0hM8?Jx=m7!YZ+)eeIQ8Z;;<lbS$4K~O}row_?f00mSOWDxZP z1;hbF6hv(MFe;O_A}E7;M8(<u)NVbVp1%959qjYnKkjquk(gxHu3EKftyOF9ByUyl zxU41>IDQ1?Ohd;}FPc;)_DKE%dsJ+~V#v7sj3Fl2<K%6$(m@W|Ql5ImBe*ORbvzSL z*p5V++Dhw5#+16#bZX2vsT|!z8kV|u=8sDqvNmFZz761~v=iKD*da6<4K^sOf<Yvs z?Ia(D3@Zaq2A888Vy&pf)3$E4rg#7<@9`G^u}#;e6%KJk6mJDcs_+~1WF}p%r>v#= zi=Yv4sM4P!BO``d`$$WOQh-?&u|qTR^%yM@0IkW8McQ!fKA69Vp`6N)(X@1~w@EYu zb4}UGi>Uss1{sq3U0fE#B3yD(SY&`fQ9?1E6LDyfir5{wu3`=~L*;*Af?*|K=5oA> z7KhG6Eg~;4q^<oKctR$dhQ<N}&-iR&z#g9t<fyb6$`r7E6<j_6?a3hm;s*+5py>%{ zlgMJ5BHmaOKLd&vTsYNKId@5Fm>NVOV*BU^Eac8;%q=B*I$KhmZ~(YzdTNd6mL%90 zNb#^1V}pf|u8W!^z!_^sVPSHBp;0WsD^{3-Dc6)c1l37X;=r$7!CI=VDkY}@XdG11 z+0$R7=p!S;zamV$9n0>xDJv+gkJB$Ch7Xm|IBDY06DcN<Ph*y3JO}||fh{F3k_emN zY+VL2X5wI9XV1w5oVID^sc2hrPOZkkLHJJbuQZ0k0s!nU01+K_ngGspUY{=lF&9mT zngp4(0735E)y3t3pPiu%<&lyhvc@n`fSC<4V}2+GAGw}t0#X>v%dzHL_#BO7YIkOn zx9ivmU{W*wX8WQ6QD-jNBn(V82Er6+vlw;aE+v#HBP~g77Y*{k*G@H+x&tnk?<vDb zV2O0+c#zt2XHfZpdn_bkj6`!Jn$}XDDB2<@s%5NV4^6!VgWkW$pF_V%Q>qDM-GDHd zDN!HHyi?*TaqVZC02~{g%g7LkwBvBGEQUAIxM%|WmhRDJVGJh)ltiD76gXO}vXGcW zB-lE#=xP)hBl=a=x)PM8Mgq|av$`HKSkhXN;;Et!j-3)G5n${XlDELXB!a_$g@M_q zN@*h2qb<^YepPYG^M-`r*Cj0=C;vTe(mXj&>W<0F3f5(T{!5_QJ@SXOQ{@fu-0||K zB1}LeKgKmBP8_3ACgDv3Fl(mWL<<G_DZ$PIYx;kt1j57op=1aOC&2(%fYKM9Y|hov zpD0sa;u)AsjG@0s4rbxUCucv-_(y+g^KOEBCd_AWJ)iVg0}oE@lFK6I0znu03Gmf( z$x>fz_JBe-*G5*tv{p3j?Yv`gj7OzsQ88u&4U?kum+C4C0?o8xeuS`{I|N*7G@}D3 zc32EB(SKO;JhcuK=kMpSfE~pd^!RX$1YqKgpn&HG%*^Pa@`Q^r;v`t{$fgh8acR7o z*R>YKWO`&tgSk9{!0y>x@+@u!;)l3MRqV=L$5KavN8ge+14|t#Qg>Bm>sZ@(2@rK= ze*Yc@Rw`j}DX7#0CylTMSnryo!MFWWfbK>iK<U&l;TUC^q$p6dYaaOM>@MLpJ2Pjq z11C&dM^Z$kfLj9#EUy-5dxN^#<Ee+&q#FHTS7JRr6U!Ev4W{=^7lRBuD~7NUdpe7! zf`9M2B-PZ~)z4S&fC;lTnk5&KT*@x(^mSEccSb8V>(kJI6){{ocY*5Jwjw~K>0)Gc zQm@*5BH*pjSW*Fe)?l`2;xy4wQBz`Enj%B#2%Mip_OyG-`?^1K-pWKNwU<oy9W|fd zbiA~LlVWNO<Q;<QOZU7U#Q}>oPqW9VQd;?f8~lt`Heqt-iOg*=Z7<FCx#a<}%OrhI z#7+tHyb;PKyN*Z2nGo*8O)Plk?~A8ovDJ>=z}2LvLq2!Zns1O#4+Me!^N&}eZp zI&oKoXjGf0H4|+%S@)R7cu0ueW2yz0UKckdq9b_C1<mxxJ%FxXV=Gac9tLGKZqBTq z%#Y;U7mof=zsYy%**8y`Q}9jE+z#-;#R(S2GuBJ$it{odH<1<W<DTf;9=<?7&%fxm z_)RU|u224mYytVWiT$wFm5G5sK#T|E*}4EsL|jS_8+m~LQ>0{1M36tus_<kq=C$@w zm-Qb{e(4Eynm&nYN)%LAbQa5z5U?xvwD#nQei>n`nWEiVtPPi2^E5IST-i;_v&*z1 zxgrofJ12D~A#_CM_C!QJ>0x16uk9p+IdMX9Yo2HmhMVuH9P%hGmb3&to>jTOr;-dE z>qlI1m*mHKi)Y(t%@ftn$lNyXnRx(xpGam<u^w<;z)!`Yp-cdtc`Hi((>V7hJ6!eH zr9})|1H;Owv+A}6G*~#Jb@j(3e?9*?#I1EHFF#u8CR90C5*<;tqFKk6TZ_D9pL)dD z;RIbnC;H=O;jD(C=T{SBI^;~zira^0?2``f%un;jbstBOao8j&`f=V=K4~FZ9Mgfm zRGE2eun^>(jepVua`5};uRk>}@TxSJUz?E!?xEBr>8XVnCSuzOF!^!Q*~N#qH4r#F ziT<5EMph#!gyX6KF{c1bid;e++3z~hHorM~#?<k0pmim--fDMZh!UCKmGqr^(r1jf z$8HfZ&Y)5+v4peH7Ckn2w8fKqY)g<6Eclum5@OLJ)yNaATLpP`ehHgwwOZJ=3(Wd+ zqd`hXL0GuNgAoAe8x752wOsr72_zD?`-S+<`-6|$s{jxa=X%l;!NDL<p4Q%Sl7QrG zclwP2@T`WRIfu1`O@!c^Gh{u-8n+YC4hpP0Ax}f}CQy80?5-H&GwFtB;3;FekhTd1 zQ`Rk8q<q%r{zvoFLq5A`>M|uV$)E^Ax`$6_?1c4=#$FCY?3r5GKRk6te-X{K7n?+U z%>9M3n3G9hxIsCGw>`z_c9FJI*CYy$%;{4qjxrL=WBP<9Gl``WJwwwmpWfzwD|kBe zG_LjJzl3sI@L(~$q!2{%`3Ffws3>uTLTE-b?jJu^t$BL*S*L$4!>fosf-Pf_Bxi2> zgz!XJ%*f1Ka+Iv+i0)n{zw{sd&*5iWSxc1jzN5$!g2;&SK*M&Owx}|}W7`c0ZO5cL zi#dmXk<{_FJ$?J|_(VH_->(J7t!blIyJPbKT8CKCuy+o3Jn+KU-Gjh<DQrs6I+6+9 zl<``;DH_pTjEkLN8thFkSAf409xy>i=MrAGB%>#>NR&czr_lgiOz0?`2`Ak8w00rk zOQVQgxIaM^G@ZGQogqEfc%-;z6ZGSQ1py_$8JuEGkrX{U{A||L2^nwS7XGdl2?c4* zmTH<*Opepk>i<%|0bv~iYn>hv5e;$m>By6l8{o)5VQZxAdib_yq<K{T=q_l+Kc;&4 zxLF>+u1yL7lukvzjsEG6gDcOy^wYQFaRIs{Olvid4!3q`t=_ayf|k~))w_y!URM`H z=Rb^0e0eb^Y09^3m7@Q>M1O2t0Zu6vH1HcN{gL8U$zl!HnvR^L5k!?PVAhMf9}<<= zuI<h=SqkRq$lH9IVj`=Ij8S%g7@T<U$-3XyeE0qzr<7Ee=qG_upo-qcvg={@lphD0 z2e3Q94<YY+rm`b}1TvpOUt&o)nVCvgj}IT)GP5&n>0X7K_t!pZosYgdWkJmm7q{u( zsRXhTj`yqw<D#b$uJz0Wo`6acLEVfeV?&5e+{z_?un9bnEgRN=PG5A%bW_ZYIhlc9 zd4rv*0pOY*cksf=T^%Pcc1{Ynb5w@3rv#d&XnA{FczcudM#a^hI=<HeACK^Shk^-G zH<!2g3L$$oMO@u^b*3THVR7i%1HwZJm&C1n*zPZHJJX0kWR^}o+GwSe&gV`5Af1FY z66H|{o7x#uGd4@~do*#mtbXUs+}5E3tus33Y#o~6?`?G4AvEr+-mO2HjY|2IBU=0K zo#l<A?|5}J4Dr8ve^Li2gsOPwm0$vcC7fYm%T^_MzXgm>UC*-FBpgc0_a0_%?@1Y7 zeKU&@4BH^i{N%i|)7(SZA)9juC|AX|1P)qywSVj0m+s>&F=hh3?PIM7nvV@9X8jPN zkx)V8CW`JL6*50;L4uZXIQkz8egia_SdKrNke@q5svejW1{85|4Y3cU4D5B<I$$F` zn|G{jbxjH>AOhp{nJqC)K!;f%s6PdwmK*)#ZBz84O=Tw5d|j>RT@e?LpV%8^;oC28 z$Z6U)rBcw4T$HB6Vp78SA%8Smo#HId@oJM;Vo<eR+C6~q11F9qBt_~szfmLmV{WL- zXZ_*Vi5dX20{BicgauiGaUP#;d7GX~ZYu{Qx0jpGbZ-rg^0A1toj?iFIOB7{KK?ah zTOt)aLHx_}1zK!@6{lO^5^{A{GjK1J8szuMFP}fu-c>vUGfSb%Ia&d~`}}Ga#2EY~ z<Xvg1B~bwZQgd<nIb-S^$-H$gsp+OhSd8OzO^{;%UfLphHfI7jv9l%s`rCtc2s74) zeoV29S&SCcIfqS(&JL%staMoAUl0GhYu(&P5K`6A2beR}+$tC8Os3cSq-OReH6bE% z2!l3_z{t^e*VDuQ8F2w$Z7KMTBnC_3N`CsuL)he6c{OAjhZe70q)k?0U;UpVDxPg> z6VGSU(qIFqC4aS@p5k4o0TzRLV#hh-v3wk5otAdmS1;*d(*$581+8x0dN#%`AW;*0 z$jrY!>z9ewxao<a-(-9EO1|&Ki7!&nF$$R%aP`4hCa>&DHvJktr_xdg6!uK%CYAig zVR6wc5ME7ypa1?&6n(SO!EW+`N#k=E45ebG@5(SM1<!$}3^7`eW5f!JQpc$*t!b_^ zHtsX~>$xE7R9x>vF<fEBRDR5jox-lT{3UZ{dhN>X*-2DGdL_2$3b^tbny|jDW5S8= zyiYssOS%wt^dIjAA|8hAv!g7!!S2jO<s1u+?nEo!gJ*n$0^hCS1rfG1aoii*9LN)@ z=xt*4zaFJHSOR)20s~zE9RIWNkz&fI=kQNlhDFSc8D6;a2GuT^iJ{kNLL@!IKhawp z%$vqmA1K~=qj`>%%CB=yzZ!|FsIzAqnRNvD8_%>;h|aKE#<NWwo|zBSIx+8893C0I zyzlV=3TVEp%3(+M6Z|u}+?%B{y_7DMHENxO=O^^mM$RVSUl`ryLjekxspHuY`W3HS zDdHPot|uOy^$fqzAf6}j!u7(YdB6O$@!Pf*>EtjgVGa<&O@bhgG9YxB$ew1+i9kg0 z;*hwap|}$`^$COkb&mB<%if&b+p%q4scz=1+fS7(`?nbND*1c#A_z%Y%xx_&yZh=L zUqv_7<m%sEnWghIbmsLtUhIORqo$c`q2kuj?-OxDkS6wKdlD9IM$eKtiNwFX#swc= ztl(XG?Ww%<x_QA|UwX+$2=(kwejUd%PF1wYTtfF8TeI1M$>g`RlzOjIVO9)FFMkTW zX2H$x_hM7+rMmPF#)HbL_g-@ebFaSp$>MY>6$qCB<k&*>nW{~Zn^Zv9&%r%#Qh;{; z>ts|8KNnE?@e3#P6i;MG1oszTSidcy<GEN=v1O~ItTk${$DF6TS|_rGe%zvzBA0<} zYZD=r+T*8wz3~j<vZhoD=dE#hw5C+O{@#E%R!qNX6m;a5wFAjHqAkHAQqKw5@`UCm zGxCI1jpM%lWevgK121gU^W-NF>A@QdO;5Qj-;?XI$x29@APJ$fmW)Hl#4<rI?!>O0 ztyb4ZYh`y5o;4K|!~N;|<k>q8>icB@?BKxL1#L|b2dsP-@<rw;UoMs7neLsnvESv5 zLm2}yFU{Sv&t<QJJv03?!q%u~=T)5)#S=RBiGyns`g6)q!}^{TM#nv7Fvwe2cmQ?A zpk+7uN>;7>y)UbDA=XrvPt$g^Rng#Xd}!f3WgV~mCOr@0m$YyQibonBMg8F0><Uu1 zMn`x&X~n6^CWvKnfjzSlfkHW}XD3bcjs~2bQqF3%?vy+oaQgaxb28b2+Ik12xSRM4 zCCV(`v^a;M9HKXN*i`hN93!$uky2Kb)WTyFwLafsyNz2%R_w})?1!Ces>nbUdZy+w zT$y3*5RDY?tFfFS_xX-=NY1VeIymuHcjV$vWlybgb}jJepE5EQZ!mxaq8J7FFRy3k zjftA>n#^P7MfLafpF6T=^W;DQ>|V#hwaY(7AG~}akp?#Q51_N*SN`8knHQB#iHXQX z)3<y&w|9J7@V<?q2t0sokFlkprr<ALU5mOR5>s#^8ZIo(T0h$%M-TXEzsU%@aq5?q zo;=eDeb@gnZ3@i}$LWq-0FQ$I0fLig&C^RSU8?a6HX#L~-<W+e?dxA1SDk%_o-BO& zhJhdZHpk13Z(zuf1HP<de>(W_E<h?BK&n-VB7>Q&Uw`=2Q2n@4m;O8ioF3B<eo)QJ zN`wcaGp2VvYU1E_7C9j#0_6ZzRugG&`JSv~M&1AT4+%q90Tb;P<+hH;$8iDov-bTa zFz`JCiEh;%U-hZ<;*8ooUnx$mxxqd?<yK9|%z4WvpUa81tcbZeXXYt>%2jnbV3`*Z zxh~Foj$6;?DqVVOXY{owDYfs-`*n|ySk;8e_ekx%h<Xw6UT({|+YpzVX1vta>8rHr zt!=c@$T90h8`(oH`o@eP!|arwf9>UNy4hkO>?=xq2)y9UUEyCQ%EhSGxzxPU;}K>~ z-Zpe2@-yX|;FpO__4QS~I6pgx<t2Vxxnc08duuP(ExPfghc)Q|sL#479|SAPi{nUB zf+%yK>;01739eZ%0^PIkuA38f$2$IJfsu~&R0z!1JOA<3?CXYDCa*SVCQ0c+h6Wh1 z@pmt-y>qZ)L$MqCqaudm`_kuS-<_$C)S;;;wzD>>YU3FVwOM%F^3BV~n+efB!(lS( zw69v8vHI>cIg<p{U@KXC+tM7t+3h*qsZc*RZHtlaiNVdWyjVDBL!_9VH++Xkq+#hh zY<)Qpb8ZZn=y!GNOXrmv)sTsVhyy?sZxWEKfy_S3G;p0MFlg6u$4(w=smZb3!m<0< zw<kL7bx7z1vDzX1^ca=SMC$o!@A0cv8ha$v;V7fJ>g_qF5s*+dBE)6kf-2Zmli+a^ z!=f##d>2Nb%Dw*R9~;)}+k8t282K3gBR7Yz_N0Nq6DE{joz*jgP@B;N5Z;GwR9@SD zD7b2ZAdKD)LTGBXy=q@(T=|-}VafcUl0YN9L~x-48dU-**J}A>%IkWmA?W!;JA{V3 z2S%BD6?mose1t2?2y-dDSNH4Iw(h+l#+YOp^U8&zfIv^Q&6(A=a1CiklN^Z0o!)y6 zrl__JfA{@ME9;W>SDWYf&@*v@+#HC>DUFg5N*-|Qb1yX+zYbft=G3%#kL~~x)ke6o z3*zISpPqLtr*yeQQuj!SQ>4vVH1bc#!V5oN^LLy3&wkQCaZ$^h9)ksCk^TC&Y2W1p zvrJ;9n|b@VfV#^>_H~8^(c(lD@wiD#K5pMRmy;ec912XNf`EI+D8EYn@-wr2F)XM7 z1)%25o@6Xzr{i^m&$vZvtT3fYoq`*2jyv0kP{hK<uO(*@1Df!EdOYB=w^2xl;*;3m z(+4i#in-I)-!EHKu%{8D5~NjsLK>^iuPSUm^W$r-Mc8o8DNEti=zSpuK0)ps^2+&Z zLO{E;fc}QhA2-(1EPEDbDqnfj5W-QDfCe4Y{^kOrExwW<Z)=>}x^&>si$#yQXEv*H z<d<C=!&!o-pyY0<>~*Pe^Bo(VL&!POL{v@`k4>1o9h$a;>3jCQ84N1qXVOE-DK$Pq zV^oQiT8-tvP>nQj(V7K%tFpL8Zgj{Y7Ok~T9*H_`G4~DLdOUa_cQogdse#aKNSnjH z*(u|3m7%5!EI2Af&WYERpE;fgD(2JI<{<vAn`})&=(?_;X|{LbfNG><glf*dLnZ~N zQgm!_=H01%$t#{-{nYra;uXNPtxZ{)h>SS1QOuRMYwD>j@AqGO^-eq(3Y4}5a3rG0 zD&*<j1Oj~ZOkDfMGq1P|u0`|*qkT~;)66qIgRId7=<Y8qG2G+JgD0bsC}ZP8rR=Il zq8K2+<!4N-NJFRwQ<`73{m_*=v!}fJY#>%sJ{aAd-BD_+&#mD#KC+@I!=9Io`j5(; zc4W{%bMLVyI3I-ezHtaCz~#p6+`i?^+21^k9hTOw5^>lB|Bg6IaKW1iJsDETA4kp6 z*B&E0SC)RY<KOdV$X_T)r9PLv9zx9{H8T<xaC~Kz$KK7*=6?(L-j5rY%~`;0!m_QV zyqj=$Hq*)ML-@b7e^dw)N-;bv|Gsl*p^49!#u~3adu_z65(IPj``!@2xxXRGq*+=` zV~=>X()5}d8%Y>B?tQFdp-PXMY!NjuyRDZI#5*&5J|uf@{FRq3YP;u8^+Me$Wo=<; zhAfc$FdM4Zyw(4l`_-u@+><nfR~0!n(}o)-ztUhBqk~Pu|9$S;%zZ1q%C+a6xhbAJ z>2>tf8gV(#Al<X7DCBgoW_J>@qebBKSaQDD&KK5C`E>h!+y6xnzD3&Kx~0L519)Ft zyZ0N%AAg+Uy^F?f!eQ$6O2t4VKk`<z1+!vr4!>UWv3s$?nqPU)hlxnH{8FgV$@8xk z7S}}j<lOyu{?qo!nOuO~G|+JM{VZ&O@b1oJ;?TtXHt#T|!PY}FOHMKAR9qT3jrL9P z{DZX{f7qKz8xM)xM(M1(v%Pi|O#X2CuU)B()3%E-m;AjNW;N05^U2kqT({(}JnQ$F z->cNAf4#jOn_2K)70kU8{;}Z=|DsN0QLDpT{gnqjLbLUy++|y?MDpA+>LMdS33kh9 ze3W_L$-$gpJ8=aGTH)B*q117na*ZtJ4h>t)0ZGHMoqcV)3N9AWa7T+@>P5$L;pSyI zyIgQzNHj9_&WEkIG$cWYU%Td0*cT1-dPO-5G+xt<665Wl#QvzchzC(yhvvik$vTv^ zj=TYj1I9Bo$3_1Sm+EPcKJqr0U-)Q|ptER}pIBbA{+yjv2)2!waCbYOx_0xF(~dqc zafPa7TdLsmN@-5zX1|%y4R;<Vf3yFVxT|_n&5VXD{f#rWU)k#|mNku$bHTg5Gv=5| zo$BrMkVwzDIqxc0Z><aD-Q6y^{6IEs{h2cj=V)qtldF^J4G8SwC=z8!T~frZdylVT zW1S%&+v|@)-YLP4Yp<K9#(M4Y2)-4ZtfVW_l{sX={@}5SF|upj5!WiCeU*a1S9blL z?Z2-3Gb$pf?@i9~TMXjK7Uml<8WE7K6Qb9=d$kU~_W(EZc#6{`Gx|s2l+q+tXKIAg zru*$ozNgM2lMeaX`O6M0-z(BF@Fwhc+A@fiHe6n?@>g8=Vp%5qS1x+i=om5De8K$? z^NX*~zuLaj@r}<S6F<3Hv^JgNDrgDTM-Gas`H}jzN9&3?+T?}MHN#?#P>{WD@)yHN z=n_9n&bTuMHnfboqkAr~Yq@>=H+^7VX~d@=37vA{?V-24yZA5cSKi%YT4T!dyLvmc zzw%ls<bhOof742MdHCCNv3!dZb``H#=sArwOR}w<f4$E5+xmEWKNC7WX+}ZB(O3z& z$tgW|>X9tMg6j0xyS1qG)W^Zf?_Ye~9+nd4dwOk)EObtM3Xr)p&UnV<L41dFVQHsO z)vYhLUts96{)!!ktIZ1=HmN$sQn7u{e0cn>vFv0W!(@5&4=JWRA*Hiyl?#`J#UOlR zWLWvNn|1TV_7SgyDN<fz_~X<i_kQzQ_H%9d?lOW_^s@_`#_ClY&K48UI&2}AusPLR z*S@$_z_Lp}t!EA9<HdnNaQxi>0wvCYJz_kT&ryTpT{ZsU&EBY$Ur_cDoB4j`kE6dB zanOPaqQxva2$0H^mEd(hzV-8R!zqCtHPzR=!)E!B_mQZqz+J<QRa?cPb02~${2emt zv*u0%NLtKY5b?^BNr3bzGo!=k7)ef`XWwxz;l275#4MN(2RyLRJW8hV*{g~9*j0ca zc~PW+E9TzOawEKKpI|H#r5=yq*cuBXl0|u}e;2=UJ8vcW@k)#N(D<uX@ZlmRO;!9n zUqNqs)A#icbtH@%5l7v*Vl)jq1w2w;HX<n~X8+=S@73?L9Bm$#W$DveA&zA=h0kv> zy1QLPx_YUe@#prhWRtYD4dF$ksM*!q&n)2Q$T4VKI6Mw{N2%;D|JdSjEO9LG(B2mE zMboZ3Bjp>#l$XcVb$@!&$XM#?&9JRv{NyR>+;;(5Cp@PW9k}3{!t0gQMhosOJzgGQ z6+pTWa=o{PKkd4%`CSw)<4&*Q>e`Cs+*jKrVL79zf7yJ|@;9TF5MymS1YHG-8!qf_ zi+t*?ck-9ignaqZ`ef;$0UO>*?9pn`ymYUfX>z}(mseUfc5uLziGXJA=EzsR3!MF^ zaULhuX7afo>7Pph@ALTL5Wo#78<RtOQxx{Zw2GLH(L$|zwauPkUZ!;iD#~F~bg3a2 zWG=UNW5lGx%y>ew#c$Yw`RyrnqW8ne9;wf6c&j9r%GZWH?o8WhShlqvhT+({-E6_P z>EnmG#3b@4+izBrT6C$ry?)R4`BP7wbdslfmAc$>zHN;<*<i}1YAOWok?RmnTdTp8 zbCGT9=3YIv=6%2Z&82p3&rhX^*WL_XV5rv^&%Q-=fWR+WN<FTw_;bQpdf=J{tRHXf z(`Dkun#0Re*M3v(-C8w%EjN4&G-~;{0R(+i6whDz;T!=>do?_&n_>}CQF8p%H>DB# zPWpM>Z}(_;qbJ9YNyYNDi!|(AeAL(|eCs{Ft+6g)R{Bx{ZAvNR4GiV$fP`w-bed;v zEoeEtS0woL)E5^HrufLEVb+c>3;*=25Iv9c(c|!eS9}zm#=J6ndlj-lwdhQ?EkH77 z-E$$z)%ei3H<8zRYj3LEK*LQWTIZ)mcCA`%Xi%}4L~mf~qBj0{2)D!upb6w(?$w*i z=Lj|9mA1Xw{)37*bSkK+0iK$7f#!N#IVmNp@hw>~RbV3@iCITt>9i?*4T1lBJ)W<1 z>3#WJiEz=EiQVP13kuTFG0?W$Txn`KucIajVUqz)c7CUS<+qn7>sy1?T0jG37ar&3 z)!(F`M5Qur{nme9NgR5}4*zmNRg+stTHx70=nW#^mlFhpDO<NpT3H+Qr_B;;F9M`( zRmYE%ebg~RSC@yx(?`iKXXuiB@K~8U+rn<L^x-7hU&V^(F#Ykvx&cD9=t8>dnG5M0 zhkThm3$qTu-q5+$%U3er#!O{~XpD>v9&3r8QY}J{NKO*8CmQB2txVspx_bPt<=GA6 z$Pxj}FQytd#(>v;dgk(-YwA6fHU<d8YZrI#y*hMV-;)WFZ?I%oHCi^)R1CRfE@#sB zd9JAQUe{U!%qo5aUX?B``#DQziV(xMo87v)a2fO1^~IQT^Qq;xC@)`HN%V*)&>K>{ zOH%PG{Z~5Uk&nO1(qan%(!Nrb!XyM-fR~ky{Fiq&&oy9Us|=lEPdjZ~@;P<SDLC5S z;OwQ>Hn!6iYyIf;zO(OK4!-y6c9Nib6tUgLhy4|r=a8qb{QNbw^RB*)5m+Y(iyom^ z86C3W{7<XyMuiN~&PYx}5rgag^0cfswY645uXbFKH3qGX>svHwUO}{uj?sdh{a;)N z)nOp4D04Uw?x`E^>W<cKZqIe8UOhr56<`-`eV%oD@ji0p<g;hO=BV^^t+0&E8i^fS zH@3GHJ*d6*;h!xNcLk2=iBn$c61v>&&U*Jl)AalnS~4gh=8pV=9@~C6<_!In^WZW& zmCalje<}F(K+<{5kCXvS9T@V_$Gl=9DNl>2VVg3I2=s6il4XNJvG#{vqs8B>2*Hw- zae73wb{+YtG|0C#gq3~Qh%nWuW6{?>oP9ZK$W%{AS%WprA!&)Hyy;E_m2UN8*Vk*O zv35TyqfR0S=Ey@^*v-H=0&zzfPtz?WSGX1tTaia8T_SY9NUL`rHx6v?xV;5%9K_u% zGug%KunJJ($bk=DbZ8_!?!9KEan`<*m#3`0bfW&2+HEap<2Xjx@L+la7*$(l$XWGj z0(?hV=|MX!MJUx|!E|iZC{&p>RC{+t4s8uM7d3URJpS7Gg!cs4y{c-i-mp`SD3(N! z3q&5c2~@@;Na)lmo;9hj&Q;r%i{8d9BYh)4rr+JphOv>7+esb|y!+HwQs6`ejOw7Q ziafbG`#w4RZ>g>xK}Ayn-SDq?m!qpAhDH>cNu#)jGDd@6*IckSDk<A-V<0SLlS~fT zAz0HG4hn$Mi0S0nG3oCcb*4InO3+Hco`VT)Yo-s6+?1cZ-*x+m!%$*)3tJp~p{f(O z3A@E%$LUA{IodU_dYsSiFWQ^5>@shBA{_}-2Auc=9i}7rvJ+1Us;3<eSvhI4kc#Zy z`)W0~&-m%^nWWO&E%kFH;bytE(b@~{C77f-wm#gRuEPsjTjT4!j>Ho?{cbOohkioT zzUIQw*r71v^LN$~AEcHFYDf-73g6_mq3xzS>vShCTD`KQvNJ!P7Jxo>%=9)P=~0x= z6*pmJ^!Y~T-z4BZ>C|lA1i-62^!lw{=5dhlj>`PG=b6?v`zaHfv9N`pq|JgEp|=p; zKeqd?`|b75OlHvmtjP4dc=_80CA{7@x@YdiAEbUl^ifk(kiIu|-P*;lIb~pKdCBo; zBQx;TN&mQ3X$dNr*O#?;WGN>pwJtlLIHu|rMb<l%V_~x|m%U>ZYI<}0VMsniVnTLo zXp3TTH=(bGRJ*b3qVC098?JNR@8@rwm4}#yv$IDUpBE)8DiYJ};9*ysxnB8B)z^tD zN;F+NF8@%FDiU*hAAj1i&nt~#J{7ocHsYs~W>)~=%SQ-fwUWC=<2!1%uKZpy+VXU$ zo(HxcQ3X3!b}pA>A@rEJMp~<0xt+df)bLgcxmXP$!z(#Rwlscm?vZlE<UqHFV^>`+ zv`8jouZzbMoLV>ETC?3r&O|#{fW&?8Jl?wGR|PO^^nbXMhKUpg&3PMkqIlICk)u=g zU|6zUkB(nlF1E>gR5x$R3OYydYG1H&<IqYeS@!`EUiU4v?32S6z4ckm^Es9oP9;38 z0nLg-I<_l~M-mWLR8zNGV<tBFdf_EZL)-WS%S_<iT(;DmaI+_zxuzngZiluDGG_jP zOZ5rIqw3vE^DDxpiM7pTZvu{HfRGNF5$4Lv_yD(aoUMafQ=~onZzBO`so-s(Tl(tJ z-OldPh22hiZ8dMa>{A}AXPV}7=qav2oYJ$9Ph;JtH9{VIChuFY&2!i6DJu|?Waq=U z<i?RW{yg~0M=MF}nNw3|GL<BCAq7a#LOzE`oLaW`n)kotmrQqrJb03VPtYm_1?jeF z43YsrwPmd}S5z!JvUUTdDaVTIrERt4Qs6=%K#esAEy_Pdk5AV42WXCWd|lR&pya5l zC-fX?H8u?+&}`S&n>{aG2=fSg?&(Y>UMhI4(+qw9X`ybnIfAYb%{R3TmCTbAy7Reu zHNRx6w^%Duwqnd;swQM$NKV!?YqzGQ9A@d5Xv7@yrS2ps@D0cRKte0YLms?XU3gmo zO9nFfmP-PVurglv0b4rCEqjxEeADRsrNn6PE<BmYtXWkNxU}<Tg@>Es%juaT?+x^Y zR90&(o%~ROfsegM%&JyyyKu~9oBbGToc16K_+nF>JggVYzPEwZZyWx*^a7;3^8yg_ zVqV~vcj`ozB;>;@W=`QN?Y38Ze_vmV{!S@`rb~X1yFQ6;gnLXzg77y+r?xpbsouTZ zc*;oO+?%*wz*RP($wrOz>bLfC3=B*)nG*NdrI&T#ht$cl!orFqoDl3hgj*hlcNf0a zop*~~6NvgUq-&MsJa+2UCvTGQ4SBk-)3poT_hVJ^$Ib$|^7;!<yeu|;@o?Be!@jT- z=GY~-y5e=iU%}tzT)rTZmNM$s>sQT8%M~LK0Yush{)C2!eKGMS0oMa_E$5=yTuLT^ z_DRGt)-Bvp<m?3Mzg+VT+UytGy92sG!BwUt&`@B*6Jzl0?pWQ-moo+K+m%>e#2c3u z{7Mzl=1Am4R0M3<PTmrn5ac|rMJB?+&OFXQ#!2Ot`BW!#Cp+*vvi$M~!>}=ftjeSE zIiiR)ITI21-LBQYSsm2%-f~x}Hzg>!>9n~uRkrov>5}7B>GTq$6iON{c*6&50)#a8 zSxBJG`|g(Pq|9W~CeGr85ui8CeFiZtIz<_MD1I8rJ@_i^!YyLc0vn!?Xk=+dE~@vc z!DhCDr6JFiy#8RBX+N+WszTu#+C~g%pPKcbq*=3Lh-Kf=ySF9wgx2K&+zI@<XyE5~ zDeg1db28#rz9~5bQ;BGd8mU!{Et-LQVqr7c^3Yza@G=6c?isAVGnBLy7-MVj2Jd)f zbS~F#y@Q^G$8$6+d_;QGSLiQlmDg6~MApZ#ap^+hM4~+z4QAlP&quSI^t_IF<vF>% ziSr(836h`ua}kLqp9}aQBkNzs{>OGn5QVI9pvx|%>fEe^bs*ZO4Na5Es6eHY27}FS z9O!%SM0*=eudZ8>&u|ln(FzG<0sPM<FLQZqoRy&4ONI8_sZU*-RA{3(e9&ob(`Pa~ zOz8L})W><Ix7WvqIm=;aC_XbQGFpSG=}bq{B7XR+(sF*oXA3KT8+<!jIKnc73I(W3 zOl?#{N*?Q$2Dmd35xWoQj{{HK>&yjySK``mB_U0t6pS=pwLkr8_Flm!hw){e>ozK} ze#hKhCnq-@xi1zB)f*PXmaTNo<)n2Qn~v=+01RzIKGq5T!mSUNRwxa|?;I5WJ*{>p zR~_ymfg|5={LX{k;@w(5cBNS7(};Is7*iTf2PDwgcsd=5O(kMTmtIM<&lKXBxUYZT zs9WP5brYLO^1gyr1<l}2qm7N!{j5-8DbvvdAND%s<4SK`+^(U~+9x|GfM3;-cevI( z{B(F&LyE?JEG^~cm03uIDW>O0%JdRwfG?d~^5dVbJ97d4io7EX@wc{i>$I8Uv|)tO zPpi+;BmRqkPPSzrT@(BYF-D}>I^Q20pM2iXAU+y-zouZnh~xK?>k4a{*-WyWAcXZW zY6Rg0$x0%#7N4GlhghTX?M_}{rY}{8xc9vDkpHvZ;-G8C#+v0j1(Jcg<CZclh`*;B zq@7_8I9C7ffdz*XMnw@wfW=<exMr+7g!YvQafPB33Z(8jrj7NJIyUF1HXuOAHT z*>Z*YYJEt(C=kKSb^n-zgrW>-G_Ncli|Sa0#8EL@U_|%gDuj6c1#e}Gsyl9PeQ-R^ zPx*W*u7NQiPy9GG-TP7*+$~AqNG{(#2T0=b%df3nhnz)P<h1CxcjE<^h#`1$<U$Ah z<Fe2*PPxEM%Rr3A@`IAvQX0`Br}sg+TI2LW;o4lD;}IS<mYsp;JZhjHPQdP^t+Mc9 zKdNJ6>-+ihqznMF_gs(FG^`QN@^MWWiw)`PFQzN2zjTCN_|HXG8o%-TXU7*E^KE=k zP1&M|jn}`Nd@W=8^b;Lexl%iOaf?>%5sDr=)?%L)Yq5br=ziC%(Ba;^dq8~aq}7*C zy|nq6B1PEkHn`lj3@4Pih3c4dhH+HvJ2o33$dUDhAS~OM174p${`MOib1~(oY0-=2 z_(n8%@XI>-QkU(zry2<d6oNde-e$5mwPn|R=e3S?i?$zF^p#`_iB8&w(pJ|m$qX3R z_Hd~_<@!3QG(R68=vL_)BRe;SKriu}g*EMdlpO8?tFD?1OD4sqE^&a&Vs`9sFD4;z zot8oSg#<c@q>nGOGdnSwY<JN$J@x66?$Km?L)gG=>T2f`X^4p^u&ICwQIpNwgw?%c z!58aZW|Dtq6(TLY7N!@zPXQSpFLFRhCW*0QL_y|-j+6Pq_C2?Pr#GcOy)brZOYvu{ zMU_;D5Swu@LB6S0lh4BI@-w7ix2%X3$Q{(_f32lmpMHt!lYO_}drnU<K95VGUARY$ zIkJ{x;}PVQt@Y_?omebM|6-}BS8Ut~|1-rB$i^<W$S?n}@yYrU-kO2#^kXiA1)`Kz zoLuIHU0;Y13v|D!3w<5Eh%)w5T1(>2ic7V9T;jtQx(ygtXog4nm$@9SnlBH}<*3Un z@`JalyxujPrH4!IqSllzy9JBAP`4X9dMqmTf@^K@7`UT<qBcD?G$!gPkR?{ufVsnf z{npm5j30u}l18Hj>Ma6Ot0vo$<?jg~>lO2Czgf5P^aQbL5IdIP-Z)6{0i`$DlS=R@ z&Z&!rvb1_9`7tl8;emS}k6q2^2Fu@h0s}2!*O>dSS@+{D14%bca$HUxBOA$ZwKcnD zz^9%UeRt`wzAfrHY*AKCUOZ}0kuY<?Fz&<=QAm;Hv=%I$uSE#@?Jea;Di)P=kcODK zxoX3_6gFyHty#GzVAvSRdviNkR!dnC@u~I+iw=-9CAW;RaN2BTPYt~<0cjBXv!sU4 z^3f;Hg|7N*qB61B!1@FdsYrB)(Ms3r{&MTpgVAzq&QLye>-q5txq(7q>ing<W{o54 z_Qdnrv7lb7`G;(#k#1llH^WXoeGYoIL1PU30;G9kTiky{gA=v=iyro3mkPL6dj*od zY@P)zDUm?aX@$LB!$AP#E7zr)1}p}h8&_zA9*->TVLJfqdpyDm@CD`11wi`d04>Sw zHz0#T8Lbo)Y7s!vB-9X9B$(MI9)44ki2H}otWF-H`N_R{|N6^duJ(NP{F)lUn$JnN zl3=e>@VMfVe6ZKY_IBd7MOqrw(^E6Y{4ht;DWT3+xDjqXK=4i1N#ax!63VYzwJm&Z zLG?<W7n5Od=;4i$p#sg+5nTLoeOSrGmjW=c<@G~Jt@Y*pWWMM^hLDX0+ilC5q2+Do zuvdn>b~y6=oyE)cg9xu;k8O}Z)NnQ~Qzp{8crlreNy3gpKMeRB^H?V~&bU0(S5NDO z{ZMrOL9Zv<Z>{vMj@#@a9)X_oD@397BmS#2ODei;D$);k2Z-~nY}l=H+J?A7x7~=d zNY$8RSBLAq4-=-pdC|Gb(KzO_f=KV!IzSmYRPUA|lsAUy)?gpZMAP*fUQkTX1IflH zRAo_p^sa`QKfJ!Egu&h9UcSH4-}!UD!qN#_E;r@+Xoej%R6jyn5kJ%;zIE(oUQqYm zl{&pjW;Qk-{-R>EN>3|K8)55Y(M-Q`g$riBB_1-8iMU#m5X)q>{jI@8vvR?J))J9S zGyFICR?MDADp)xbyM0tI`*4@pY?GN&{~46lLDDUJIdp3O0b3Dy22A@8$=9CuJ{JvK zC)^o=wN*|k=^)3D=v+v+&F5TRAu9#>0G~F@nZJWt{e<=YVej6I9UHREIj22BaXn;o zo>Q8ib78dP577?|K0J`~$69ELY;Zd9;*PDWRGF}0i)jz(849I)21gcl5wx-Y!E&Ls zs5ZCKFwb9>TCyiH$v)FN))ss#TDq<0c9Y9oF@N#x?(o@4K>+5HN4HY$f0_5ilk(ZV zg*E{)5L6&Z3akRlT7jkqdT{yPb`(EouKS-K3tOiKQYQ5Iq`}cHW?+I1HgPdrZd`V- z5aucZCv(vu!x+8Px)-u9H9DZ7^hRWxh+bK2vfy>hL=&<x01g^zU0$VL^yy)>lPB}^ zL9;pKxc$wWoVVI}d>Sr-$<70|B3GQKrNk6k1R$}|4Uma_C*F(KNw)>so<k|zTAZi< znvaOH%=~qn55CTzfM7`X&EFogx86D$FzUWDchXmOj^V#Y`!g^$T6hP2xVMZ{L{S|; zw7EqP7Ra%?-^#-t6v&z68&Y^(pWvayy~~UQGkvLMUJH|$#qx`QiOGOADO&uoYHrEp zI##c2aI^wl@h8pTv*_O<Lk-D235!y4o6r!p6~K?ANdw7?|9OAzHw_UQ3&bHJYD>v? z>PcVa5_h!g8R*`VVQqvRF#zPz6zn~-_sS2t%j$gLE;c-AR;QSwgQUve=eev<KCrg& z0&Dk8_LrmqZA^^`c<p27V)YpjjuZ3eF8}Vl);gAn-3?=I{h_a}?EGry+U?tJeH_=L z#408BGCA{FwLC_t({-<&X<9H9KL=*Na*j8oe-Mk08XOzf3Vn6-lVW3@y)JBDD<j54 zaU%-8`M1%p9(^WHdsL1Rg1wRol7kQIX4o~IGMkmXCBU(#(V<hE!>RYHt)6Y(6Oe7S zNUlwshqjR>L!jh|kwF0u@91k?9;81<k-0=52w^k4vfCpc3l>KL%8OtP)zD?v_Gr(r z{)|y~i43<18LQ$!c~vdtxKdJC;s5-Q7vXh`yJK6s&G1_52iUa3_B1&;#eQ+UO+a5e zb~v~&K3ccAD}BR1d0#jlS(`pzbX#Xp6V={XU#87dI`V>`*$M!$-CACsnxxRx#+C<# z=QoY^wl572VUmbp5|9MXfn}cPKH!U+iHDkCr1U5tjVIzP**b`p75HB>eVImR^0?5U z@NJNODIosa&+X39bj2Zqd|fx)*elg5@7}4X<cm+9B<%Rr<-?-QSvhFsROIdcvnfGh zCP(4c9FQSW?-*+w?U4{un4~kVRF!rm=H^<E<wz77NNL0736pa<pDm!^w$09v2a8X9 z`TMT=S7K%JnbW<^3e-Ss;$x&+qHb^TM|@lrd%N~leD!a2S?ZLPefWjp`WWE7NZ9<W zcrqOclL9os68%f9M^g)vP7S>H*uD0`xNYBj8Q+q_Ft`zv>t?)P5M5K7(`J`;Fq-y7 zGJL6ZGh;)$g&{s8fL<cWTi623ETdd<@_F*sZDxx#Z{b}M(yGk87-Tpai=ZoG#M+|; zM=M$pq#@JQ#EV~c*bq<|jgM~Ycuq}+_V3SFD_0HH`&@g1dp<nuu8>N*mGaT^A%n?z z#HA2T+V%a?5_a#!h8%eU%4APXVYXz+`xq?}xasEp3mL;bV(zo=w(mY_Fay6Yz31d# zFY+w)C!G+IAITUah<}0c9@-mQOUG;FLXW1e9E}!Do9=}5@U!;t^O?$T8vd}^N!$&l z;h(qb7W*RE=OEy-ib_?i2VKOr94p>z`6S%1MTjn>mufxZ+;dNc^yj@dSZvW$by$DP zv=iQ&e-i8F1s%rLN@b5^;Tb+GOgxWlCBX|TA~WPzK}V08BIiYi$ZN8XNdE242eG%4 zFlLhgY!wl#Oj!LS(eM4ZdHaumVn#*-$$)#5VEc_pC6$j9!+Z3GZLYfkCO|qO&Cu<1 zBIuGLChKfghUZE!x9LvlcQMRuA9lz?*5<};$E?b*s3-VOgqn}M9(^lM_`*|ps8{qt z2*TnexExy92mlv?Ew`oh*Z1z`^7=PVBeTn6=!Hv}^`f>ct=V&xu-tQ%!jfoQ<tkBR z2fR4=rBk6rR(bb^5msPZi{_x~?2hcOd@tJ2%q&`#u?O7Cxh?llli8Z%gq_)31IG>A z-(kbGsicDgL;2{*sX|2x$mso--rhOd(q3W}E>C0n$FDc-X}6BVuMS?nZ=b@6wGTW! z=bW*vNT{2KJtLrmEX*T@h7~?}u=ZLP=j5PRqZ-`gH(osKrt;rF`wyX#V-@l8*V;x0 z4~<;XrI)c6#)Y!6#)x<;>t9ggaFmW6SaE@mzJA2}Zavd&@{sZ3JEmCLg7%b;rVES< zx<zD}rf9DLg!b;+4VS-n{GaP_uiZWzJLJ<+id_r5pkAQMQqEXgEtA)CW3C4$3YS}| zW&}*Mmf;BQ`!9CZJz~3KKQTHK4C9hy#?AHriZ@2wZ$VtnN;dpGDaD@d2^Efod918p z>Bx57|89S4eDxpEF4>4uisq9MwNV$RuWfU8NKqV%^<uX4TDxB;Ow=r)bkmeg-Lem1 zw+`rcq>T<STbEwHm0)5UHzJ&#+bf*znl%VMU(1tIe8$WYwmvqaAz2Gm>a(x&U(QQT zaJ07V=V@PTILBfyy|<oG%SPg|a#FO6ZkVu~A81U2R#yPLSj?ZIzxu&3h5#V)S4*!w z3C>gKVwyrd8rJREwLB!udC=ujLMxpBDj)*sK43TJ!yy<?LQxalELoGbOa8a^$P~*R z`*U&@UV8EV8~O1Vdq)QC_LR2d#798gPI?T~%PRn;V*dR8`ccanwGXL(J!d=n_>P$Y z5{MdE@DZQOmR97vR7>pfMdycjK}@9ZMc+g2?{Q1omLi-Wh+N|36~XT^v?UvB#v~Nx zKX>`Fdo)(4_tn%5+aDjR)-jNciAd5D=fW3K5Z-rR5Iu_5WEh%*2=CZ4<b~U0DTwe_ z;IfER&aI``0PX4CjTaL<lJAYYH=EUQ&)2$*+Ra%x3AvEiSpU84#NeitKMp#&TIt%h zCmdSukRrkeF_8dSe_2c#1s<LZL27<~DD(MsS53^6$r~dowBd*k6kaX#`7G(-<dylf z;V9K+U)}qwz+B2eEQp)ov0t~7Z@Y3*yT_|WyJe=yE8S86#4myJ9S+<6VrxKKG)X`U zFJBr-GSQ!ZB=4V2w)-b=^x76H+7K^#HwRXTUYvU9Hdvzg96M<NSOPdq=OiNLSea0l zxw`9o)aaJY@eTKmY4gMz*C)&{F@VeFmgoHdt*AXN#cM1<Z1<uJ=xt3Lw6j0*>-_UB z!x;Lx#Kg0^aed69LFq51e0AlIJtYgatT&98z`qRiK6b@C)!(zrk~3en;A-M!9qXRd zlxl4QIW2)QEBV0LhBIM4d4f>vx!`ss=vhaV+P=8N&xefJgKPefR_0+`Htyb!9RVPc z`09<$f1WOBw(V5eFK%@1qT?=U&C`GCxBKb12o81cB(e(PN$tOV3M_7^S4|A<we~gE ze_L_m7Oq!a5VFI!@E#0hj(iomG~S}cNUMQ4ZFQf$Kx4neS2`!noD}BKWLD-z{)lt~ z2x`c-s`u&@LLPuyaG^2mE{TMfY!F#UuxVA3#sbO@1LsV8soi1(|1x6!b0_&v1mB*1 zHy1-`wu>R>63JBuK*p}PNhAGPwQlM|--b`okIBlrT<5u};)_1ph0eB*E{&Ue;hRgP z_cO-73|{p%{7X9j*=>8s*2nGqg<NoRusuMEJhS}%1KEn!#7lZw<Ive>Um}VC_`mYe zlUlvJU8Hj#=;FPR`S5oW^LX|%pEvr)ACWoo&2qujbu6!GINDopOT&1HqaXQ|=B85F zFSc~<?S%Fw=we%=4myRd%^xioE_|V_gYW^~zQ*1h@4A1rWpkCE$pIj7L+ZY<8M6GM zclz7BH(nbrI)xnz6I<`X3<pIWzw&*cg#}CjD@<*Gh2mbJu0$K${zbEn^qBcoLe3O~ zUV6s`T*4&{W~2?a{yJ)tEQxpG>F^#!X2jZUh!z+M+5!$)t*Db37pQzE78)P8NqzI5 z_QR><;y{@**Y<yVC;MC_YNje{dgFBxW|h-<2t1`RVcD?>{~l##63ciW?0C@K;!W+K z#VnpPrWclOxA^Bf8F5Yn{h}?GYMxaT{wq~WO*ce82#H4|F?V!qS&=vK9BaZk+1N4m zeAin}&aaG{t<N9f5oZf3Ivrl*v%8gO-|tKJ`+o)BYlxX(t?>bMWYS=5RMK#UKaZ+Z zrR@la(B6U^M48nYt$m{N$4lQk{<h)EHCkUr@-7amO~Q)#OM(OV_6EE4{!U8J13Mt8 zcTxxc=}TkVK+C0A@Vjoa1B^{Os33`EEK+SPe0q6;*dJOReL0YLQLnx^)?tHi0*g|w zkH7Hm=?*+g#l2y(-;~R3ElGTq%9BD{UPvE26fYgn{{3RMtc|4HnzHD2g|2N{q!!DS z5~c-i*|<Ld7AT#-Q=H()Pfv5v&0$F8HK!(DdystmjBtMl;Kj$JS@oyHZK#I4pyB$# z9!q45^4jN-t&0BWVnm!u(O_Kmsf06sEIrCO4V`FMps3ybVhdK1U6=o4p70NPAf#6c zO1$=kH8ulbIgAKbKNNGw1trpg$p86q&F*w-j)N_BCTJaXpR6<a2~8@t(d$!`I<6^9 zpwl#@pdDuOueE$Mo^WyJv?Xc9S)D64)F4;PY7YP1a8-|(toMMZW5*25LIn{_j^vG< zjbp0R@tGS|*V<oKW<4yuzqmPCKu)SGil|54D@;4_VtBr*R5*25sS>yfO1Avs+rx~a z0_`T6<vuDts(ZmzF}px}EYK*+(YEbL3^>ETOojbU81nTA(_F2I_2L@l)ANCg({IBx zP-GS#-|I>;GG?AV6sREYeAXkL0v>H!o0hXsp7f$tQyUiw%Qv0)=KIb{!Td=D`%`o_ zB}@}ouLx7AE`PHx<`mP)*7UR;$r&-vFKRpGZ<p`Pa<<;>I+&6}_eOez_kU<<js95l zLvpC?=QW%AA^Ea7u239L3`ZYosziR)Y*>)k_Gi6$Mz#Rv4rDrZ@DWJ0r+%{}e)o+_ z>%#Hv)s~~@zYjG(Oap;^N_*nPbn=A{?JZ3z2fSD&s13@lKmCY&A*(sMguX%#(LcNV zTG#4kPt}%)zTYh~6R(xOan(dk++Ry-yg#{QefU<trSYW}jzG>Q;hI1S4*dQ!zf%tt z8(i^wy~D2qIG%t4yQ{K0x5mWUGctW^3iWtchPn$5j7#fwpFMR|*g|A;W2Lk_^ZoKE zQyO>ZF`a%se1EiediO1t&9U~{tX(=&f8lV()?ZRvY|@+do$l9<eoT<%(pL!5yg38< z9PAcR82!0gQ|dtX29b$ki_zguJpteT08fWjyBdP&=__c%EjYh!*y|su)7^zEwPmq- zz$<Uy_Q>%31D|cAAfwQ^yA8x_>|?Uv@|Vp#JBqST4XkqBv?88^k2fi!=C&;&A*)sv z`IR8oe({IR>1FSq)SDbWIeFKvabt!?4{ttyXK}=v1A}FCi_a|N#GG%w?$D`{Ix-eI z-n1X8W@%6SJjqBf!p{30TWn%PpNFp`Y;82xcL1CBhlmRA6zmU@($><6*q}L~MzHGV zjOdd2?sm|+2nglGSHujJ3%9PFeq!Xhz5*Xbha1iQCT>II=Su);QERsb+3U4v{HU&Z zhj_v_zt7jVoMFUSm$2XIfPao;p7mwhI9L3rA7+t9uk0FO@JJS#z<nofkEodh&OIvf zH(FL$mvla}`ETR3&n)a75fb?jEJ}AS+jnvYEOB>=<<I^9cC5)&r{{f}!ZP{q#QV%W z>YSNI)JYd<#>Zp->iyyghocbNo`3yx`KrFn{+7Jl7TIl^-68<h6(sO{u1$FAw%}k( zCmepQi=dCdpja)#adpeXdN-#5VFJdXsZ53o4l&T^i#(3h566DeDR9(1#QDI~n3mdL z@yBuc3Uy@Sa0P){fAcKkOWZOe=Zb9(zy9iHL~gP`kT(vxiO-G0y&V!HM}Hnj{{7{p z<JU`Mwu3%*tsx`jkec@`gQYP=2gxcxx9N6dvD+{4T<HjdQ|;_`&iW(CMKIItobJq@ zjHRnCx&{g_hz63+ZH$|kb84k1(VEeftcd^5{2W9vQYuw>-v;hGnXuA=&Jo5`F($Fc z;3N++RP4<_#zCJj_Hb-f^3Q#jytyad>*)uzKdeWTAV*5e7Yr1dnUgIMhWjtQ7%ez3 ze_FU-iRM0~*lErHY4E?zIr#o-ITpq0t+|^scI#NghrCOb=os<64ZC`DeCTWtl>PG9 z!8oVsp~<Cl&aGX_432Na{zi;(Li8u5JAVIJF4}l@GeY#I4?j2G`C`i9dl5dfG`ICg zm8M6BsxDBCYdBXvpYZ?t|No&miz(q)bs_!azpwv4TH&UCKH>jeK`H*fudNZ6$BYRP zlwwnC`YbyoDhVkZp&!N`$$#__)MQXhu9$oZFb+^@KHVgE(1t=vDyA5;<@3=JDi91b z=+cJxd>@UD<BC)0%2J^PUP6ar)MAilc%Mn0h&?T_2&Ga)P<+i%EW~@b>_b<SC(>jt zo1vua*f2KyL3;8&Dd}V+=vc_c&EvmI7NxZ0dMTx3l)ES$E+yqs6QtuTr1+UNqf{Z* zae!(2DN}Xu$3`qf@e`-8E9qyIlp$$L$;9ny38luz^-RhzWCCStXjdd=0PkGH)-a)g zJ_Lt3h)0OeG$vZdP)FqNIf1mIql3@>85j`0W<j?~sSeSSQ)o>srP>`Bwi2&W0*@wt zpgoU$f@qs^ObVO`7Hb2XhgZ861~Rhf;pPc-08VYP2JeFW+ceXp&pHp-qKE__01X68 zpkM9ap6aC%SE`A0rapsMrl!fLMbhOQ5eU$Py^BW)lRWb#WL7jaQE5Tm!dE^RO>E_e zYY~AE<3xa9yHFj{sCjlQnq5ua^>?76o66$7aENZ6450|k(O*f6v%;Hsq#HB{S@HQE zKK>T5Wn5A_pW&@GrSiaB90o#-;6HgO{unA+w;*ywlYx<X0WFdi>q=r6O;3O%txTX# z$9$mJv1F(Eea946;vb{Q-7sVUh9EY{0~ZPX<_GFw=#U<$=y(H;QX4~(Vc25@{m?qX z2;vVQ0Cs`wETI)I=JfQ_m5NleC*esn#u8156qpQuAR*{O;6c-zUt0#W0_1cG1M;H- z6pT*<<>Pe_EABW`HBxIaXGIi~1q>q*l#Gz)D$ppCA`+7#Qh<w#1Gt@}^oP!gHh364 zK#L5i9;J4tYmt-aKMUxziO-=ck}-l}O8Nx{lyQpT3Yg|AQ9mM;fSDi2k#hJMM5_{T zW;c_%vZWOjP^&esjzN>CiL|&M)PzF-Zca5}D!7<BF`&$t3aAjh5NtC3k-5YW@KmCH z9VcRQgQiW3GUx+DFAi8<Do=8RCoduiI*g#ndXB#d6$F7hjWBKqOu)HKxxAD(8UP(F zWGOG160$ETMQr@G3Pw<C5sfcB9I!BfUYc^dg-t3~N?<_d9%f+SU6-jqentjQ3=2hx z(bJAXzv@Eg;E!qpVGSO3KiIYmD!)@1*8$!1Q*Z%2oS~UOpzlbC8Y_804wM8$L(NMG zQ#|>U=b)I9byd1IiKzzQREh8tWi8@3?DE5fFKKEvS&PA@rp*j36X>jKDE>q5u58;| z#ux<b4gW+d(q{2gVA;yJd1`WQP!`4@A-4dDGUW6*w51~DaXsb9z^ygX3}uUNp~zfU z91qiD$Z({>blDyvKTF;rVRqulm^t_KD?u|QCuj=T#bllo=$XM~NtAH_6ygn;YYNp0 zG&xIpE>7cU5TS$2F=l|GudK-VcGEBze>)bF_@Xqt2nZrdh31Jc(6*A|s{vC+2@Ry8 zS&*Nt6sCPXo%EB-0PP%mF49G$&98`0N`Min<T#f-Q}Z?<>q35-7!2k1Y>rpT33r$_ zGg76e|LMrvTpq#*1XE@Or^V6Xtw?22$?&dA;lVm#nUDu3fmzu~tkt$OOi1P9x(gO3 zVQ#9kDAt}xDM1N_Edr&B>F3G)+HEs4ThTCyMmQ5D2!~M!c{ql7_5@-X&u}+{G-$^X zFV_fDq{skdw<&0cNAacjhN0Xc2axv7T3Y1?T>S=vra_5-iJ~J5Ruh%4-9>RI+mn0X zk8x=tip&LZh*>;OJuxT$y7i1PU3clI1v02UFF!yD0z0!`&|>XfgxNwo(gCcwl?biT zqXunUbh@;lm?z4^+l6`z2M#6##df3<VqnZt4k{a=$Gq+gQM8dX%9UZ#M2YUY*noQt zJ}_}#LI{>syDzyx_`Z-y;#|_%jxmF2Fa4NEu*8%w3LIn96v>4>edjtyfO!(BOlESF zQ`gwa5t}NbJzSYYPJy5Wt<evt65&n{OKlpF0OmM(-X)aGL_<(=hA2<hs+b|;dJD)O zrHmUV>X&9adUMbo@1&anlr84)?9)UV3OoqOTaySOn#$lYTya%V$&sTX0-eCw?8hN* zK^G>B6fzvFSCtGE_AfvwQoOth@+>DqVGG--GtnQPx6X{)1cvyj=6)Z91#gZrE{|L` zVY<h6=FU+~&73NS=c>)qL`(ER9>z2>U}d~$v49)LPoOOX4QtrhfYT~C&Sv@q9DPg= z!$2h#VsV9Ogo{^##C6#oMy@9~!Kbeire!LRsMDJ$RY}BE=Zt_vM`9(!hE5rR>iA7J z=9nkvs8Y!Mjq$5d6T#axA^{)!V)@_!F--&_F?$4jVsbPHlT7TDJeP9hGA`j|i$L=w zGX$R?$H-q3O>V|E0WCbLAMj`L9w6G`0hR6(p$MQsdG=N-;(_Rla91dy3d+04wIkZw z74dfD^jvyEZE2!4R0JczHUvaRkQ8{@=L2jGW_t6XFaf6L6azgIi2x(#fX7QgBtp2x zj{+`9*u+SHhSuwZ9yH`=B0A!XRQE{=)kK~*Sw~y90$;mqIY)J3y@@Le<X`Nsjx8v1 z6ar;!Dm76<A0~Cl5Jx(p4WMq9npxu@OWe*i5zZn0OhEE$mLCtB^4B9L?N+pc6%O#| zVuD%5x!B3V{3z)4BUroz`fz#IiRv=|E)zez-pR`ZL$;XofkGbx99^YNxUB^83UDpA z6;(+QrJNjY9T^e9(y1<BT+RCcG0u0HI%AfkNa>iE;9Z>n)NQ^e{U2F2X}GOYyJzQM z?u;e2eZB&4)d|9y;GRj7QWt|MUUaRZ{LaM*;uz*<5g^e-!H<$XntG^83h2nZ6w*C9 z-<Bk(z8Z1y!!O)6HbJXK_jLY0J)L_zlxhFR$IM{T#EjF9F_^(hXqzEIlZMey*$q)c zY#4`@6iSQjX$Rww9TI9ySvj>y6cx4h>Gv=gVI0ylO3yworyoW2QnU4{e(mr1eXo1^ zJ=Z_O-1l|3zu(XIdtLWEGw%yxI|k1WwgjLZLOa`Qh=qGCu^~WRWDiiz5Hg6PGw|x6 zeM1um;4UYGiS9$QBM!ek1^^>r?;RPSXA9l->Y?$+hI)KTFsiWt-ZOBA5$?B#lK4&S z8bEBZ_TCA&qfss~EC@r~kuNXo(d)H$)q}5mY8QsU-X;NGnVmbUBvwOsaQ9TR(*&jQ z$Utw>o~+8y0jy1O?BasH9FBd+SW?zB1{OO|#jbY`7f+VhiSVlnDL?!<!$bUCd{ACw zAy;zssS>Ut2H*EHU~z*B%TBXnVdY6I1iUq@_tM@_;0ob%AVQA?LB}<klY-)3FQ9<N z*qF#Y6=YeHhvChgXkU`*V9O#4sMlF^!=w9=AVwut29<e`++^@R;DwFB2tRYyj{`LO z7zf7i*@Q@u4oME6i6M+#TOE)7gYeP-b_dC?%a(E<fyI5eK(j>}e7XQMS{NGpw1=S^ zoZ)~Wal!Z%EC?^<0un9Ia{0s6HAxxODHlg(xE74BZ2_g+XCaR_c37{28+ughRlSCN zx(oc!L#&N=xSE>L{({U)W!(O{qG-f=n<vi|fW7}26!fMY7yJRjf~%-(OwD-TacAMb z4ZnRAV@krQ%w3a}Lup!}VrL=EL++|08>d1X0Xdlq8;Lj^d}@!DXjr)q*AB>K*f{03 zuj{eG^%f*=k0tJz#hLv-HTffvf|(%(j}6zJOk)B*I?gW18tMW;{S9~O%EQC{xS%oR zfY{B=%gcmli|NYCO%}h{{beH)bX-o>0l+oTYM~4>&-R|X#5nb4=z+ZgEYH<P%v)$G z^Dv;P;RGy7FG?<*Tm-)G=hy-`zkSZucohUF8&RoEfQVb=+pumq=OSRvuipv0fGr7O zHx1X52!m~sHI_a0_ajR(h9kaV$O2JfMHRCT9&g#^NrBG(<8T-a3N&2h5O^5E>8#Gd zqi&aOovLhqY`4>rWu#vXLHP4F_vM-a-1D>TEpvx5^wjLY29n!{<bcoylIGcv%|<Js z@4!U2XQ*vYHD?X7(;>nb*$bhv<&u!Cm91O2&Re+NVh1XKGHZgt7g!Q8&5ti!1rnaM z9Aq*)GdIir%y)*&>Kf~?#NxkEW>Xy2`&K7`3?r1)M5HEE0BLtJt3}s!JhsrtD8m?8 z70|{hKNu(a4R|J5f0h4JQD0Du9GO*hK0Yw@Gd3Eo+SgJ731i=RnwySeJ{fsL>^h?? zM`A{;dKo=9@J(VMEEW-R79pqM!0^nlrI#Cw(P6KkVku&sF~TN0<}X0nU=Q)%sJ5i8 zS11z(&V3#0P$`|ZfK=!p`|XI=nK4<t9%(&@1av2N%iW2ZtW??`x~Q4*I%BN;hz*dN z8IaW^Mc{skejWtTF>R-C{~)W;ubZ}aBUZ=PY5-CVUQ3`@<2%zkXZ!ZJGu;-r6ZsE@ z_AoAN%*o(@34r4Hc1Vj=hV5!fch<6$t1|tw(~BP>20MT$gUV1$dvUySNF$}5jd(Hy z%Ygg@<?LV$d+y3_tPS`JHNFiyO=E$Y3o+}-1<bYQr*aD)P0#F_lZZTZPO0g%oS$TF zX<_4AnEHV`HxGqAd=}69ivH;t_8n6I3y%{ESJTG!o&&?7Hj>k_oZydTh5b0t$Y;PW zMj>zv5Xf^^38Jta;84I5Cm|z25{~lFSnMB(Y4@w2Ui{Rr1GymvIJQs%^@^_Gfk(~F zZ>h;H91Tv9${p=55dA>e_QrVt0Or9?#Y-n^-B6xDg$H<NJVZR?qwM=ZWBf!+CI1gT z#yHqWGF+47kw;ZWl`@+R{XUB3e+)RTBeC`Jcc3PM5=oVs%GPPG@z5QR^Aa-_Exrte zzDyGw)&~sBmX0L?Df9wmckPmiMc*{#Igi)mFY{e8-{wU@;8IXJ2qYo%oB61t0r?_B zudE4LdKM*U;=GX`90qV?1~}4)h-<C`bpuzEk2=N0+~<Be{S!RcY1XpE;VpptQn0Zi zfv&u?Z+x1TH8)^8t^o|->stz)Lq7#|jusjKQMiD>@@w$gOm<u10k&P!;rC8cVpm5& zOkcnY50vNY<8d)}yOKTz*@O=^r<zwNc;96>H-VwiT~=7IyC7VZ;C9Iy?*}`KaAqE? z&op^nJ(4n#jj>3;s>>CyGy}tE9zaX*e8cBcA77s+>aUCFkJ*7?jAP_|`~N5Dhb?8- z1dc7X;9g2Ya+oc~8AdSP@*(z`Y+LU8YrDVprr;3P)kFsYUmp#RW#{$Q_&eHN`B%fw zf2^vgyuUNvB-29j^`NI<K}FL0?rly{kyL!Sv_|IpGUyEtau%q>f<U{bXfAQlTW4s> zl70TBGiq0c*$wf5as0(uBR2pc*E!k7xQ6WZS;E0A#T<#PqVWxlQ0oX<j-i6V+UFiG z^=THAjl1<xvH|cbEga<+D8s|w#E_6P;E4~YO9c?}CB~__Vl*{l1(7*TTx_?ehv`Di zqeWzx!hwcqT~V|r9OU_cwwqQAK>c!QTI;B2O)X;<A)cXTa}3pGt5JXiR~ehpQO><f z^WuVxK@xi{4|ctuunQ~hNS3w~E9!1qE?&0ScljUZOoRP#<*<1L2`A23o1Jm*(NiOQ zZp`$X?13$9bo7(?;9jMSVppWEgNw=Q($trH9-;PH9k@HsTU8|aSqx=ck3sf_tb8o- zE3g6{C;qK#cKrF1X1Q2Qv2C%1B?vl3(s11sEyb-n4XO~Bn=3(xV3b;6#{%F<kHJ&0 z3a-(TeMz;~jRT2kOk7oZCpm$Y?SLyucXxmnD8NC*roZYNsqb&RtF$4<1;<LjJeaGh z&bpDI8JO8oYbX;hDKV%v*db`*gijduI1)8et$KRWdPNNJ5x(NNEU(&G0Ju)M7<gJO zA$CO3>TC%H-)tuH#TX@4+vHxY3z?PZwd(AqALjaOQEL?tcI?>N@vMPKpc%ujFx;KW zPK>szvoK&Hj%dn1`Xa<#Po0}*3$Sv;u#FL50CCJcSj09TURnU+x~R4OM4|I9fT4LT zjA<L}yWp{$XO!#kYbY5KiWyXd`2}#e;iy+Y((b*p+-r6X;v?91)ax{|=`l`*@Ic0@ zKk~pHt45q?;(WnxAt~HsT~5rv@e^${AxCM}#4+Gst~X=BcWoDDP7m}9jww<~12$gR zSpalF9IHjJ19il6om;&hI&$S-wGVI6S~$UQJ}N-ZMTu7Rl*M1(==IiPiP%>&b=YN~ z{;5lgd~z{qo5Emtmw~CRe_$durD}bF1LAx6$Cn>1dA0d6e`qGCaLvJYeT{!B{K6J2 z#<bu}e${f=+|4t$T)A>SyCYxU4rw|lOTJ`arVyG%#N{kT1<`BJz~EW#Gz%8jFpt+A z{$_E#4~NKvO9wSM;gYuwrM-W0v;E}~sebN0ZL=qugff=5T<ATGYC`Eucds>?%2~EG z2Xpe4L$~J2*h9zEN9mKr>N<25NX!HR8Su6;00)mZb$N|@E&cc`sB={;ZZ2-7^ZH5p zGOqyCR;A4A%8^J*TdTN*)&98icCaS~f}k@Bie;J&{)uBqZ}-uOJUs;8PIjGB9SzBc z)|mugj(cr461D1vxFZTJvQiE|+$Zuo2Qx#?&fW!*_@-CVsoM%j3r<4m<HrVvB$&#L zOdD$ln-7@pCd5W;GrN?fhR6D-0K)l_y8%^$SqLfrR!PhvH=hwkRh{^YmhVr+RfUgD zCDw3xdQXOmYU>U9YOWH)zK-KAXQ}9XAaJw&>PfiQ$|O^PG@}Bj(Wp^KQ<X~1RgsHs z+%q|8WKo|QL8db@CT9F$_(_S?nwkuB8Wg}d*RFxngK){a<u%!O+_6-nAIk<E0Zke% z`WmJ%dpo^rc*vtjJ5Ul9R7WfSee;WNS2zan6LKd;sDB#=JZ{=?{#$Q3+_s7hS`-{V zQvDGwMJLywMKI8tt>&l^4VdEB&&{mVv)Qa?X6Ps>s3%O3Sj6Gw!J7}v6_a-86n5dh z;>lcK`g@Ht_07zo*$s*x6>pnUh?3$q%PxME0O|@z;*Kl_n`jY<<*z)3hke)lp=|<| zHEuZ}3%Y?YaZYbNE}cQdVYWbeya@2dT1qu;L-#o6-cP%!FracNt<}K6?N}``8W`eK z=(Q7gH~aC%ACF6LBXx4{kXZiaL-)mhjt-bVxqBU~0;S8@k(~_piU5{wsS|8G#OOx8 zMx{;=UMkwC!xP*zwWAe+TjR+bA&YnUUyB;L5w<?pp6Aq(%t+A%!|sQufOh)!z=VM_ zOB_pzCUowzLS$G`@T?do>Tt5|Rs=iRCL=r`>te`XC4|Q}o8|nH=91j%BuVSNI<Dr@ zJOarAR+-*N;f#~+AIbh-3vFkR6Vu5V6Fmur^vAAO)9N|>?QZ+bsC7pQ{>()KNnS45 zzQ;ynR_5pr=)4vp5TKFszz<=;Z#yl!gjE3QlTsU#t2I&z1mk<CRo?wUn)B#fV(4r? zct@<Fu0Igz$z;Z+Gv>>|WVy~n;7bn_pL@03u}VuRWeN47UZYp+!kL-<GcC<j>Vcnc z+UOKfLQ=?K_L>?yra^J(sk!aC5`zX=nCAqL;2S8iB?kBe9#=1ZkftBfIUPOpyjWfw zDI$?(<4^rkib&BAI_=4=)KcGkBci>X;dTnn{mER%DgPZR`U7Z#i6gNZYN<CJHY}|- zR3ZKOWx0;C^w;@Nf_qKeyzX<07@Obo6qNk6_@?$xSF?zim9cmvq?%8q<T$V-#oeV5 zZ7W&9;h>|>rGlCd>oXiPvr>0Hs||tz+3aC-82AecItn@QE@0uTICm>9ubg=AX5FEt z;a&30e<fd=3z?$fDQ26mt>rK={Y5QO(tQY>lR>F`fenclRFMt2r{@U$myfAiujxuV z*umb@M`q-W9RTN$Y9kPU6^1^Un@+Z!3B&mnH-j&pM5yE(^So}eNvdl?w>mu#Cw_c0 zcj{xH)$P^tyzU)oA>Jq=uG$$gSi(ZjGzqMztsVxZxb%}E5|0qKX(Fm!XXT=(6!d8g zQe>4?lo=A{l~<DmSUQJ`QFOMyL_!Y@VBGb?@k%4nRZ)^}iT=909a3d6RAoLG5Lp$0 zE}&|@GZEa~Yla7n=x^E(*LGI8rk?h?q#66PDA4M4>`0TH?R`i@6Zv~cxbm*yq;d$u zpf_$GOy)~AT(gn#y@S1vW6F`V$DtfU>VOv}AZxY5gpmRj+EZ-|lYjUioggpnQ~;V- zO^10|!k+8enufWAX)!;O2j?Ots}N1uLr|yfcRz0?;BT8#xa~)hL>n24TFkRJUP{2$ zWLV1-=wS0!bY|%B*TTWZ&1e`S_BeW0sXo>Xa08vy^hTgnQ~f^oOq_lp{BaicbZ8H{ z%o_*>eBj62gRA0_`XetU3Uu%><OHoy5U6;+E>AZldL=!|3^=zaiJ}4s?3*dx{HijF z_PQzwG17rtf~x?`-cC-RDL(J(Y|Hz@fK^!5f~)0>UUxPOmjb2QXv3(wfa8adz6@vE zF!8A0zgw@!)O4c*R6L+kBL`8$Ahh$-S3Ly;KfrQ3OLB{`fAD~0R&Rc&W_f)7OinGJ zrdVljMqqZIpRq;NFcNnInAy7!&`&_h2Ka2Nw;Fll&aDn~X=v4n3cOvG0-wkB7VwRt z2M>`EhZmU5on<VHm;6g9ydmc7-6(CmE&{R?#`y+5Ys`gnra}%;L|co@AKW`Y-4qQY z?x87w_=;G#8?lH7{wE{nnRf;MTv=|Xf<oD7`95;H9H$5#0dBhX45V!swV3WQYOV9w zWwl2~ceC}K?_a;Z_DkVq2@{4WER1~Tay|8(@Zfi_&}jnFJIeM2cBW=9Pw|WCv~c6m zCTAZ7(0dUznl|;49AtZ))}G8>*O^w$KW9w<0|B{P4aR^e3-TYdm=%~FH8mJ;F9xS0 zDdDKS{U~x;rj`CbyLAx69#6mW3c&~9g64X3cIb|(M-mAKUvtzcWZ3)yQhVu*sn;DP z_~vC?Y(zArelz=_o$7kvaU9UDITYj%9vQQ(S}PNttD<)YVrEBCI+ulm<yt!;``0z> zD?PK)6FJy%*!;$g*AyLQ{H?6Nef|xoFRjB#(0|$HeSsEfA~ufl{L^u&984}YP-nFb zrgySnp3(x5s~?37)~^)p;&nc``;xuy2Zb7Avg7(gIfe{MtB6tU`siko5OWx=xkDHp zs*OukbNFETIxLf*0fh#fR88H*JXoFpq-DP_sc;4IA%7#c>9f*82z;{@T76y|OhCag zSK~@e4(u;|_#%fj3Qk25s^(+PRV)uZ8C)q5vn3S0m-_+{PCTx^XA&t1^#pRga_hF* zPb#)8+*MK!SmjJ?L?Ex#3PYD|$E{F~C=<o{M-LKS(2X{DE$m84yQkp$$HwU96DjiC z(QV5pdmyKBY#Xl6=YnkgMf`(zE<I>lR1$c@VQUdq96Vo!MF~6c52uOyYDm6@t?z;k zer4G?*Nh?ZnG(*oEAw}gC4erTEr#eE1fnyTUK@pCz{|hQJPB!<?E$^;cc00*xWkN$ z1t^*oV7O@Py~0*^z+DTFJA(b2n^5M2>@aK??HPv!G)9i*2%@QGd>o~uSn!dz|A*So zwm=E2YzTP)n7pccYIh$svIeU1mc8ZAl)nutcWs-0(GV~_Ty@^HFp&H|c?2v2!R1}g zv@eR}6e?PBC!tS?tzSW^hq@#;@O$uE42o#%9C86W4h*?M*KeiwF%Lx$AE519umb$` zMuC6S3a!BRd*@w6URabvlDR%lz44ZFeV0twi~B4PK)zeg^SH}j_)GvUng@XB1#Kz@ zelg>a%wx-P3K$A{UG4GMdi~#d`mV+#)h<&L=QJ_uN<`B)Bqd6(JPz5!2%!i3CC7x# zD}Sq4@n9&iK7#RW8^63voANFc!=?u)fW!$cyQXJzemF6Gk9-I)=KYWbwK8V*m!w!V zvVlDOQzttidH=iiwHTlgdO`zr7xZ@;W=ueCNLgpxL+f(3ys`3{z2>${-l0cK)EQGk zz4HgBDP6Vcq!_-`gLv2F2~IjWhrieVHj4+}P~Kejv49|9Hr+lD^08bHwL;3R<~%dA znSZ2b4Ar3*AiqaHS-E_s{j$#Qk$G$NC^UWq)XZZmI)6>ej6P#?yUNkT*%R7A?E}S~ zMT1CU8uxYe33G50o?u8O<U_gxB-bjl4TMu|+e3B4b%D25EG=Kl1BAoqwu9C5<gFYw zihzRDmItqpOa6{UQN`sKoaP<n(yY}S)e7Bak~T$WIXOS-+2!^~zF{wP1rMpf8)B4@ zP`24t<_!KN;NkX`zukJ}3qz*Rr4_c+=(P8Ew%f2F?sjyc_OXmh;UwD^>I8>=H{U&4 z(D`SeaGC;=V>)TQ0*4@TQ|-!6?5_fP;YeKDysB+}<zp|mCGO0t5tnsyp6z)3yUKq2 zK7%U<-(^MZHo(W5-bOcJ@FT&2$a&E{0f{EOr=F+i;Lg{ZV+6$DMm4xRGVzsDzqmn9 zV74q4M5SDK?)0hoOLxfLyf7)I2z37fo-yKa<{(4?#BaS=xBsMcDpk6xR|hYKyam(J z=NDKwt6I=R$W)D$t^C-l@5B@2M(#wH*4`R+`VZm8e)hibz7vE^fO`htNY5qrXL8dp zkUb#LXQ|HM_dvt&95MumpCkN3!viT}HtV_m@4pvP9xi;@7ku56>C`wi#fH0DM`Si% z7#Hk%&}sN<?9*76Z9LLIaf;Po9(6z582AO=db{>aK(w8IY<ngh534d5iJvh25e?|o icK<aO5S8gz`rW}PDiIGW9=KdO5)7OJPt7mn_x~Rzf%CQi diff --git a/taglib/tests/data/empty.wav b/taglib/tests/data/empty.wav deleted file mode 100644 index 74b5a6de7b02e17ed293c677b873f446f77d84d9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14744 zcmeIup$&sj07cOU#g`Gf2C@Q@S_J5yG^o}w2qQ2aW56DqtFJoaXBf6Fncq{t{MT2T zq)MIRk?hZ;Nt<t3%kO$bfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ gfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5V*6z34A#SivR!s diff --git a/taglib/tests/data/empty_alac.m4a b/taglib/tests/data/empty_alac.m4a deleted file mode 100644 index 8c678321847428247a7776afb210b362301c32c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5380 zcmeHL&1(}u6o1)T`#~t_he&F`p%l!;kk;J1L{RWj6;bdY>STA5Zo9L)-I)aHLE_1O zL%c}AqemeMLPh)|?4RJxLt%YyKiqAsB2-XeUNU)a-g`5@dB1&|F92X&wHs`-t}s9$ zErQm%BYi=0fO1v%{s0YE3^pzDd^}s)$MFH+)m1Q_w4ns_%;m@g-DC51o_U;Q02o^; z<l7j$ueM{%sT?!ijc^MRLyY148rL{2EQjM3OjyU)b@zP?u(D~nVFo4rzL(jVF1-<s z*Tq>yie#rWvT7y%nibj<C!sTz`=QGcyEK%l<Dz{}DjBnz_~ANtxrsJOUY7wCav<*{ zt9cH(EA`nq10wPR%zjF<m{dx}*+?tu3z$e#+;gstx`wz#9KxDR;_w<{kI~Mgjt2XO z2i6TusZ1X=$#ha{<vGB78^>pWg(1Kq!|@hi=@G!p<-Vmj>Px~V9m|m`j$IP+AfRiM z$QLB<rQ=G4)0I7s(|xjR@pv_{2et^*?!)xjRL#JlwexAl8Ok8320b32{voieL_ifR zjIV(Dp7JTeifGQAzGq9e)@-cfW37ep-bEDDHDU9(TTNdys0O={WMk|c9^6I^*F4k5 zKJBqvJmi8}rJin2Q5e`E`AXdEPzz5CI^hoaQC|E8%u)tJz&CE*-oSNR#pAPPDu3Jn zn0n9+?YPMJy!u5mpc&8%Xa+O`nt>BDFfr1ft|ul@Z=f0YI}A*g1%3}_0H<JadgkfZ vchL}k7Jav(XVK^&I@EE^PoXPxe`I%xzCZqx_Xqs9t2X@Ed))ca!T#YliGbjW diff --git a/taglib/tests/data/empty_flac.oga b/taglib/tests/data/empty_flac.oga deleted file mode 100644 index 444587fd0cf950ce092cc5540b81f973b52136d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9113 zcmeI&Pe_w-9LMqB<7R)X=Hpsx*{roTTWGc!ViMF+=unb}K}D3HHir-v=4Ay7v44~u zIut>N3=gqOk|2nUC`n|P{Q)8B5O$FcQ6nW*B<uO?vxd;6YxMnHp5N=?_j{i4zCAzI z6p4gXfy#|@6U`?uEsfefX*<sEYuwwQDP?MJY-up=x^<-+7mHGQ(X;xLDu@MV5A;p% z9~+2|mW6&sAI4rc;c@wa#~J&Tcl=CTt28U+a~bLiw}-pJoo!*)$&OaM!WF2ht_rxS z{r*~iU7!}*|9lR9W2(NtTeF*#vSQ8Rq33pFaszKR)~UhM!%s?n-^^colxy*3nM(mF zAO)m=6p#W^Knh3!DIf);fE17dQs7@NkUdPnIZSroXv8>*QSMf=N6#OLaN^0Wk&6_N z0#ZN<NC7Dz1*Cu!kOERb3P^$fuR!+u*&K}VZxZ-^E;J%^nrjApmcJW%CY^MsF{T^& z3~A%k_B&9)bIPtkrb()&8#2GA!ZlFgTk2~NTJnmTd<QLkLmeB0mi?f5k3-8BD4P!| zny0o6K`Z8{(FthfEY*AoTJ?cS&Ow%sRH_3i{z65ZkUm7cyaJUBQ%4pcYl3QtK&u~7 z->i`B0c8zAYvR<!a>(9KB@)ou`&2~|a$Ke6cR}l}Q*8&K(hJnlX=r^fHFXbi-lDe7 zKxH?m$2Xx3x2em;(8jxzeim}MsY7mPlb3pW7;;xq=_zP)1$Al!^6aLreTTetl(P>i T_fuYbCLMKbvFzDNznJ+2futKO diff --git a/taglib/tests/data/empty_vorbis.oga b/taglib/tests/data/empty_vorbis.oga deleted file mode 100644 index aa533104d6fde177772775137cb7660a3be11418..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4328 zcmeHKeNa<Z7Qcaj0VBRZupy0Yf-jPnCQiW6B^Gy+lxT=X;6W@Ova5Uu@necac44>9 zMDnm{piDN#)TXHen52-3E3{ba&d$14sftBDD!O&MwWSM)PRCvUsI&j<p7(+u-G90> z?jN1b-nqFs_uO;Ox%YR@yZ79Jy1HT%gBHrk8-IL(CKr|8-p+c4^~;wVtE@Jf5tDa} z{zJ$<#A5zWu?py!4+}k$9{Favk>V-;_1&^4HmYek2$WhI>Q@ys)`@pnt2Q(G#rfha zl`31cTBWAdvErh_QvHjYSxAczZWGAYg>1_xOsFqRn-=Luciu_UZ{)R#vNl$XNNsLO zuuJc(knJCHTM#|rRb4Zma_Kk{O1iex<H%SGlv4vdE6v074;q7}9!7PX<<zt)hwJ!T z&V3PO(3E1pn-fz@^{4!fV;T^~vyFw0c+H%MI;)VmTF<FYEu+}kvX0iTRTn;WEY>^y zj{NNVLaI*Jyew)1*BRZ8c-;j7wN3{sh}WFrQzN=wAtl#vo~6X<npEUQsH;cj>X9X4 z!ofsz0U=CV#Q%7Y=;Cih7Y9U(IZMjo01U(dIio9R?EKp3!OJ{Srp~+;QH%^SHH(>U zM5wTcYuLkI#LTNfh|`th3YEG-^{!cGCx<$4EC$&TVuKm=i^aL?y?IwkEZ0u%zVTSC z@YSX<(*Z+l!n(aL-l>XBi)Z`*%dqoYs&n=SAln6|q@IL+%@={`uCgS*X+X0)U>s`k zyyf~(GaImtUYrSJjsn#aDC7D;ZZ>ePt1K}}Wel{8`Q<ck&*-hK0p2iBEBjmA{?~_q zitD#_`Zo*!W&E&(d}{;Ev(c)UX8!ywQ6Pox_Wt2R-&<qnfhrij_16IQP=t|VK!*Kl zu>-Gf`wPLDn5`GD<5dZ>Zt1?AQzZx;0sZ{=Tz$~Hh9f<+hcsnG0gpjij--uG8Xq)O zPRRj5<0ayqu2z%0ueYZoYeezhWu{qk=h%BmFK{!@VJ|+{e~v8Pojp~$^Bc{q-|_zD z@}2!dq=^W5$wUS}F<`HcPpfek(VDBA#5;k;M0sx%PBHBogbMy48s{y4RR1oz!jl#y zLsd>@Wlt6xEKRl7d`)E^?5numR{8C|&!OIL+E(hTE&EQ5ZXG^qF$8;bBgC-4c3Crr zd$9-G1c#yq{(2_f@(1w^6Zj_+ih_IUf|RvIe8Z&LGM-vl^po91&(}_7R~A2CY1zE{ zCExCflTA0?sJ-#+zAqlDm5Z1yCL^@Qvx4xX6Q1duPCQ>*e?gA4@$?tz`byS0o#Vmt zJyNTuuEp2;rvKKPN8}Mk1YxuYU0mU2S6{QMx4Co9>8XFy*W2fR?o#;9>EpM*uP$Z+ z97kv`zP=G(PvQm=2nJm{mqu6gQ6_F^RE$ihqk9}rSqp%^v^RQaEI0rm?!^=Qk#UhZ zS$dUJT8fodNyF7*%l8%Yq}rSUz$PF!3%RjkrE=Jx(2iG4?0C1UnoHgZ4H)HhLmynq zY!eLqT==TD2>VSRUhUFdRtCq2mHksC`Zj*>aJ4*@Od`Q~Z3y$TZZ?Rtg9@k&G6=cV zOU81So=`7c=;P*CMM13kO6)@aN&d7GYVEyTs0&KK(A`|#-8|kxUvVW?Jsz7|1gFOn zm;bbN0&L~+#&RFC1%`6R{}=mu;>G@7!H*pQ46eGH@Y^ck3kTDYGX*smlko%(`;%Cs zFV5@;|4GgA)aoX?tSa*(EN~dmO^RJ89|p$M&h$q^9vJAdVg`E<2I_?mzafygqL#QY z!{L=@R-2vadAxAKqgjtra54)T-~v~5b04lL$5qQh_URlS<OH45rOP0X@=09?Z7uW5 z;Glo9@?C?;$QgqgWMJ^)0mV(Qh+iB;zPPbmdzb~g0bv=vx)ZwMsy%i%_+wBJLh<JZ z6y_9zCusF&xbXbR+ycJUKihJ|diGu}z3rZQKV~RWn-7Pr5xL52NrimnCJnnIeC{jM zcHkHr>0^+{RaNGnX*rVN3itV=S`6cAbFn4g6K**I$&%F{jtnZy_j2hgs>EVxTVO{b z^I)ie57L&aO<&R)z+z<nG-GtK#B6D*6uZJ!e<Tt)zBsRd4>~KaHSM2$t;ZUPynA{T zW~S9ORhGrmD~#N}l%=(RrplLmEPBfA(}UbX%QYDH)grp57y;CiM35MFbRF!Fx1SiN z7BAIyOP-6d%Mdyv2=j|Csa8sYm~a@U`1+O7&;%I~2T77hrAkb4=}|AagRo#E(dSLn z%cX}%gs$(8g<o4?{RI;eFGY6MI{MPylpf?)k7_b_q$_haaL|-F18Gn`kp{Q<Y|zW3 zJfw-{X^0S$_jpMYWJ;S%gp?Z9WrVyFkRPQWRKlQr^ui2#g^q!nWFc;6H4Qf)<--|o z$^7A!`B4W%E<V8X5V(<sJ|e%C3VDIqVyPTdFj&r?R?)BlEK$%-ui8~XqgI=CvL8GG zm~FY%RQqS&e#P&P-}!71p}Xuws4M2_&Fgar;bMilMoQn8T7kn2DS0iXPn1wzk^^7G zW8t5Sj1cl215<QDHKnbC1}OVwru(QN>Cs2s|B6yVa>it6k2P`VpOzeS|7X`vtT~%M zUb+=L%CbYapAm!vHm;rsm2kiVdrQjO2lUR&Sv>e@`L6S}QJqY3XsSwa#FnHdi1VAP ziwKG&P0Ev{?WXRd9@5l*wX`F%FE~}+-alN`kx#t;X?c6*vK70`eM8rGygMMM-YHkU zFR1P~&-q2oE@k+$9ZQBeD=HMqtK~aY!-CH%+CwM(?U_Hl{~4*soZ5oWuN<)`ul4oS z$MCmPJL8`c4kjbOO^iX1K+Hf?1j!B!L`9OG(_I2QhLU(Y=;&eIKcoqG4CN;07bwg` zyiL!bpGZW=!Hi-iSt!U~cro<_y);GYVYlEYMot=p4439{y1{uSq79~nys%{=lx#|n zQpqGig!m?o1O|auVoK<yk|8*0>_LHv0Pl)&AUPK3GSV!|wjE7)>Y3=NQUf_pkC!Br zhSv0uASl?dF4b08?&@vilArXEqv9Fd=gg$M2TQVM_<F8>UevUah*usG=!XTt>x~<_ zZAow{>X6;;MktmYw;G+fiN3U9dt=z^pGJ0Z-gal+NBV~5!UT+0%+gl1>Q|wX(k;Qt zE!sC&tLDBs9xGu>I66gAmz^yNG<=lua`V|Go5l!vlNj_Ov;^IS1#Uq+-uUHhHTAn1 z_BOv_r<@&bI3S^<p;zGLD%IxYscnKZ;nSk!&pa!Zq_4o?7>~ZU#dgGIM>8t=1ZT6E f2Q~Z5ucPNV{h+3)?Z4Ys(arjy7nGRv!!G{@RvL-o diff --git a/taglib/tests/data/gnre.m4a b/taglib/tests/data/gnre.m4a deleted file mode 100644 index f925ea9eb5d1cfc12a1effb51e3208737a97aeb9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5026 zcmeHL%Wl(95Iu1mS_G(8d9|erCuP9`Arblk4Np}<;-N}(frOmcX|39E@V%)73zR*Z zO0b7*C4PVfQg;0U7HnAa0qnyWKS&y(Zb9OXV$IC)&CK{{=H@y8mb&^?KklzLK@lCQ zBnE1qW8c%?Z6FHUUC-;dH*Yl8f!lcJ+D$yDWAngT#@f&rh6K|IW(v#{{0mdSJ$zm^ zZs6Q@oFx17qj-PUm(6|j^WL|kg}Dfo7YC?aK936IGm&Es;TeBpvhq)sMQ|xhd?h!X z;cz&IN8|CrcnsKDr`{gn=Xx)zrSiL$GK<tRC0Xj3{3q9AJFy>n4B^K9%=6;YU082M zMfm!zAEjj~l?-~NUFhmj9QL|&92Mt*iW^t`9AEX*K<<l3iDw6C<mPtut<vp?_Kwmj zBR$9QjK8c>oXF&{EI0zNJds<0%E_yeyaoZA`ohLVV1-G30B71YBG#gFimD=fyGrYf zZ`$I2;FqW*g*D>!o@KlippcK$42IL@G93J+9=OJy>@c^8^sJ1-^+HSYt`;_XyOYos z5!~g{FF<vZ?pN_U$9tb~vfk$mh|F&feC<&`jsww|G^S^t`$g*Y`!cS%JmG3|(;z4T zqYVRw0mFb{z%XDK_%9e}gpuOg6IOP5shk5A`7%|W9)L?kUdjpK#B&4}JuJf14|O7k knB^i24=KR?R_jjjcN*3XTTi!$U72366)5etQXMM&3nGA@LjV8( diff --git a/taglib/tests/data/has-tags.m4a b/taglib/tests/data/has-tags.m4a deleted file mode 100644 index f48a28b520399cdd2184f965f4b690c68f6702d6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5108 zcmeHJ%WD&15TD(od9`_IYG0vjnzk0Psm2zG2HLbSHKMJQfF6Xp&2DVkY_?>#MMWft z2StQ};z5Lpx1xB~gAk!0cvi3$#G`+JS6OE^8=C|Xgn}OSm&eTf_S>2HW@o+x06KH( zwH0Y)Gztikc}120T3$;6uYR!t6!Hr>p3ibeBhgWSNqE3nqc9zU^g7!G;j*ciMKC+T zoC0$S{)Z_5@Ps8<Uc<AzAgwJ5bf{OppW1$VHk}4$ejQpm_5%a--bI6fbdx=?yYhD$ zi)3eB78JVZE0@c5nAJ3|rU6)0wZtzYeMw!`b76kvQj0?Q)Iks36#vipSbdU^=g|cx z2~GQj7fE1mRt)!{MWIltg;M0zVof)s<(-r-=FspdQq_@hp<k%-L7^nlbpoZ>wpuE1 zRo!w=Q5OoRUr|&=FM5@S3;2sl$q{z9#e$CrOpkC(RI0_ZVDb8pu%Zl1v;%ZwkZ%C3 z3oXd7`+PPO4Aq-cR8_Ax>SS-=O(-Y?TfxsmOyfEc2A-lsXW%qHW)1#P4-8>XW-&H_ zdX~oFupy~=gNBa1ot0515YOS#HvpD2njgu|HugUH(R&|ffZz<T3M!AXM-oZuXqbIG zFG~E%3XN+G?CpF(QPB!*sxk%d!au)sGdc%IB@$D{-(LuCCgw88_0%uOh>FT3N@`yB z@oX4@OM;Tf>xWEMmLe2TjN~(`MUe(KP~;^MB@i<+J9iG%rFxg#5d(X!;HDmB<uy7A z=Z%OS%H;0(nQ6DH+l8t-eL6XZk{%Q5pzj|a9#h%}(#b^T>XYn^jrSGA7JXF!{7&ZL z^E*5GQ%j$kNxq!Cd<(;j81CJ8CupCvui!hAN~eHf7!dFU+73*C(`I+rZBB>7;c_`! zJsn<;+wBPk+Wj4Uz2R`Em*WNwjSUYRj1F;JWPBugJQk0~`-dk}i4&=@lkpfiVO%bk zr_Iyj_4dRDxxv_9L#u$_f%|1GOdqg*#^PtREojG7Dfc?qkq-EpS)j$Vtp-?awAkOo v;<i6Sn}xwJ7C(%`{qn0WZ5zP0lq-pPPc%3&4YLAf1<VSV6)-EXCl&Y!Uf%vX diff --git a/taglib/tests/data/id3v22-tda.mp3 b/taglib/tests/data/id3v22-tda.mp3 deleted file mode 100644 index d89ae1c4473cfeec3d8c9a1ecf8c2fe0f4570506..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8192 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 diff --git a/taglib/tests/data/ilst-is-last.m4a b/taglib/tests/data/ilst-is-last.m4a deleted file mode 100644 index c56c80498027ecb7113d0ec56042277233361ccd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32768 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 diff --git a/taglib/tests/data/mac-390-hdr.ape b/taglib/tests/data/mac-390-hdr.ape deleted file mode 100644 index c703e2e2fd595469973c4162cfbebcc0722ab829..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 128 zcmeZubXKt8U%)TMz{KFPhJitc0Rp&yR9*@L!%cMt1`s>Q)6MOUpcX^8W0-4NZi#{b zP>d0(M_?lp0}F!yLrP*v;trsi8lap{9TP*cE-ORIPIiXhwp<L~F7Yr#X7e*VV;5q0 QIah=s$V;5zOy1sd0HO&R=>Px# diff --git a/taglib/tests/data/mac-396.ape b/taglib/tests/data/mac-396.ape deleted file mode 100644 index fa7ae4149460cc0a94174a1e3ce72fa4f1106138..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 104 zcmeZubXKU~zrZfWz{KFPhJitc0Rk9-)PX7{FbBjA@^o`kdCkcX?il8pmRq7A02E_{ h>Jiw;#K6KJz>tzylE?s569JSH7VO>34%f}V003n#561ui diff --git a/taglib/tests/data/mac-399.ape b/taglib/tests/data/mac-399.ape deleted file mode 100644 index ae895ba21cb8d6ca9561db087d4373d976503e3e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 172 zcmeZubXJ(g&%j{9z`!5@#5_Q(1H>9Y3<JOCbl$m`R%)zJn7KqqYVpYn>_8a>Mur1c z3=GUbrT_yIgUcEQh87@uA`s65;vi2qH<j0%4B?Jpu4%a?3IaeeMyNW0jZ6$IKwT+` iC5a3`H9bi(y&xk&Du7H7qX)=jpYR>TWVi@qf*Alqb{*XS diff --git a/taglib/tests/data/mpeg2.mp3 b/taglib/tests/data/mpeg2.mp3 deleted file mode 100644 index 13e8d53df6f32dc924cf5b153eb62b92fc13e65b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16384 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 AumAu6 diff --git a/taglib/tests/data/multiple-vc.flac b/taglib/tests/data/multiple-vc.flac deleted file mode 100644 index 93d9a8a14a2eb60b75cbb1be5c7975a095407b18..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4754 zcmeI$%PWLY9LDi8jLQr&USo`5#&u@nGP#vYk!EC~rrc(MTpAkESO~c-l#s&SWrvl8 zVkZfOg(N#EJ3D28gq86=9=861bL#Z=>381Eclqo01!{#5IVNFJKSm)G{ki8^L`<J< z?z=zwALlpD?v<h~ebt0k2%GvuXw;jaUU!SXq19jQ9vK@P9m^{Ie_S#vlmh%Mk1QYy z$O5u}EFcTW0<wTCAPdL>vVbfg3&;Y01;U^0RuQ6<B}g+wEry|pAaxvsB73P^1=3DX z*UeDWFxBCNqNk|7V<={Zdb@&RTdDj?Nav@He2~72TDXPcIw;dN6yHd_KR||hDzFL} z-Bg<aO7K!QlaTVWPZ46^2}-nc_Ph?6lBvr`C<)6M^>mLz<{0X*9Qu7ITpq}x<IH>q zrKk%XoVi`d>YzG%pj0Pyl?SD{sMkHnmPZ9IAbSlpI}fE-P?i@cqnIiTL78RLK?any dOnrHw>=kOT6v|nkns&mUQ&xxeWQ}gC`vy%NpK<^I diff --git a/taglib/tests/data/no-extension b/taglib/tests/data/no-extension deleted file mode 100644 index 65f57c2ee985713476ac0b6e3483e6fe472e2176..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 256 LcmZQz7})>-0RR92 diff --git a/taglib/tests/data/no-tags.3g2 b/taglib/tests/data/no-tags.3g2 deleted file mode 100644 index d31a6ce96d7cb701216e29bf17e15903e3fca5c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68335 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%0DOmT!Moqh7w1Y^2~HTN>C$n{#(z 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 AGXMYp diff --git a/taglib/tests/data/no-tags.flac b/taglib/tests/data/no-tags.flac deleted file mode 100644 index 41714416760792085717cb85fa1542e5a7e28981..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4692 zcmeI$&nv@m9LMpGZGLQwubCN}`LSJ$g_Iwqw8?T<Ar7<rXtYTjoG=HqY$@FRxZ&iW zxJep?gO=Q++}xDINbF?x>Lq{0=Y9F~=<_~3kMFQA*eisnHwZ)aDHcM}-FQ+$wQ{w8 z>i!PD#`dnCm6iit_fk|SP1zMWvVbfg3&;YpfGi*j$O5u}EFcTW0<wTCAPf8#$fQTj zVvbZcpqzPXJp-viR3Zear>F)6(kxN;Ls0Gl6>va#5o$UC<*!noNvL3$YV3lvBh-Zt z(v4H`N2oAB84jVM0qW}o()UxrZK&8y`SnnVmwH%+6bm);29;W=)GlNwr|#5H8O|%& znOKC3`P6v_^tUKn9>}ESpYaK*$ev^{YsZk;PK`}Ml@2QDgsNQB#|dO{QlVSO+CxQS vP<1C|dWUSSRP!8E(@ve)pxRC9#|zbMQL}AOeViIR%A_M^yXJC-_V@h)*-@2S diff --git a/taglib/tests/data/no-tags.m4a b/taglib/tests/data/no-tags.m4a deleted file mode 100644 index ba4e92baef225c0204347186c4aaf42e0259112f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2898 zcmeHJJ#W)s5Psq~5L6^AKGYUEIFx|_Arblmn$m(QRYIyNu^?4WUWZ!sTL-^yD#1`? z?^3DV=~{_Dz<|icFJORynIF(SJZHO2S|L^#{3zDlJ+FOtKHZ%IV5V!|^>lBc2|{FK z5)IToX%*O?E)YlUZV+_*Cy$#8z!DC9w}}@GtR6VCm>-l%S%k6^$|)$P;D49`?(n)S zZZ7b;PLf^PvEJQMvfPKKE8mBwYhO^=JV0&w7Alb67#9rEm+Zyyoqy6Ck~2}Fj2wD{ z!Qd)hjz%{|Bfzyb4Yo<Yw%b`Ql{}Y~ALQ~VlFtM(@>2Z2=i_=>MFCy-T1~#M#Q3-j zXKz@zZ)~YJJqu-${?3_R$m&-e?R05)M(2)-g9j?-=TsWXxj<69-cMsc*Q@)+wqxpV zj5S%&a~`kwWtHRv<JWTF3BmLPPeYRzugc=xC*e}wUc3X`WsqOMRJ%sTx#?Y@s7Sqi zV{KM%>SBN3LlhFi8S*+}8t;WDa7;;OxK>_e4gOINJY-LH7+WAcE93B}kkY(!h0fmY zB-91M`@HotP+g_@P3+Fa-lw0e_c;R@>V0JcYHzz~7*5VS_e2`>dNQWxSc_uArHRIg nO(f_ncc?r}r@-@8>sj&l7xO2r^$l|OCU4jXjrCipjg0*b4AhjE diff --git a/taglib/tests/data/no_length.wv b/taglib/tests/data/no_length.wv deleted file mode 100644 index c06d1071d5ac76d9be9d6eff977a5f8cd4c82863..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 532 zcmXRfE6C1ZU|?WpVPN<V1VAQ(QWyh+qC^ABdZ+S_ief>YZf+_+IT^wo!(7vHOB4iv zDi|4<7+lscFbHg9VqjqqU`R<UNn`-3VPaqg@>$tHroccd6NuFXB>(^Kh$sizX9DDd z>~pAN0^5abA2t(k=>@rfT)k;bjAZNWh#+6@s&(Y+J;TDpu*(J#H}CIsO5qHv`jVgM K;oRm(yj}nfOJeE( diff --git a/taglib/tests/data/noise.aif b/taglib/tests/data/noise.aif deleted file mode 100644 index 310b995e3c64878ca14d096b8e219f59389e6ef9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4400 zcmZ?s5AtPT5L9>cbaQj|_XV;UgculsWGaJ%1K%1KAPWfGe0+i!82ArCc%$TK2#kin zXb6mkz-S1JhQMeDjE2By2#kinXb6mkz-S1JhQQzsf#6_2V4t4R9Og=<u37ARma=Fp z{r|b*Yx0M`OLf`XqgZ_&au@QmO@GKX&0C_whUKRX@6{-2M_q2#X&izT3_(%<Y#7-8 zd|=+g|7&mNpR?0`w=Dh1eV93d|5x^<-`(w>v!*?M<o(ok%lnwaZ>Bu_cG%{JsSW!C zT}EbahC3BZKKwj0_&NXcGl(r^iH`c+{NdX@hCeqieQ&j4Ui^?<b_>7xLvG;;9x)r9 ztO_m#Z}I$guEn~%jO}di4~t7zaP9iQuHpT=j{nc^rECfh*#h{5PBQ$;KFoGim$AH^ zdD1j?&Zu8*TYf%S`b+Z?vr!b6l{aIl&5s+G{)O0l)|30SLhk33Ex&f@GBz${`}l!z z*N1P`6%3O6e^sV&>OSP+l@pvX?Z46`4woolcklnjx~%CBzp!O~dzSet@-T~~Cj$T^ C(vHsn diff --git a/taglib/tests/data/noise_odd.aif b/taglib/tests/data/noise_odd.aif deleted file mode 100644 index bccfd7283c4be54cb38d869161148a620cc0647b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4399 zcmZ?s5AtPT5L9>cbaQj|_XV;UgculsWGaJ%1K%1KAPWfGe0+i!82ArCc%$TK2#kin zXb6mkz-S1JhQMeDjE2By2#kinXb6mkz-S1JhQQzsf#6_2V4t4R9Og=<u37ARma=Fp z{r|b*Yx0M`OLf`XqgZ_&au@QmO@GKX&0C_whUKRX@6{-2M_q2#X&izT3_(%<Y#7-8 zd|=+g|7&mNpR?0`w=Dh1eV93d|5x^<-`(w>v!*?M<o(ok%lnwaZ>Bu_cG%{JsSW!C zT}EbahC3BZKKwj0_&NXcGl(r^iH`c+{NdX@hCeqieQ&j4Ui^?<b_>7xLvG;;9x)r9 ztO_m#Z}I$guEn~%jO}di4~t7zaP9iQuHpT=j{nc^rECfh*#h{5PBQ$;KFoGim$AH^ zdD1j?&Zu8*TYf%S`b+Z?vr!b6l{aIl&5s+G{)O0l)|30SLhk33Ex&f@GBz${`}l!z z*N1P`6%3O6e^sV&>OSP+l@pvX?Z46`4woolcklnjx~%CBzp!O~dzSet@-T~~Cjgc7 Bj?Vx9 diff --git a/taglib/tests/data/rare_frames.mp3 b/taglib/tests/data/rare_frames.mp3 deleted file mode 100644 index e485337f9e489dea7fecc899c7418cadc923c4b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8320 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 N691C_K>+}&{{TD^OUM8K diff --git a/taglib/tests/data/silence-1.wma b/taglib/tests/data/silence-1.wma deleted file mode 100644 index e06f9176648836ab73928f0e15af92abd5c82f8c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35416 zcmeI*U2Icj7zgnG>1H=(g&i@v5Dd+t1e`W(kcGvMY<7&vhmhfvIB*UrvIw%Q8zV>} zOfZXlh+a4_MsZHvT2QiJNYDfmBXL`#V~Pm|k$@p;Oi*LyoEZJT=bQ#M>y;Pl#s75Y z^z=O+@7v$$#gnJcS!Ye}Y2LFYVZU<*F|0bdZqsBqQx=z&Z}yn2bKH%{fzNw1A%ZBH zyms^S=GpkJ`P~V7&v*DZ5L^~n>un1Ub^q}0lDikQ9y~m=aY5ec<uAA!_LhX&OaC}w zUGMF8I59cHtR5J+$7i17*O?{QAJCWM&WEl5A7mV_4Viu}y8V2e>+A-5@Qe5{(|*Zq z_v0Y9bXSD8oWFc!Vb9Ex`_7fE*b#Df=2`twJjEA*2%g4WXy&^CR_^>|`u2H0&3~hI zVq{uoRqvGK-qw%(!=Jui(^9$p$=I&)kwtx*lUw*~A>gP05AZAx<9<|mTP+wlKj(6K zZA3ku;By!o*ykE98?hdBTsN%`abAxGtYeGO1s0)*%cd{=dEfR;nAdsi)p-9avF{ru zu~Cx*Bp?9^NI(J-kbndvAOQ(TKmz|up#SYlH#MFp3O~2MyS~a_^XT&bI9v9})f~mO z>v85POwPjMBh-=1AOOL0u`{=9d2Pu@Gj>#ev+qJj{=d#!+Bq<ob#c&c{}~5*AM0A$ z>Ftq$sdxm7QGsR5BP?WwA;Qc-l-UH6M=;Y=6k--aoUbltqnO!;Vs4!>>gWe~bOfuN z*&KVbcZ@mOJ%c$56C<Ot89rp1ol#nK>iJs>2kf^xImV32q4%6tplnRL#daU^*mFI{ zxSAtv;fRBL7pCue<~V{VW7fs2Z{T_f`!3`$w{hK!JILhBDrQ5XxRdL1FxP3R#AfHU z$vhc@h;wWa^EVAVW7O#(?B!p4sIy+mI(zi!H94V1Z?vVa*AFkQN!VR~VQcM*@`9zG ze{%fAx`e&6huN?r7lPhybOo|GTlj3~*UUQ0hpiv-y-wqm&&g#r3~j(99J+&h#B<^~ z7I3n8_?g`mr|jLWc)Y#0qbGSP^Jy^ItKu=4weuU@zQ$(Bl36j!YUL1CI{4KV2f!)Y ze8fz8Yyyz=?C-Y+^Ya6jfBW<0y|(Rd8M*gJTd*}d$ip;AKmrnwfCMBU0SQQ8JO$iH zwwh5gBU$IWUMG@0&F@F^fXv)7{*CAO)VBmAAOQ(TKmrnwfCN$txRGp(*;q!hPHxtT zWDA%po}oxKwV7HaAOQ(TKmrnwfCSP(z>Q@8W;T|QtaHbW6UlC4X~A4YvgvSzGzJMs zKmrnwfCMBUfz$$Cbpc~oMzZFXYqw7JE7r<ZDw0iYrdA0^KmrnwfCMBUfpie?stXvy zGLkj_kjaf?3jzRdMs(|Bb;nmaTq%t~0uqpb1SB8<2}oeHfLC3>7?zPNi(|b=cH0fW z+GHd<`Ut&}fCMBU0SQPz0uqowItX~x1uTnYB+F&8x?m!(Ns(+iTp^7?0uqpb1SB8< z2}mHdfLC3>vRFp4Tqdgv_+v?JieyupsZ|0JkbndvAOQ(TARPp}>H_{$0wY=H2NT@? zU0?(I6v?K;719_aAOQ(TKmrnwfCN$tc+~|gi)AFs+q{z11vdg+$w*dre5JNis{|w< P0SQPz0uqqGcnbUjXqG|4 diff --git a/taglib/tests/data/silence-44-s.flac b/taglib/tests/data/silence-44-s.flac deleted file mode 100644 index 24e15deb8c85ef82baf22a231901d646397dd8c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50904 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 diff --git a/taglib/tests/data/stripped.xm b/taglib/tests/data/stripped.xm deleted file mode 100644 index 57055f5f192d5858341a8a9235d0f642481d7180..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 602 zcmZQzKm#S2B{``I`DqHp`FZJRa%fypAfFM4Ilv?%0~<pv0|O^Wkplw*Q^P12(IEf; DpT-63 diff --git a/taglib/tests/data/sv4_header.mpc b/taglib/tests/data/sv4_header.mpc deleted file mode 100644 index 214f7ac4eb710e8e21de093ee7959dab8fe86bca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 128 zcmV-`0Du3%Cm;Z)0P+K!E+_X8&%*;!>;D5wsil<Pw|`SHW?4+jVwPoDmSr)-7(xuW zvBWGKXl@{?UfGo!nyhFu>6)pQDvY{}wzBH4T&wTPvrFTA(>cv{&D-_Dah=cBT5|n@ iE3UO<#~#&>*ohqgTB!C%gDl*OOm-ISqH9VS7Q>v%RY5rb diff --git a/taglib/tests/data/sv5_header.mpc b/taglib/tests/data/sv5_header.mpc deleted file mode 100644 index 6d17e65f0f865303397cdb08632cca5a2aa0365a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 128 zcmV-`0Du3%FCYN&0{{RVcBcU78pg2y2S5XsQc5XpYAK~=`TMqG7PBld%R&|wvn-27 z)(~SG+b-oV^~l!Gc|2h@R~)T+MB#OHHdkBzU)gt`zIpg}+1_WT^O~=6<x2Zku3Wju i%9txZJ@=^oqLdzMqz%Mg>6~40@oh*DH|+sQguls;y*_RL diff --git a/taglib/tests/data/sv8_header.mpc b/taglib/tests/data/sv8_header.mpc deleted file mode 100644 index 3405545a29460883251a5ccd6135ae440bca5815..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 114 zcmeYbaP|)N;Crv7*~rn-9LK;a8RX8x=vo_f28=z~0~zHQg8eyM7=XYrfJKH(ED#*R L#wc_k*p(Ro^T!wZ diff --git a/taglib/tests/data/test.it b/taglib/tests/data/test.it deleted file mode 100644 index 379444b91869139a9ca1b73d5b2b9bed98370e9f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 644 zcmebD4e%{VEiO?g&d*C%$V<#kWk3Qf0!%<2D+42gIFkqyCj%Qpg8^G@15|}y3da)# z3V{QK;Q#+GK-ai1GB8X5;wM0C0&+4CFf&}Yi&S_j#sH*WDj9Qv==Zx`3otNv`UV6; z)IdoG28WQ0%wh!~N>nIL%q_@C1qX#5iYhQ?wE{w{1!@yE^E~qua`RJ4fd-{zf{6U0 z+{BV%gkBhnSo4rv1$1OlszPE?X>n=_%osRLta*vW3b~~@C7C&yd8rD?`MJ5Nc_qaZ O_*Vh$0{jeY?gId>FJKJ- diff --git a/taglib/tests/data/test.mod b/taglib/tests/data/test.mod deleted file mode 100644 index 136b6119187bf574bcfdca2c4a4e9155880d553a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3132 zcmeH@u?hk)3_#mI$u2rO9=Pb@KU6O#1)D<C&i=Z&DA?il4km>V@)AN{jrEC;7vM|} z_lXN}EiEBcppcNiZRaMbd?*Ov));39KO{uyJ*Rb%A(FJZn56b8&rQxPaZS0TQ2C%U uO82|1CtRt{Z6%|<6|?aNHvFsq<cRusI$uZJwVP(Z4445kU<S;<SOae~S1CaN diff --git a/taglib/tests/data/test.ogg b/taglib/tests/data/test.ogg deleted file mode 100644 index 220f76f0cef41c7e50736c9134ffb20f0d297961..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4408 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 diff --git a/taglib/tests/data/test.s3m b/taglib/tests/data/test.s3m deleted file mode 100644 index 668250bb7876f31762bb3c2d4a2cafb93cff2f9c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 544 zcmXR(EiO?g&d*C%$V<#kWk3N^0t^gH46F={Kv4x@CWc_=AYTWzS_6SUNXj@EIhnYa zxmkEvdD-~b`Tt`8P6j>(VFn2XStL!km<<iMWI*B$K)hN3NFafbjLc#MAWF<r$jmD) zDJsoP%_{->MGr|8cBTVR7~MSI{FKt1RE4xm5RqS$n^;neT{9L@Z002<l@_O>JB>&q lv6@$`kXxEll9`j4m#UDQp9}JCF=4NQU5m{;1+WZm0sx-yM0EfF diff --git a/taglib/tests/data/test.xm b/taglib/tests/data/test.xm deleted file mode 100644 index b09d91324bb3e6edcdae4f659965e1a87b5e1954..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5471 zcmeH}Jx{|h5QZ-i;$vq*Lb?$N!4F`{(t)89`~lNA$f`do+mT>E^q<2yPHTn$T@XX= z68kLqJowT3+FrawX<OOi(zU&ocNkUF5?zPE*=NXcu~d5f`sl@KEj^BLRGn7<^usCj zTWZJfHZGWNI!jw`0O~ErtO=ZuGwyAOzBkfFw8F?R+M<T5arC#T0ZdXnIFRb`;Oe>_ z+)vv~@$sJXPkjS)Ou&OM8!dmY`%0`-C#=Ft6i<DiQ%mfaQbjdutO-hRMn+YH29R*A zoJkT4sBGa#C)B)g>ENbBR0uVLT6gen%LI)sshQ!z#7@z5**R}S47n&x-ds<8<4Q`? tkyd^iJV|I60z=3SVI{B<SP7W`D}j~3O4t)%JFp%0V&HcI+u{H0@Cp8IS;+tZ diff --git a/taglib/tests/data/unsupported-extension.xxx b/taglib/tests/data/unsupported-extension.xxx deleted file mode 100644 index 65f57c2ee985713476ac0b6e3483e6fe472e2176..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 256 LcmZQz7})>-0RR92 diff --git a/taglib/tests/data/unsynch.id3 b/taglib/tests/data/unsynch.id3 deleted file mode 100644 index cfe6ee1a6f13da6901627a4543f7849dc2d99ed9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 320 zcmeZtF=l3HU|?W02=NRtVqjn}1+xGBXJGJUsAN!JNMc9?;#43ji=mXEn4tv7N(PD* z0mX`e>@<daAX|YUmmxJIz||0_UlOX{k0FyG52#XsAsEQY1**#fs&Vvj0;&;(sxf3R z076xu8ZV&ADu$|%AZKr&JUdk0fWbJ#$JGxg!tVfal@Ws>gBe(t!T;YAco_IU9AokT z$}`9?cnSb1W(H0j5I2rd^#G9ij|`svU-M@HkGx&2`|172;{QKAZewCMWnwU>eR}Y_ dH>%vO**}Anyl%v>9odbd=d!cx(>YD)697C+bpQYW diff --git a/taglib/tests/data/w000.mp3 b/taglib/tests/data/w000.mp3 deleted file mode 100644 index f9c2261764526ff40aba618a1e9b9933acada5fd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 512 zcmdUqQA@)x6ore5`rwm4K<|s750-TE!M*9)BBSeCW@Pvz=}fz@G#PD5?Z5XFd=USE z2R@Q>a&K<3h^EILbb1qJX^PDTNK<)vV{1#9(F5I6-}nAu3@p6AwKcLxwXRV`=ae;M zOL9BaQmM2gtmDzvp%+~{RVXJveLl~}0Vg1sJn}GG{kYrd9gkNb+$H!mI5SISBwz3e z@(Yj{+bdJiyX|-yM@Y^9V-IXL<9QswT!UBHRLate&~^}pN}sr>8$pSbMi`#I%~5m? z*0v~=X*Y~9xGT@o-Cnf578>b(c#>bDK4>}q_ygkWFhSiB2>A1IyyefUko+%w1F}q5 ADgXcg diff --git a/taglib/tests/data/xing.mp3 b/taglib/tests/data/xing.mp3 deleted file mode 100644 index 0c880151b6b60b5f5ac4823a064320710b687449..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8208 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 diff --git a/taglib/tests/data/zero-size-chunk.wav b/taglib/tests/data/zero-size-chunk.wav deleted file mode 100644 index 8517e797dc803bfbcea502588f70d68e643a6aad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1024 zcmWIYbaUfiU|<M$40BD(Em05vvKbke7+lscFbHg9VqjqqU`R<UNdyXyg3%Bd4S``6 F0sw5+2R;A* diff --git a/taglib/tests/main.cpp b/taglib/tests/main.cpp deleted file mode 100644 index ab89dc3..0000000 --- a/taglib/tests/main.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include <stdlib.h> -#include <string.h> -#include <fstream> -#include <stdexcept> -#include <cppunit/TestResult.h> -#include <cppunit/TestResultCollector.h> -#include <cppunit/TestRunner.h> -#include <cppunit/extensions/TestFactoryRegistry.h> -#include <cppunit/BriefTestProgressListener.h> -#include <cppunit/CompilerOutputter.h> -#include <cppunit/XmlOutputter.h> - -int main(int argc, char* argv[]) -{ - std::string testPath = (argc > 1) ? std::string(argv[1]) : ""; - - // Create the event manager and test controller - CppUnit::TestResult controller; - - // Add a listener that colllects test result - CppUnit::TestResultCollector result; - controller.addListener(&result); - - // Add a listener that print dots as test run. - CppUnit::BriefTestProgressListener progress; - controller.addListener(&progress); - - // Add the top suite to the test runner - CppUnit::TestRunner runner; - runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest()); - - try { - std::cout << "Running " << testPath; - runner.run(controller, testPath); - - std::cerr << std::endl; - - // Print test in a compiler compatible format. - CppUnit::CompilerOutputter outputter(&result, std::cerr); - outputter.write(); - - char *xml = ::getenv("CPPUNIT_XML"); - if(xml && !::strcmp(xml, "1")) { - std::ofstream xmlfileout("cpptestresults.xml"); - CppUnit::XmlOutputter xmlout(&result, xmlfileout); - xmlout.write(); - } - } - catch(std::invalid_argument &e){ - std::cerr << std::endl - << "ERROR: " << e.what() - << std::endl; - return 0; - } - - return result.wasSuccessful() ? 0 : 1; -} diff --git a/taglib/tests/test_aiff.cpp b/taglib/tests/test_aiff.cpp deleted file mode 100644 index df1c5ac..0000000 --- a/taglib/tests/test_aiff.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include <cppunit/extensions/HelperMacros.h> -#include <string> -#include <stdio.h> -#include <tag.h> -#include <tbytevectorlist.h> -#include <aifffile.h> -#include "utils.h" - -using namespace std; -using namespace TagLib; - -class TestAIFF : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestAIFF); - CPPUNIT_TEST(testReading); - CPPUNIT_TEST_SUITE_END(); - -public: - - void testReading() - { - ScopedFileCopy copy("empty", ".aiff"); - string filename = copy.fileName(); - - RIFF::AIFF::File *f = new RIFF::AIFF::File(filename.c_str()); - CPPUNIT_ASSERT_EQUAL(705, f->audioProperties()->bitrate()); - } - -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestAIFF); diff --git a/taglib/tests/test_ape.cpp b/taglib/tests/test_ape.cpp deleted file mode 100644 index c95ff0c..0000000 --- a/taglib/tests/test_ape.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include <cppunit/extensions/HelperMacros.h> -#include <string> -#include <stdio.h> -#include <tag.h> -#include <tstringlist.h> -#include <tbytevectorlist.h> -#include <apefile.h> -#include "utils.h" - -using namespace std; -using namespace TagLib; - -class TestAPE : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestAPE); - CPPUNIT_TEST(testProperties399); - CPPUNIT_TEST(testProperties396); - CPPUNIT_TEST(testProperties390); - CPPUNIT_TEST_SUITE_END(); - -public: - - void testProperties399() - { - APE::File f(TEST_FILE_PATH_C("mac-399.ape")); - CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->length()); - CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->bitrate()); - CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); - CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); - } - - void testProperties396() - { - APE::File f(TEST_FILE_PATH_C("mac-396.ape")); - CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->length()); - CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->bitrate()); - CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); - CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); - } - - void testProperties390() - { - APE::File f(TEST_FILE_PATH_C("mac-390-hdr.ape")); - CPPUNIT_ASSERT_EQUAL(15, f.audioProperties()->length()); - CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->bitrate()); - CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); - CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); - } - -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestAPE); diff --git a/taglib/tests/test_apetag.cpp b/taglib/tests/test_apetag.cpp deleted file mode 100644 index 845828f..0000000 --- a/taglib/tests/test_apetag.cpp +++ /dev/null @@ -1,122 +0,0 @@ -#include <string> -#include <stdio.h> -#include <tag.h> -#include <tstringlist.h> -#include <tbytevectorlist.h> -#include <tpropertymap.h> -#include <apetag.h> -#include <tdebug.h> -#include <cppunit/extensions/HelperMacros.h> -#include "utils.h" - -using namespace std; -using namespace TagLib; - -class TestAPETag : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestAPETag); - CPPUNIT_TEST(testIsEmpty); - CPPUNIT_TEST(testIsEmpty2); - CPPUNIT_TEST(testPropertyInterface1); - CPPUNIT_TEST(testPropertyInterface2); - CPPUNIT_TEST(testInvalidKeys); - CPPUNIT_TEST(testTextBinary); - CPPUNIT_TEST_SUITE_END(); - -public: - - void testIsEmpty() - { - APE::Tag tag; - CPPUNIT_ASSERT(tag.isEmpty()); - tag.addValue("COMPOSER", "Mike Oldfield"); - CPPUNIT_ASSERT(!tag.isEmpty()); - } - - void testIsEmpty2() - { - APE::Tag tag; - CPPUNIT_ASSERT(tag.isEmpty()); - tag.setArtist("Mike Oldfield"); - CPPUNIT_ASSERT(!tag.isEmpty()); - } - - void testPropertyInterface1() - { - APE::Tag tag; - PropertyMap dict = tag.properties(); - CPPUNIT_ASSERT(dict.isEmpty()); - dict["ARTIST"] = String("artist 1"); - dict["ARTIST"].append("artist 2"); - dict["TRACKNUMBER"].append("17"); - tag.setProperties(dict); - CPPUNIT_ASSERT_EQUAL(String("17"), tag.itemListMap()["TRACK"].values()[0]); - CPPUNIT_ASSERT_EQUAL(2u, tag.itemListMap()["ARTIST"].values().size()); - CPPUNIT_ASSERT_EQUAL(String("artist 1"), tag.artist()); - CPPUNIT_ASSERT_EQUAL(17u, tag.track()); - } - - void testPropertyInterface2() - { - APE::Tag tag; - APE::Item item1 = APE::Item("TRACK", "17"); - tag.setItem("TRACK", item1); - - APE::Item item2 = APE::Item(); - item2.setType(APE::Item::Binary); - tag.setItem("TESTBINARY", item2); - - PropertyMap properties = tag.properties(); - CPPUNIT_ASSERT_EQUAL(1u, properties.unsupportedData().size()); - CPPUNIT_ASSERT(properties.contains("TRACKNUMBER")); - CPPUNIT_ASSERT(!properties.contains("TRACK")); - CPPUNIT_ASSERT(tag.itemListMap().contains("TESTBINARY")); - - tag.removeUnsupportedProperties(properties.unsupportedData()); - CPPUNIT_ASSERT(!tag.itemListMap().contains("TESTBINARY")); - - APE::Item item3 = APE::Item("TRACKNUMBER", "29"); - tag.setItem("TRACKNUMBER", item3); - properties = tag.properties(); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), properties["TRACKNUMBER"].size()); - CPPUNIT_ASSERT_EQUAL(String("17"), properties["TRACKNUMBER"][0]); - CPPUNIT_ASSERT_EQUAL(String("29"), properties["TRACKNUMBER"][1]); - - } - - void testInvalidKeys() - { - PropertyMap properties; - properties["A"] = String("invalid key: one character"); - properties["MP+"] = String("invalid key: forbidden string"); - properties["A B~C"] = String("valid key: space and tilde"); - properties["ARTIST"] = String("valid key: normal one"); - - APE::Tag tag; - PropertyMap unsuccessful = tag.setProperties(properties); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), unsuccessful.size()); - CPPUNIT_ASSERT(unsuccessful.contains("A")); - CPPUNIT_ASSERT(unsuccessful.contains("MP+")); - } - - void testTextBinary() - { - APE::Item item = APE::Item("DUMMY", "Test Text"); - CPPUNIT_ASSERT_EQUAL(String("Test Text"), item.toString()); - CPPUNIT_ASSERT_EQUAL(ByteVector::null, item.binaryData()); - - ByteVector data("Test Data"); - item.setBinaryData(data); - CPPUNIT_ASSERT(item.values().isEmpty()); - CPPUNIT_ASSERT_EQUAL(String::null, item.toString()); - CPPUNIT_ASSERT_EQUAL(data, item.binaryData()); - - item.setValue("Test Text 2"); - CPPUNIT_ASSERT_EQUAL(String("Test Text 2"), item.toString()); - CPPUNIT_ASSERT_EQUAL(ByteVector::null, item.binaryData()); - } - -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestAPETag); - diff --git a/taglib/tests/test_asf.cpp b/taglib/tests/test_asf.cpp deleted file mode 100644 index 8610c24..0000000 --- a/taglib/tests/test_asf.cpp +++ /dev/null @@ -1,255 +0,0 @@ -#include <string> -#include <stdio.h> -#include <tag.h> -#include <tstringlist.h> -#include <tbytevectorlist.h> -#include <tpropertymap.h> -#include <asffile.h> -#include <cppunit/extensions/HelperMacros.h> -#include "utils.h" - -using namespace std; -using namespace TagLib; - -class TestASF : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestASF); - CPPUNIT_TEST(testAudioProperties); - CPPUNIT_TEST(testRead); - CPPUNIT_TEST(testSaveMultipleValues); - CPPUNIT_TEST(testSaveStream); - CPPUNIT_TEST(testSaveLanguage); - CPPUNIT_TEST(testDWordTrackNumber); - CPPUNIT_TEST(testSaveLargeValue); - CPPUNIT_TEST(testSavePicture); - CPPUNIT_TEST(testSaveMultiplePictures); - CPPUNIT_TEST(testProperties); - CPPUNIT_TEST_SUITE_END(); - -public: - - void testAudioProperties() - { - ASF::File f(TEST_FILE_PATH_C("silence-1.wma")); - CPPUNIT_ASSERT_EQUAL(4, f.audioProperties()->length()); - CPPUNIT_ASSERT_EQUAL(64, f.audioProperties()->bitrate()); - CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); - CPPUNIT_ASSERT_EQUAL(48000, f.audioProperties()->sampleRate()); - } - - void testRead() - { - ASF::File f(TEST_FILE_PATH_C("silence-1.wma")); - CPPUNIT_ASSERT_EQUAL(String("test"), f.tag()->title()); - } - - void testSaveMultipleValues() - { - ScopedFileCopy copy("silence-1", ".wma"); - string newname = copy.fileName(); - - ASF::File *f = new ASF::File(newname.c_str()); - ASF::AttributeList values; - values.append("Foo"); - values.append("Bar"); - f->tag()->attributeListMap()["WM/AlbumTitle"] = values; - f->save(); - delete f; - - f = new ASF::File(newname.c_str()); - CPPUNIT_ASSERT_EQUAL(2, (int)f->tag()->attributeListMap()["WM/AlbumTitle"].size()); - delete f; - } - - void testDWordTrackNumber() - { - ScopedFileCopy copy("silence-1", ".wma"); - string newname = copy.fileName(); - - ASF::File *f = new ASF::File(newname.c_str()); - CPPUNIT_ASSERT(!f->tag()->attributeListMap().contains("WM/TrackNumber")); - f->tag()->setAttribute("WM/TrackNumber", (unsigned int)(123)); - f->save(); - delete f; - - f = new ASF::File(newname.c_str()); - CPPUNIT_ASSERT(f->tag()->attributeListMap().contains("WM/TrackNumber")); - CPPUNIT_ASSERT_EQUAL(ASF::Attribute::DWordType, f->tag()->attributeListMap()["WM/TrackNumber"].front().type()); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(123), f->tag()->track()); - f->tag()->setTrack(234); - f->save(); - delete f; - - f = new ASF::File(newname.c_str()); - CPPUNIT_ASSERT(f->tag()->attributeListMap().contains("WM/TrackNumber")); - CPPUNIT_ASSERT_EQUAL(ASF::Attribute::UnicodeType, f->tag()->attributeListMap()["WM/TrackNumber"].front().type()); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(234), f->tag()->track()); - delete f; - } - - void testSaveStream() - { - ScopedFileCopy copy("silence-1", ".wma"); - string newname = copy.fileName(); - - ASF::File *f = new ASF::File(newname.c_str()); - ASF::AttributeList values; - ASF::Attribute attr("Foo"); - attr.setStream(43); - values.append(attr); - f->tag()->attributeListMap()["WM/AlbumTitle"] = values; - f->save(); - delete f; - - f = new ASF::File(newname.c_str()); - CPPUNIT_ASSERT_EQUAL(43, f->tag()->attributeListMap()["WM/AlbumTitle"][0].stream()); - delete f; - } - - void testSaveLanguage() - { - ScopedFileCopy copy("silence-1", ".wma"); - string newname = copy.fileName(); - - ASF::File *f = new ASF::File(newname.c_str()); - ASF::AttributeList values; - ASF::Attribute attr("Foo"); - attr.setStream(32); - attr.setLanguage(56); - values.append(attr); - f->tag()->attributeListMap()["WM/AlbumTitle"] = values; - f->save(); - delete f; - - f = new ASF::File(newname.c_str()); - CPPUNIT_ASSERT_EQUAL(32, f->tag()->attributeListMap()["WM/AlbumTitle"][0].stream()); - CPPUNIT_ASSERT_EQUAL(56, f->tag()->attributeListMap()["WM/AlbumTitle"][0].language()); - delete f; - } - - void testSaveLargeValue() - { - ScopedFileCopy copy("silence-1", ".wma"); - string newname = copy.fileName(); - - ASF::File *f = new ASF::File(newname.c_str()); - ASF::AttributeList values; - ASF::Attribute attr(ByteVector(70000, 'x')); - values.append(attr); - f->tag()->attributeListMap()["WM/Blob"] = values; - f->save(); - delete f; - - f = new ASF::File(newname.c_str()); - CPPUNIT_ASSERT_EQUAL(ByteVector(70000, 'x'), f->tag()->attributeListMap()["WM/Blob"][0].toByteVector()); - delete f; - } - - void testSavePicture() - { - ScopedFileCopy copy("silence-1", ".wma"); - string newname = copy.fileName(); - - ASF::File *f = new ASF::File(newname.c_str()); - ASF::AttributeList values; - ASF::Picture picture; - picture.setMimeType("image/jpeg"); - picture.setType(ASF::Picture::FrontCover); - picture.setDescription("description"); - picture.setPicture("data"); - ASF::Attribute attr(picture); - values.append(attr); - f->tag()->attributeListMap()["WM/Picture"] = values; - f->save(); - delete f; - - f = new ASF::File(newname.c_str()); - ASF::AttributeList values2 = f->tag()->attributeListMap()["WM/Picture"]; - CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), values2.size()); - ASF::Attribute attr2 = values2.front(); - ASF::Picture picture2 = attr2.toPicture(); - CPPUNIT_ASSERT(picture2.isValid()); - CPPUNIT_ASSERT_EQUAL(String("image/jpeg"), picture2.mimeType()); - CPPUNIT_ASSERT_EQUAL(ASF::Picture::FrontCover, picture2.type()); - CPPUNIT_ASSERT_EQUAL(String("description"), picture2.description()); - CPPUNIT_ASSERT_EQUAL(ByteVector("data"), picture2.picture()); - delete f; - } - - void testSaveMultiplePictures() - { - ScopedFileCopy copy("silence-1", ".wma"); - string newname = copy.fileName(); - - ASF::File *f = new ASF::File(newname.c_str()); - ASF::AttributeList values; - ASF::Picture picture; - picture.setMimeType("image/jpeg"); - picture.setType(ASF::Picture::FrontCover); - picture.setDescription("description"); - picture.setPicture("data"); - values.append(ASF::Attribute(picture)); - ASF::Picture picture2; - picture2.setMimeType("image/png"); - picture2.setType(ASF::Picture::BackCover); - picture2.setDescription("back cover"); - picture2.setPicture("PNG data"); - values.append(ASF::Attribute(picture2)); - f->tag()->attributeListMap()["WM/Picture"] = values; - f->save(); - delete f; - - f = new ASF::File(newname.c_str()); - ASF::AttributeList values2 = f->tag()->attributeListMap()["WM/Picture"]; - CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), values2.size()); - ASF::Picture picture3 = values2[1].toPicture(); - CPPUNIT_ASSERT(picture3.isValid()); - CPPUNIT_ASSERT_EQUAL(String("image/jpeg"), picture3.mimeType()); - CPPUNIT_ASSERT_EQUAL(ASF::Picture::FrontCover, picture3.type()); - CPPUNIT_ASSERT_EQUAL(String("description"), picture3.description()); - CPPUNIT_ASSERT_EQUAL(ByteVector("data"), picture3.picture()); - ASF::Picture picture4 = values2[0].toPicture(); - CPPUNIT_ASSERT(picture4.isValid()); - CPPUNIT_ASSERT_EQUAL(String("image/png"), picture4.mimeType()); - CPPUNIT_ASSERT_EQUAL(ASF::Picture::BackCover, picture4.type()); - CPPUNIT_ASSERT_EQUAL(String("back cover"), picture4.description()); - CPPUNIT_ASSERT_EQUAL(ByteVector("PNG data"), picture4.picture()); - delete f; - } - - void testProperties() - { - ASF::File f(TEST_FILE_PATH_C("silence-1.wma")); - - PropertyMap tags = f.properties(); - - tags["TRACKNUMBER"] = StringList("2"); - tags["DISCNUMBER"] = StringList("3"); - tags["BPM"] = StringList("123"); - tags["ARTIST"] = StringList("Foo Bar"); - f.setProperties(tags); - - tags = f.properties(); - - CPPUNIT_ASSERT_EQUAL(String("Foo Bar"), f.tag()->artist()); - CPPUNIT_ASSERT_EQUAL(StringList("Foo Bar"), tags["ARTIST"]); - - CPPUNIT_ASSERT(f.tag()->attributeListMap().contains("WM/BeatsPerMinute")); - CPPUNIT_ASSERT_EQUAL(1u, f.tag()->attributeListMap()["WM/BeatsPerMinute"].size()); - CPPUNIT_ASSERT_EQUAL(String("123"), f.tag()->attributeListMap()["WM/BeatsPerMinute"].front().toString()); - CPPUNIT_ASSERT_EQUAL(StringList("123"), tags["BPM"]); - - CPPUNIT_ASSERT(f.tag()->attributeListMap().contains("WM/TrackNumber")); - CPPUNIT_ASSERT_EQUAL(1u, f.tag()->attributeListMap()["WM/TrackNumber"].size()); - CPPUNIT_ASSERT_EQUAL(String("2"), f.tag()->attributeListMap()["WM/TrackNumber"].front().toString()); - CPPUNIT_ASSERT_EQUAL(StringList("2"), tags["TRACKNUMBER"]); - - CPPUNIT_ASSERT(f.tag()->attributeListMap().contains("WM/PartOfSet")); - CPPUNIT_ASSERT_EQUAL(1u, f.tag()->attributeListMap()["WM/PartOfSet"].size()); - CPPUNIT_ASSERT_EQUAL(String("3"), f.tag()->attributeListMap()["WM/PartOfSet"].front().toString()); - CPPUNIT_ASSERT_EQUAL(StringList("3"), tags["DISCNUMBER"]); - } - -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestASF); diff --git a/taglib/tests/test_bytevector.cpp b/taglib/tests/test_bytevector.cpp deleted file mode 100644 index 9efd23a..0000000 --- a/taglib/tests/test_bytevector.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/* Copyright (C) 2003 Scott Wheeler <wheeler@kde.org> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <tbytevector.h> -#include <tbytevectorlist.h> -#include <cppunit/extensions/HelperMacros.h> - -using namespace std; -using namespace TagLib; - -class TestByteVector : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestByteVector); - CPPUNIT_TEST(testByteVector); - CPPUNIT_TEST(testFind1); - CPPUNIT_TEST(testFind2); - CPPUNIT_TEST(testRfind1); - CPPUNIT_TEST(testRfind2); - CPPUNIT_TEST(testToHex); - CPPUNIT_TEST(testToUShort); - CPPUNIT_TEST(testReplace); - CPPUNIT_TEST_SUITE_END(); - -public: - - void testConversion(unsigned int i, unsigned char a, unsigned char b, unsigned char c, unsigned char d) - { - ByteVector v(4, 0); - - v[3] = a; - v[2] = b; - v[1] = c; - v[0] = d; - CPPUNIT_ASSERT(v.toUInt(false) == i); - - v[0] = a; - v[1] = b; - v[2] = c; - v[3] = d; - CPPUNIT_ASSERT(v.toUInt() == i); - } - - void testByteVector() - { - ByteVector v("foobar"); - - CPPUNIT_ASSERT(v.find("ob") == 2); - CPPUNIT_ASSERT(v.find('b') == 3); - - ByteVector n(4, 0); - n[0] = 1; - CPPUNIT_ASSERT(n.toUInt(true) == 16777216); - CPPUNIT_ASSERT(n.toUInt(false) == 1); - CPPUNIT_ASSERT(ByteVector::fromUInt(16777216, true) == n); - CPPUNIT_ASSERT(ByteVector::fromUInt(1, false) == n); - - CPPUNIT_ASSERT(ByteVector::fromUInt(0xa0).toUInt() == 0xa0); - - testConversion(0x000000a0, 0x00, 0x00, 0x00, 0xa0); - testConversion(0xd50bf072, 0xd5, 0x0b, 0xf0, 0x72); - - ByteVector intVector(2, 0); - intVector[0] = char(0xfc); - intVector[1] = char(0x00); - CPPUNIT_ASSERT(intVector.toShort() == -1024); - intVector[0] = char(0x04); - intVector[1] = char(0x00); - CPPUNIT_ASSERT(intVector.toShort() == 1024); - - CPPUNIT_ASSERT(ByteVector::fromLongLong(1).toLongLong() == 1); - CPPUNIT_ASSERT(ByteVector::fromLongLong(0).toLongLong() == 0); - CPPUNIT_ASSERT(ByteVector::fromLongLong(0xffffffffffffffffLL).toLongLong() == -1); - CPPUNIT_ASSERT(ByteVector::fromLongLong(0xfffffffffffffffeLL).toLongLong() == -2); - CPPUNIT_ASSERT(ByteVector::fromLongLong(1024).toLongLong() == 1024); - - ByteVector a1("foo"); - a1.append("bar"); - CPPUNIT_ASSERT(a1 == "foobar"); - - ByteVector a2("foo"); - a2.append("b"); - CPPUNIT_ASSERT(a2 == "foob"); - - ByteVector a3; - a3.append("b"); - CPPUNIT_ASSERT(a3 == "b"); - - ByteVector s1("foo"); - CPPUNIT_ASSERT(ByteVectorList::split(s1, " ").size() == 1); - - ByteVector s2("f"); - CPPUNIT_ASSERT(ByteVectorList::split(s2, " ").size() == 1); - - CPPUNIT_ASSERT(ByteVector().size() == 0); - CPPUNIT_ASSERT(ByteVector("asdf").clear().size() == 0); - CPPUNIT_ASSERT(ByteVector("asdf").clear() == ByteVector()); - - ByteVector i("blah blah"); - ByteVector j("blah"); - CPPUNIT_ASSERT(i.containsAt(j, 5, 0)); - CPPUNIT_ASSERT(i.containsAt(j, 6, 1)); - CPPUNIT_ASSERT(i.containsAt(j, 6, 1, 3)); - } - - void testFind1() - { - CPPUNIT_ASSERT_EQUAL(4, ByteVector("....SggO."). find("SggO")); - CPPUNIT_ASSERT_EQUAL(4, ByteVector("....SggO."). find("SggO", 0)); - CPPUNIT_ASSERT_EQUAL(4, ByteVector("....SggO."). find("SggO", 1)); - CPPUNIT_ASSERT_EQUAL(4, ByteVector("....SggO."). find("SggO", 2)); - CPPUNIT_ASSERT_EQUAL(4, ByteVector("....SggO."). find("SggO", 3)); - CPPUNIT_ASSERT_EQUAL(4, ByteVector("....SggO."). find("SggO", 4)); - CPPUNIT_ASSERT_EQUAL(-1, ByteVector("....SggO."). find("SggO", 5)); - CPPUNIT_ASSERT_EQUAL(-1, ByteVector("....SggO."). find("SggO", 6)); - CPPUNIT_ASSERT_EQUAL(-1, ByteVector("....SggO."). find("SggO", 7)); - CPPUNIT_ASSERT_EQUAL(-1, ByteVector("....SggO."). find("SggO", 8)); - } - - void testFind2() - { - CPPUNIT_ASSERT_EQUAL(0, ByteVector("\x01", 1).find("\x01")); - CPPUNIT_ASSERT_EQUAL(0, ByteVector("\x01\x02", 2).find("\x01\x02")); - CPPUNIT_ASSERT_EQUAL(-1, ByteVector("\x01", 1).find("\x02")); - CPPUNIT_ASSERT_EQUAL(-1, ByteVector("\x01\x02", 2).find("\x01\x03")); - } - - void testRfind1() - { - CPPUNIT_ASSERT_EQUAL(1, ByteVector(".OggS....").rfind("OggS", 0)); - CPPUNIT_ASSERT_EQUAL(1, ByteVector(".OggS....").rfind("OggS", 1)); - CPPUNIT_ASSERT_EQUAL(1, ByteVector(".OggS....").rfind("OggS", 2)); - CPPUNIT_ASSERT_EQUAL(1, ByteVector(".OggS....").rfind("OggS", 3)); - CPPUNIT_ASSERT_EQUAL(1, ByteVector(".OggS....").rfind("OggS", 4)); - CPPUNIT_ASSERT_EQUAL(1, ByteVector(".OggS....").rfind("OggS", 5)); - CPPUNIT_ASSERT_EQUAL(1, ByteVector(".OggS....").rfind("OggS", 6)); - CPPUNIT_ASSERT_EQUAL(1, ByteVector(".OggS....").rfind("OggS", 7)); - CPPUNIT_ASSERT_EQUAL(1, ByteVector(".OggS....").rfind("OggS", 8)); - CPPUNIT_ASSERT_EQUAL(1, ByteVector(".OggS....").rfind("OggS")); - } - - void testRfind2() - { - ByteVector r0("**************"); - ByteVector r1("OggS**********"); - ByteVector r2("**********OggS"); - ByteVector r3("OggS******OggS"); - ByteVector r4("OggS*OggS*OggS"); - - CPPUNIT_ASSERT_EQUAL(-1, r0.find("OggS")); - CPPUNIT_ASSERT_EQUAL(-1, r0.rfind("OggS")); - CPPUNIT_ASSERT_EQUAL(0, r1.find("OggS")); - CPPUNIT_ASSERT_EQUAL(0, r1.rfind("OggS")); - CPPUNIT_ASSERT_EQUAL(10, r2.find("OggS")); - CPPUNIT_ASSERT_EQUAL(10, r2.rfind("OggS")); - CPPUNIT_ASSERT_EQUAL(0, r3.find("OggS")); - CPPUNIT_ASSERT_EQUAL(10, r3.rfind("OggS")); - CPPUNIT_ASSERT_EQUAL(10, r4.rfind("OggS")); - CPPUNIT_ASSERT_EQUAL(10, r4.rfind("OggS", 0)); - CPPUNIT_ASSERT_EQUAL(5, r4.rfind("OggS", 7)); - CPPUNIT_ASSERT_EQUAL(10, r4.rfind("OggS", 12)); - } - - void testToHex() - { - ByteVector v("\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87\x78\x69\x5a\x4b\x3c\x2d\x1e\x0f", 16); - - CPPUNIT_ASSERT_EQUAL(ByteVector("f0e1d2c3b4a5968778695a4b3c2d1e0f"), v.toHex()); - } - - void testToUShort() - { - CPPUNIT_ASSERT_EQUAL((unsigned short)0xFFFF, ByteVector("\xff\xff", 2).toUShort()); - CPPUNIT_ASSERT_EQUAL((unsigned short)0x0001, ByteVector("\x00\x01", 2).toUShort()); - CPPUNIT_ASSERT_EQUAL((unsigned short)0x0100, ByteVector("\x00\x01", 2).toUShort(false)); - CPPUNIT_ASSERT_EQUAL((unsigned short)0xFF01, ByteVector("\xFF\x01", 2).toUShort()); - CPPUNIT_ASSERT_EQUAL((unsigned short)0x01FF, ByteVector("\xFF\x01", 2).toUShort(false)); - } - - void testReplace() - { - { - ByteVector a("abcdabf"); - a.replace(ByteVector(""), ByteVector("<a>")); - CPPUNIT_ASSERT_EQUAL(ByteVector("abcdabf"), a); - } - { - ByteVector a("abcdabf"); - a.replace(ByteVector("foobartoolong"), ByteVector("<a>")); - CPPUNIT_ASSERT_EQUAL(ByteVector("abcdabf"), a); - } - { - ByteVector a("abcdabf"); - a.replace(ByteVector("xx"), ByteVector("yy")); - CPPUNIT_ASSERT_EQUAL(ByteVector("abcdabf"), a); - } - { - ByteVector a("abcdabf"); - a.replace(ByteVector("a"), ByteVector("x")); - CPPUNIT_ASSERT_EQUAL(ByteVector("xbcdxbf"), a); - } - { - ByteVector a("abcdabf"); - a.replace(ByteVector("ab"), ByteVector("xy")); - CPPUNIT_ASSERT_EQUAL(ByteVector("xycdxyf"), a); - } - { - ByteVector a("abcdabf"); - a.replace(ByteVector("a"), ByteVector("<a>")); - CPPUNIT_ASSERT_EQUAL(ByteVector("<a>bcd<a>bf"), a); - } - { - ByteVector a("abcdabf"); - a.replace(ByteVector("ab"), ByteVector("x")); - CPPUNIT_ASSERT_EQUAL(ByteVector("xcdxf"), a); - } - { - ByteVector a("abcdabf"); - a.replace(ByteVector("ab"), ByteVector()); - CPPUNIT_ASSERT_EQUAL(ByteVector("cdf"), a); - } - } - -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestByteVector); diff --git a/taglib/tests/test_bytevectorlist.cpp b/taglib/tests/test_bytevectorlist.cpp deleted file mode 100644 index 7e4a9fd..0000000 --- a/taglib/tests/test_bytevectorlist.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include <tbytevector.h> -#include <tbytevectorlist.h> -#include <cppunit/extensions/HelperMacros.h> - -using namespace std; -using namespace TagLib; - -class TestByteVectorList : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestByteVectorList); - CPPUNIT_TEST(testSplitSingleChar); - CPPUNIT_TEST(testSplitSingleChar_2); - CPPUNIT_TEST_SUITE_END(); - -public: - - void testSplitSingleChar() - { - ByteVector v("a b"); - - ByteVectorList l = ByteVectorList::split(v, " "); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), l.size()); - CPPUNIT_ASSERT_EQUAL(ByteVector("a"), l[0]); - CPPUNIT_ASSERT_EQUAL(ByteVector("b"), l[1]); - } - - void testSplitSingleChar_2() - { - ByteVector v("a"); - - ByteVectorList l = ByteVectorList::split(v, " "); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), l.size()); - CPPUNIT_ASSERT_EQUAL(ByteVector("a"), l[0]); - } - -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestByteVectorList); diff --git a/taglib/tests/test_bytevectorstream.cpp b/taglib/tests/test_bytevectorstream.cpp deleted file mode 100644 index b0fec90..0000000 --- a/taglib/tests/test_bytevectorstream.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include <tbytevectorstream.h> -#include <cppunit/extensions/HelperMacros.h> - -using namespace std; -using namespace TagLib; - -class TestByteVectorStream : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestByteVectorStream); - CPPUNIT_TEST(testInitialData); - CPPUNIT_TEST(testWriteBlock); - CPPUNIT_TEST(testWriteBlockResize); - CPPUNIT_TEST(testReadBlock); - CPPUNIT_TEST(testRemoveBlock); - CPPUNIT_TEST(testInsert); - CPPUNIT_TEST_SUITE_END(); - -public: - - void testInitialData() - { - ByteVector v("abcd"); - ByteVectorStream stream(v); - - CPPUNIT_ASSERT_EQUAL(ByteVector("abcd"), *stream.data()); - } - - void testWriteBlock() - { - ByteVector v("abcd"); - ByteVectorStream stream(v); - - stream.seek(1); - stream.writeBlock(ByteVector("xx")); - CPPUNIT_ASSERT_EQUAL(ByteVector("axxd"), *stream.data()); - } - - void testWriteBlockResize() - { - ByteVector v("abcd"); - ByteVectorStream stream(v); - - stream.seek(3); - stream.writeBlock(ByteVector("xx")); - CPPUNIT_ASSERT_EQUAL(ByteVector("abcxx"), *stream.data()); - stream.seek(5); - stream.writeBlock(ByteVector("yy")); - CPPUNIT_ASSERT_EQUAL(ByteVector("abcxxyy"), *stream.data()); - } - - void testReadBlock() - { - ByteVector v("abcd"); - ByteVectorStream stream(v); - - CPPUNIT_ASSERT_EQUAL(ByteVector("a"), stream.readBlock(1)); - CPPUNIT_ASSERT_EQUAL(ByteVector("bc"), stream.readBlock(2)); - CPPUNIT_ASSERT_EQUAL(ByteVector("d"), stream.readBlock(3)); - CPPUNIT_ASSERT_EQUAL(ByteVector::null, stream.readBlock(3)); - } - - void testRemoveBlock() - { - ByteVector v("abcd"); - ByteVectorStream stream(v); - - stream.removeBlock(1, 1); - CPPUNIT_ASSERT_EQUAL(ByteVector("acd"), *stream.data()); - stream.removeBlock(0, 2); - CPPUNIT_ASSERT_EQUAL(ByteVector("d"), *stream.data()); - stream.removeBlock(0, 2); - CPPUNIT_ASSERT_EQUAL(ByteVector(""), *stream.data()); - } - - void testInsert() - { - ByteVector v("abcd"); - ByteVectorStream stream(v); - - stream.insert(ByteVector("xx"), 1, 1); - CPPUNIT_ASSERT_EQUAL(ByteVector("axxcd"), *stream.data()); - stream.insert(ByteVector("yy"), 0, 2); - CPPUNIT_ASSERT_EQUAL(ByteVector("yyxcd"), *stream.data()); - stream.insert(ByteVector("foa"), 3, 2); - CPPUNIT_ASSERT_EQUAL(ByteVector("yyxfoa"), *stream.data()); - stream.insert(ByteVector("123"), 3, 0); - CPPUNIT_ASSERT_EQUAL(ByteVector("yyx123foa"), *stream.data()); - } - -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestByteVectorStream); diff --git a/taglib/tests/test_fileref.cpp b/taglib/tests/test_fileref.cpp deleted file mode 100644 index 197a921..0000000 --- a/taglib/tests/test_fileref.cpp +++ /dev/null @@ -1,163 +0,0 @@ -#include <string> -#include <stdio.h> -#include <tag.h> -#include <fileref.h> -#include <oggflacfile.h> -#include <vorbisfile.h> -#include <cppunit/extensions/HelperMacros.h> -#include "utils.h" - -using namespace std; -using namespace TagLib; - -class TestFileRef : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestFileRef); - CPPUNIT_TEST(testASF); - CPPUNIT_TEST(testMusepack); - CPPUNIT_TEST(testVorbis); - CPPUNIT_TEST(testSpeex); - CPPUNIT_TEST(testFLAC); - CPPUNIT_TEST(testMP3); - CPPUNIT_TEST(testOGA_FLAC); - CPPUNIT_TEST(testOGA_Vorbis); - CPPUNIT_TEST(testMP4_1); - CPPUNIT_TEST(testMP4_2); - CPPUNIT_TEST(testMP4_3); - CPPUNIT_TEST(testTrueAudio); - CPPUNIT_TEST(testAPE); - CPPUNIT_TEST(testWav); - CPPUNIT_TEST(testUnsupported); - CPPUNIT_TEST_SUITE_END(); - -public: - - void fileRefSave(const string &filename, const string &ext) - { - ScopedFileCopy copy(filename, ext); - string newname = copy.fileName(); - - FileRef *f = new FileRef(newname.c_str()); - CPPUNIT_ASSERT(!f->isNull()); - f->tag()->setArtist("test artist"); - f->tag()->setTitle("test title"); - f->tag()->setGenre("Test!"); - f->tag()->setAlbum("albummmm"); - f->tag()->setTrack(5); - f->tag()->setYear(2020); - f->save(); - delete f; - - f = new FileRef(newname.c_str()); - CPPUNIT_ASSERT(!f->isNull()); - CPPUNIT_ASSERT_EQUAL(f->tag()->artist(), String("test artist")); - CPPUNIT_ASSERT_EQUAL(f->tag()->title(), String("test title")); - CPPUNIT_ASSERT_EQUAL(f->tag()->genre(), String("Test!")); - CPPUNIT_ASSERT_EQUAL(f->tag()->album(), String("albummmm")); - CPPUNIT_ASSERT_EQUAL(f->tag()->track(), TagLib::uint(5)); - CPPUNIT_ASSERT_EQUAL(f->tag()->year(), TagLib::uint(2020)); - f->tag()->setArtist("ttest artist"); - f->tag()->setTitle("ytest title"); - f->tag()->setGenre("uTest!"); - f->tag()->setAlbum("ialbummmm"); - f->tag()->setTrack(7); - f->tag()->setYear(2080); - f->save(); - delete f; - - f = new FileRef(newname.c_str()); - CPPUNIT_ASSERT(!f->isNull()); - CPPUNIT_ASSERT_EQUAL(f->tag()->artist(), String("ttest artist")); - CPPUNIT_ASSERT_EQUAL(f->tag()->title(), String("ytest title")); - CPPUNIT_ASSERT_EQUAL(f->tag()->genre(), String("uTest!")); - CPPUNIT_ASSERT_EQUAL(f->tag()->album(), String("ialbummmm")); - CPPUNIT_ASSERT_EQUAL(f->tag()->track(), TagLib::uint(7)); - CPPUNIT_ASSERT_EQUAL(f->tag()->year(), TagLib::uint(2080)); - delete f; - } - - void testMusepack() - { - fileRefSave("click", ".mpc"); - } - - void testASF() - { - fileRefSave("silence-1", ".wma"); - } - - void testVorbis() - { - fileRefSave("empty", ".ogg"); - } - - void testSpeex() - { - fileRefSave("empty", ".spx"); - } - - void testFLAC() - { - fileRefSave("no-tags", ".flac"); - } - - void testMP3() - { - fileRefSave("xing", ".mp3"); - } - - void testTrueAudio() - { - fileRefSave("empty", ".tta"); - } - - void testMP4_1() - { - fileRefSave("has-tags", ".m4a"); - } - - void testMP4_2() - { - fileRefSave("no-tags", ".m4a"); - } - - void testMP4_3() - { - fileRefSave("no-tags", ".3g2"); - } - - void testWav() - { - fileRefSave("empty", ".wav"); - } - - void testOGA_FLAC() - { - FileRef *f = new FileRef(TEST_FILE_PATH_C("empty_flac.oga")); - CPPUNIT_ASSERT(dynamic_cast<Ogg::Vorbis::File *>(f->file()) == NULL); - CPPUNIT_ASSERT(dynamic_cast<Ogg::FLAC::File *>(f->file()) != NULL); - } - - void testOGA_Vorbis() - { - FileRef *f = new FileRef(TEST_FILE_PATH_C("empty_vorbis.oga")); - CPPUNIT_ASSERT(dynamic_cast<Ogg::Vorbis::File *>(f->file()) != NULL); - CPPUNIT_ASSERT(dynamic_cast<Ogg::FLAC::File *>(f->file()) == NULL); - } - - void testAPE() - { - fileRefSave("mac-399", ".ape"); - } - - void testUnsupported() - { - FileRef f1(TEST_FILE_PATH_C("no-extension")); - CPPUNIT_ASSERT(f1.isNull()); - - FileRef f2(TEST_FILE_PATH_C("unsupported-extension.xxx")); - CPPUNIT_ASSERT(f2.isNull()); - } -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestFileRef); diff --git a/taglib/tests/test_flac.cpp b/taglib/tests/test_flac.cpp deleted file mode 100644 index caec715..0000000 --- a/taglib/tests/test_flac.cpp +++ /dev/null @@ -1,248 +0,0 @@ -#include <string> -#include <stdio.h> -#include <tag.h> -#include <tstringlist.h> -#include <tbytevectorlist.h> -#include <tpropertymap.h> -#include <flacfile.h> -#include <xiphcomment.h> -#include <cppunit/extensions/HelperMacros.h> -#include "utils.h" - -using namespace std; -using namespace TagLib; - -class TestFLAC : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestFLAC); - CPPUNIT_TEST(testSignature); - CPPUNIT_TEST(testMultipleCommentBlocks); - CPPUNIT_TEST(testReadPicture); - CPPUNIT_TEST(testAddPicture); - CPPUNIT_TEST(testReplacePicture); - CPPUNIT_TEST(testRemoveAllPictures); - CPPUNIT_TEST(testRepeatedSave); - CPPUNIT_TEST(testSaveMultipleValues); - CPPUNIT_TEST(testDict); - CPPUNIT_TEST(testInvalid); - CPPUNIT_TEST_SUITE_END(); - -public: - - void testSignature() - { - FLAC::File f(TEST_FILE_PATH_C("no-tags.flac")); - CPPUNIT_ASSERT_EQUAL(ByteVector("a1b141f766e9849ac3db1030a20a3c77"), f.audioProperties()->signature().toHex()); - } - - void testMultipleCommentBlocks() - { - ScopedFileCopy copy("multiple-vc", ".flac"); - string newname = copy.fileName(); - - FLAC::File *f = new FLAC::File(newname.c_str()); - CPPUNIT_ASSERT_EQUAL(String("Artist 1"), f->tag()->artist()); - f->tag()->setArtist("The Artist"); - f->save(); - delete f; - - f = new FLAC::File(newname.c_str()); - CPPUNIT_ASSERT_EQUAL(String("The Artist"), f->tag()->artist()); - delete f; - } - - void testReadPicture() - { - ScopedFileCopy copy("silence-44-s", ".flac"); - string newname = copy.fileName(); - - FLAC::File *f = new FLAC::File(newname.c_str()); - List<FLAC::Picture *> lst = f->pictureList(); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), lst.size()); - - FLAC::Picture *pic = lst.front(); - CPPUNIT_ASSERT_EQUAL(FLAC::Picture::FrontCover, pic->type()); - CPPUNIT_ASSERT_EQUAL(1, pic->width()); - CPPUNIT_ASSERT_EQUAL(1, pic->height()); - CPPUNIT_ASSERT_EQUAL(24, pic->colorDepth()); - CPPUNIT_ASSERT_EQUAL(0, pic->numColors()); - CPPUNIT_ASSERT_EQUAL(String("image/png"), pic->mimeType()); - CPPUNIT_ASSERT_EQUAL(String("A pixel."), pic->description()); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(150), pic->data().size()); - } - - void testAddPicture() - { - ScopedFileCopy copy("silence-44-s", ".flac"); - string newname = copy.fileName(); - - FLAC::File *f = new FLAC::File(newname.c_str()); - List<FLAC::Picture *> lst = f->pictureList(); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), lst.size()); - - FLAC::Picture *newpic = new FLAC::Picture(); - newpic->setType(FLAC::Picture::BackCover); - newpic->setWidth(5); - newpic->setHeight(6); - newpic->setColorDepth(16); - newpic->setNumColors(7); - newpic->setMimeType("image/jpeg"); - newpic->setDescription("new image"); - newpic->setData("JPEG data"); - f->addPicture(newpic); - f->save(); - - f = new FLAC::File(newname.c_str()); - lst = f->pictureList(); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), lst.size()); - - FLAC::Picture *pic = lst[0]; - CPPUNIT_ASSERT_EQUAL(FLAC::Picture::FrontCover, pic->type()); - CPPUNIT_ASSERT_EQUAL(1, pic->width()); - CPPUNIT_ASSERT_EQUAL(1, pic->height()); - CPPUNIT_ASSERT_EQUAL(24, pic->colorDepth()); - CPPUNIT_ASSERT_EQUAL(0, pic->numColors()); - CPPUNIT_ASSERT_EQUAL(String("image/png"), pic->mimeType()); - CPPUNIT_ASSERT_EQUAL(String("A pixel."), pic->description()); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(150), pic->data().size()); - - pic = lst[1]; - CPPUNIT_ASSERT_EQUAL(FLAC::Picture::BackCover, pic->type()); - CPPUNIT_ASSERT_EQUAL(5, pic->width()); - CPPUNIT_ASSERT_EQUAL(6, pic->height()); - CPPUNIT_ASSERT_EQUAL(16, pic->colorDepth()); - CPPUNIT_ASSERT_EQUAL(7, pic->numColors()); - CPPUNIT_ASSERT_EQUAL(String("image/jpeg"), pic->mimeType()); - CPPUNIT_ASSERT_EQUAL(String("new image"), pic->description()); - CPPUNIT_ASSERT_EQUAL(ByteVector("JPEG data"), pic->data()); - } - - void testReplacePicture() - { - ScopedFileCopy copy("silence-44-s", ".flac"); - string newname = copy.fileName(); - - FLAC::File *f = new FLAC::File(newname.c_str()); - List<FLAC::Picture *> lst = f->pictureList(); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), lst.size()); - - FLAC::Picture *newpic = new FLAC::Picture(); - newpic->setType(FLAC::Picture::BackCover); - newpic->setWidth(5); - newpic->setHeight(6); - newpic->setColorDepth(16); - newpic->setNumColors(7); - newpic->setMimeType("image/jpeg"); - newpic->setDescription("new image"); - newpic->setData("JPEG data"); - f->removePictures(); - f->addPicture(newpic); - f->save(); - - f = new FLAC::File(newname.c_str()); - lst = f->pictureList(); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), lst.size()); - - FLAC::Picture *pic = lst[0]; - CPPUNIT_ASSERT_EQUAL(FLAC::Picture::BackCover, pic->type()); - CPPUNIT_ASSERT_EQUAL(5, pic->width()); - CPPUNIT_ASSERT_EQUAL(6, pic->height()); - CPPUNIT_ASSERT_EQUAL(16, pic->colorDepth()); - CPPUNIT_ASSERT_EQUAL(7, pic->numColors()); - CPPUNIT_ASSERT_EQUAL(String("image/jpeg"), pic->mimeType()); - CPPUNIT_ASSERT_EQUAL(String("new image"), pic->description()); - CPPUNIT_ASSERT_EQUAL(ByteVector("JPEG data"), pic->data()); - } - - void testRemoveAllPictures() - { - ScopedFileCopy copy("silence-44-s", ".flac"); - string newname = copy.fileName(); - - FLAC::File *f = new FLAC::File(newname.c_str()); - List<FLAC::Picture *> lst = f->pictureList(); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), lst.size()); - - f->removePictures(); - f->save(); - - f = new FLAC::File(newname.c_str()); - lst = f->pictureList(); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(0), lst.size()); - } - - void testRepeatedSave() - { - ScopedFileCopy copy("silence-44-s", ".flac"); - string newname = copy.fileName(); - - FLAC::File *f = new FLAC::File(newname.c_str()); - Tag *tag = f->tag(); - CPPUNIT_ASSERT_EQUAL(String("Silence"), tag->title()); - tag->setTitle("NEW TITLE"); - f->save(); - CPPUNIT_ASSERT_EQUAL(String("NEW TITLE"), tag->title()); - tag->setTitle("NEW TITLE 2"); - f->save(); - CPPUNIT_ASSERT_EQUAL(String("NEW TITLE 2"), tag->title()); - - f = new FLAC::File(newname.c_str()); - tag = f->tag(); - CPPUNIT_ASSERT_EQUAL(String("NEW TITLE 2"), tag->title()); - } - - void testSaveMultipleValues() - { - ScopedFileCopy copy("silence-44-s", ".flac"); - string newname = copy.fileName(); - - FLAC::File *f = new FLAC::File(newname.c_str()); - Ogg::XiphComment* c = f->xiphComment(true); - c->addField("ARTIST", "artist 1", true); - c->addField("ARTIST", "artist 2", false); - f->save(); - delete f; - - f = new FLAC::File(newname.c_str()); - c = f->xiphComment(true); - Ogg::FieldListMap m = c->fieldListMap(); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), m["ARTIST"].size()); - CPPUNIT_ASSERT_EQUAL(String("artist 1"), m["ARTIST"][0]); - CPPUNIT_ASSERT_EQUAL(String("artist 2"), m["ARTIST"][1]); - } - - void testDict() - { - // test unicode & multiple values with dict interface - ScopedFileCopy copy("silence-44-s", ".flac"); - string newname = copy.fileName(); - - FLAC::File *f = new FLAC::File(newname.c_str()); - PropertyMap dict; - dict["ARTIST"].append("artøst 1"); - dict["ARTIST"].append("artöst 2"); - f->setProperties(dict); - f->save(); - delete f; - - f = new FLAC::File(newname.c_str()); - dict = f->properties(); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), dict["ARTIST"].size()); - CPPUNIT_ASSERT_EQUAL(String("artøst 1"), dict["ARTIST"][0]); - CPPUNIT_ASSERT_EQUAL(String("artöst 2"), dict["ARTIST"][1]); - } - - void testInvalid() - { - ScopedFileCopy copy("silence-44-s", ".flac"); - PropertyMap map; - map["HÄÖ"] = String("bla"); - FLAC::File f(copy.fileName().c_str()); - PropertyMap invalid = f.setProperties(map); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), invalid.size()); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(0), f.properties().size()); - } - -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestFLAC); diff --git a/taglib/tests/test_flacpicture.cpp b/taglib/tests/test_flacpicture.cpp deleted file mode 100644 index eefa930..0000000 --- a/taglib/tests/test_flacpicture.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include <string> -#include <stdio.h> -#include <tag.h> -#include <tstringlist.h> -#include <tbytevectorlist.h> -#include <flacfile.h> -#include <flacmetadatablock.h> -#include <cppunit/extensions/HelperMacros.h> -#include "utils.h" - -using namespace std; -using namespace TagLib; - -class TestFLACPicture : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestFLACPicture); - CPPUNIT_TEST(testParse); - CPPUNIT_TEST(testPassThrough); - CPPUNIT_TEST_SUITE_END(); - -public: - - void testParse() - { - const unsigned char data[] = { 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x09, 0x69, 0x6D, 0x61, 0x67, 0x65, 0x2F, 0x70, 0x6E, 0x67, 0x00, 0x00, 0x00, 0x08, 0x41, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6C, 0x2E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x77, 0x53, 0xDE, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0B, 0x13, 0x00, 0x00, 0x0B, 0x13, 0x01, 0x00, 0x9A, 0x9C, 0x18, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4D, 0x45, 0x07, 0xD6, 0x0B, 0x1C, 0x0A, 0x36, 0x06, 0x08, 0x44, 0x3D, 0x32, 0x00, 0x00, 0x00, 0x1D, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6F, 0x6D, 0x6D, 0x65, 0x6E, 0x74, 0x00, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x54, 0x68, 0x65, 0x20, 0x47, 0x49, 0x4D, 0x50, 0xEF, 0x64, 0x25, 0x6E, 0x00, 0x00, 0x00, 0x0C, 0x49, 0x44, 0x41, 0x54, 0x08, 0xD7, 0x63, 0xF8, 0xFF, 0xFF, 0x3F, 0x00, 0x05, 0xFE, 0x02, 0xFE, 0xDC, 0xCC, 0x59, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 }; - const char *pdata = reinterpret_cast<const char*>(data); - - FLAC::Picture pic(ByteVector(pdata, 199)); - - CPPUNIT_ASSERT_EQUAL(3, int(pic.type())); - CPPUNIT_ASSERT_EQUAL(1, pic.width()); - CPPUNIT_ASSERT_EQUAL(1, pic.height()); - CPPUNIT_ASSERT_EQUAL(24, pic.colorDepth()); - CPPUNIT_ASSERT_EQUAL(0, pic.numColors()); - CPPUNIT_ASSERT_EQUAL(String("image/png"), pic.mimeType()); - CPPUNIT_ASSERT_EQUAL(String("A pixel."), pic.description()); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(150), pic.data().size()); - } - - void testPassThrough() - { - const unsigned char data[] = { 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x09, 0x69, 0x6D, 0x61, 0x67, 0x65, 0x2F, 0x70, 0x6E, 0x67, 0x00, 0x00, 0x00, 0x08, 0x41, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6C, 0x2E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x00, 0x00, 0x00, 0x90, 0x77, 0x53, 0xDE, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0B, 0x13, 0x00, 0x00, 0x0B, 0x13, 0x01, 0x00, 0x9A, 0x9C, 0x18, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49, 0x4D, 0x45, 0x07, 0xD6, 0x0B, 0x1C, 0x0A, 0x36, 0x06, 0x08, 0x44, 0x3D, 0x32, 0x00, 0x00, 0x00, 0x1D, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6F, 0x6D, 0x6D, 0x65, 0x6E, 0x74, 0x00, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x54, 0x68, 0x65, 0x20, 0x47, 0x49, 0x4D, 0x50, 0xEF, 0x64, 0x25, 0x6E, 0x00, 0x00, 0x00, 0x0C, 0x49, 0x44, 0x41, 0x54, 0x08, 0xD7, 0x63, 0xF8, 0xFF, 0xFF, 0x3F, 0x00, 0x05, 0xFE, 0x02, 0xFE, 0xDC, 0xCC, 0x59, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 }; - const char *pdata = reinterpret_cast<const char*>(data); - - FLAC::Picture pic(ByteVector(pdata, 199)); - CPPUNIT_ASSERT_EQUAL(ByteVector(pdata, 199), pic.render()); - } - -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestFLACPicture); - diff --git a/taglib/tests/test_flacunknownmetadatablock.cpp b/taglib/tests/test_flacunknownmetadatablock.cpp deleted file mode 100644 index 881078d..0000000 --- a/taglib/tests/test_flacunknownmetadatablock.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include <string> -#include <stdio.h> -#include <tag.h> -#include <tstringlist.h> -#include <tbytevectorlist.h> -#include <flacunknownmetadatablock.h> -#include <cppunit/extensions/HelperMacros.h> -#include "utils.h" - -using namespace std; -using namespace TagLib; - -class TestFLACUnknownMetadataBlock : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestFLACUnknownMetadataBlock); - CPPUNIT_TEST(testAccessors); - CPPUNIT_TEST_SUITE_END(); - -public: - - void testAccessors() - { - ByteVector data("abc\x01", 4); - FLAC::UnknownMetadataBlock block(42, data); - CPPUNIT_ASSERT_EQUAL(42, block.code()); - CPPUNIT_ASSERT_EQUAL(data, block.data()); - CPPUNIT_ASSERT_EQUAL(data, block.render()); - ByteVector data2("xxx", 3); - block.setCode(13); - block.setData(data2); - CPPUNIT_ASSERT_EQUAL(13, block.code()); - CPPUNIT_ASSERT_EQUAL(data2, block.data()); - CPPUNIT_ASSERT_EQUAL(data2, block.render()); - } - -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestFLACUnknownMetadataBlock); diff --git a/taglib/tests/test_id3v1.cpp b/taglib/tests/test_id3v1.cpp deleted file mode 100644 index 7db2dbb..0000000 --- a/taglib/tests/test_id3v1.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include <string> -#include <stdio.h> -#include <tstring.h> -#include <mpegfile.h> -#include <id3v1tag.h> -#include <cppunit/extensions/HelperMacros.h> -#include "utils.h" - -using namespace std; -using namespace TagLib; - -class TestID3v1 : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestID3v1); - CPPUNIT_TEST(testStripWhiteSpace); - CPPUNIT_TEST_SUITE_END(); - -public: - - void testStripWhiteSpace() - { - ScopedFileCopy copy("xing", ".mp3"); - string newname = copy.fileName(); - - { - MPEG::File f(newname.c_str()); - f.ID3v1Tag(true)->setArtist("Artist "); - f.save(); - } - - { - MPEG::File f(newname.c_str()); - CPPUNIT_ASSERT(f.ID3v1Tag(false)); - CPPUNIT_ASSERT_EQUAL(String("Artist"), f.ID3v1Tag(false)->artist()); - } - } - -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestID3v1); diff --git a/taglib/tests/test_id3v2.cpp b/taglib/tests/test_id3v2.cpp deleted file mode 100644 index 9f5ffe0..0000000 --- a/taglib/tests/test_id3v2.cpp +++ /dev/null @@ -1,758 +0,0 @@ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <string> -#include <stdio.h> -// so evil :( -#define protected public -#include <id3v2tag.h> -#include <mpegfile.h> -#include <id3v2frame.h> -#undef protected -#include <uniquefileidentifierframe.h> -#include <textidentificationframe.h> -#include <attachedpictureframe.h> -#include <unsynchronizedlyricsframe.h> -#include <generalencapsulatedobjectframe.h> -#include <relativevolumeframe.h> -#include <popularimeterframe.h> -#include <urllinkframe.h> -#include <ownershipframe.h> -#include <unknownframe.h> -#include <tdebug.h> -#include <tpropertymap.h> -#include <cppunit/extensions/HelperMacros.h> -#include "utils.h" - -using namespace std; -using namespace TagLib; - -class PublicFrame : public ID3v2::Frame -{ - public: - PublicFrame() : ID3v2::Frame(ByteVector("XXXX\0\0\0\0\0\0", 10)) {} - String readStringField(const ByteVector &data, String::Type encoding, - int *positon = 0) - { return ID3v2::Frame::readStringField(data, encoding, positon); } - virtual String toString() const { return String::null; } - virtual void parseFields(const ByteVector &) {} - virtual ByteVector renderFields() const { return ByteVector::null; } -}; - -class TestID3v2 : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestID3v2); - CPPUNIT_TEST(testUnsynchDecode); - CPPUNIT_TEST(testDowngradeUTF8ForID3v23); - CPPUNIT_TEST(testUTF16BEDelimiter); - CPPUNIT_TEST(testUTF16Delimiter); - CPPUNIT_TEST(testReadStringField); - CPPUNIT_TEST(testParseAPIC); - CPPUNIT_TEST(testParseAPIC_UTF16_BOM); - CPPUNIT_TEST(testParseAPICv22); - CPPUNIT_TEST(testDontRender22); - CPPUNIT_TEST(testParseGEOB); - CPPUNIT_TEST(testPOPMtoString); - CPPUNIT_TEST(testParsePOPM); - CPPUNIT_TEST(testParsePOPMWithoutCounter); - CPPUNIT_TEST(testRenderPOPM); - CPPUNIT_TEST(testPOPMFromFile); - CPPUNIT_TEST(testParseRelativeVolumeFrame); - CPPUNIT_TEST(testParseUniqueFileIdentifierFrame); - CPPUNIT_TEST(testParseEmptyUniqueFileIdentifierFrame); - CPPUNIT_TEST(testBrokenFrame1); - CPPUNIT_TEST(testItunes24FrameSize); - CPPUNIT_TEST(testParseUrlLinkFrame); - CPPUNIT_TEST(testRenderUrlLinkFrame); - CPPUNIT_TEST(testParseUserUrlLinkFrame); - CPPUNIT_TEST(testRenderUserUrlLinkFrame); - CPPUNIT_TEST(testParseOwnershipFrame); - CPPUNIT_TEST(testRenderOwnershipFrame); - CPPUNIT_TEST(testSaveUTF16Comment); - CPPUNIT_TEST(testUpdateGenre23_1); - CPPUNIT_TEST(testUpdateGenre23_2); - CPPUNIT_TEST(testUpdateGenre24); - CPPUNIT_TEST(testUpdateDate22); - CPPUNIT_TEST(testDowngradeTo23); - // CPPUNIT_TEST(testUpdateFullDate22); TODO TYE+TDA should be upgraded to TDRC together - CPPUNIT_TEST(testCompressedFrameWithBrokenLength); - CPPUNIT_TEST(testW000); - CPPUNIT_TEST(testPropertyInterface); - CPPUNIT_TEST(testPropertyInterface2); - CPPUNIT_TEST(testDeleteFrame); - CPPUNIT_TEST(testSaveAndStripID3v1ShouldNotAddFrameFromID3v1ToId3v2); - CPPUNIT_TEST_SUITE_END(); - -public: - - void testUnsynchDecode() - { - MPEG::File f(TEST_FILE_PATH_C("unsynch.id3"), false); - CPPUNIT_ASSERT(f.tag()); - CPPUNIT_ASSERT_EQUAL(String("My babe just cares for me"), f.tag()->title()); - } - - void testDowngradeUTF8ForID3v23() - { - ID3v2::TextIdentificationFrame f(ByteVector("TPE1"), String::UTF8); - StringList sl; - sl.append("Foo"); - f.setText(sl); - f.header()->setVersion(3); - ByteVector data = f.render(); - CPPUNIT_ASSERT_EQUAL((unsigned int)(4+4+2+1+6+2), data.size()); - ID3v2::TextIdentificationFrame f2(data); - CPPUNIT_ASSERT_EQUAL(sl, f2.fieldList()); - CPPUNIT_ASSERT_EQUAL(String::UTF16, f2.textEncoding()); - } - - void testUTF16BEDelimiter() - { - ID3v2::TextIdentificationFrame f(ByteVector("TPE1"), String::UTF16BE); - StringList sl; - sl.append("Foo"); - sl.append("Bar"); - f.setText(sl); - CPPUNIT_ASSERT_EQUAL((unsigned int)(4+4+2+1+6+2+6), f.render().size()); - } - - void testUTF16Delimiter() - { - ID3v2::TextIdentificationFrame f(ByteVector("TPE1"), String::UTF16); - StringList sl; - sl.append("Foo"); - sl.append("Bar"); - f.setText(sl); - CPPUNIT_ASSERT_EQUAL((unsigned int)(4+4+2+1+8+2+8), f.render().size()); - } - - void testBrokenFrame1() - { - MPEG::File f(TEST_FILE_PATH_C("broken-tenc.id3"), false); - CPPUNIT_ASSERT(f.tag()); - CPPUNIT_ASSERT(!f.ID3v2Tag()->frameListMap().contains("TENC")); - } - - void testReadStringField() - { - PublicFrame f; - ByteVector data("abc\0", 4); - String str = f.readStringField(data, String::Latin1); - CPPUNIT_ASSERT_EQUAL(String("abc"), str); - } - - // http://bugs.kde.org/show_bug.cgi?id=151078 - void testParseAPIC() - { - ID3v2::AttachedPictureFrame f(ByteVector("APIC" - "\x00\x00\x00\x07" - "\x00\x00" - "\x00" - "m\x00" - "\x01" - "d\x00" - "\x00", 17)); - CPPUNIT_ASSERT_EQUAL(String("m"), f.mimeType()); - CPPUNIT_ASSERT_EQUAL(ID3v2::AttachedPictureFrame::FileIcon, f.type()); - CPPUNIT_ASSERT_EQUAL(String("d"), f.description()); - } - - void testParseAPIC_UTF16_BOM() - { - ID3v2::AttachedPictureFrame f(ByteVector( - "\x41\x50\x49\x43\x00\x02\x0c\x59\x00\x00\x01\x69\x6d\x61\x67\x65" - "\x2f\x6a\x70\x65\x67\x00\x00\xfe\xff\x00\x63\x00\x6f\x00\x76\x00" - "\x65\x00\x72\x00\x2e\x00\x6a\x00\x70\x00\x67\x00\x00\xff\xd8\xff", - 16 * 3)); - CPPUNIT_ASSERT_EQUAL(String("image/jpeg"), f.mimeType()); - CPPUNIT_ASSERT_EQUAL(ID3v2::AttachedPictureFrame::Other, f.type()); - CPPUNIT_ASSERT_EQUAL(String("cover.jpg"), f.description()); - CPPUNIT_ASSERT_EQUAL(ByteVector("\xff\xd8\xff", 3), f.picture()); - } - - void testParseAPICv22() - { - ID3v2::FrameFactory *factory = ID3v2::FrameFactory::instance(); - ByteVector data = ByteVector("PIC" - "\x00\x00\x08" - "\x00" - "JPG" - "\x01" - "d\x00" - "\x00", 18); - ID3v2::AttachedPictureFrame *frame = - static_cast<TagLib::ID3v2::AttachedPictureFrame*>(factory->createFrame(data, TagLib::uint(2))); - - CPPUNIT_ASSERT(frame); - CPPUNIT_ASSERT_EQUAL(String("image/jpeg"), frame->mimeType()); - CPPUNIT_ASSERT_EQUAL(ID3v2::AttachedPictureFrame::FileIcon, frame->type()); - CPPUNIT_ASSERT_EQUAL(String("d"), frame->description()); - } - - void testDontRender22() - { - ID3v2::FrameFactory *factory = ID3v2::FrameFactory::instance(); - ByteVector data = ByteVector("FOO" - "\x00\x00\x08" - "\x00" - "JPG" - "\x01" - "d\x00" - "\x00", 18); - ID3v2::AttachedPictureFrame *frame = - static_cast<TagLib::ID3v2::AttachedPictureFrame*>(factory->createFrame(data, TagLib::uint(2))); - - CPPUNIT_ASSERT(frame); - - ID3v2::Tag tag; - tag.addFrame(frame); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(1034), tag.render().size()); - } - - // http://bugs.kde.org/show_bug.cgi?id=151078 - void testParseGEOB() - { - ID3v2::GeneralEncapsulatedObjectFrame f(ByteVector("GEOB" - "\x00\x00\x00\x08" - "\x00\x00" - "\x00" - "m\x00" - "f\x00" - "d\x00" - "\x00", 18)); - CPPUNIT_ASSERT_EQUAL(String("m"), f.mimeType()); - CPPUNIT_ASSERT_EQUAL(String("f"), f.fileName()); - CPPUNIT_ASSERT_EQUAL(String("d"), f.description()); - } - - void testParsePOPM() - { - ID3v2::PopularimeterFrame f(ByteVector("POPM" - "\x00\x00\x00\x17" - "\x00\x00" - "email@example.com\x00" - "\x02" - "\x00\x00\x00\x03", 33)); - CPPUNIT_ASSERT_EQUAL(String("email@example.com"), f.email()); - CPPUNIT_ASSERT_EQUAL(2, f.rating()); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(3), f.counter()); - } - - void testParsePOPMWithoutCounter() - { - ID3v2::PopularimeterFrame f(ByteVector("POPM" - "\x00\x00\x00\x13" - "\x00\x00" - "email@example.com\x00" - "\x02", 29)); - CPPUNIT_ASSERT_EQUAL(String("email@example.com"), f.email()); - CPPUNIT_ASSERT_EQUAL(2, f.rating()); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(0), f.counter()); - } - - void testRenderPOPM() - { - ID3v2::PopularimeterFrame f; - f.setEmail("email@example.com"); - f.setRating(2); - f.setCounter(3); - CPPUNIT_ASSERT_EQUAL( - ByteVector("POPM" - "\x00\x00\x00\x17" - "\x00\x00" - "email@example.com\x00" - "\x02" - "\x00\x00\x00\x03", 33), - f.render()); - } - - void testPOPMtoString() - { - ID3v2::PopularimeterFrame f; - f.setEmail("email@example.com"); - f.setRating(2); - f.setCounter(3); - CPPUNIT_ASSERT_EQUAL( - String("email@example.com rating=2 counter=3"), f.toString()); - } - - void testPOPMFromFile() - { - ScopedFileCopy copy("xing", ".mp3"); - string newname = copy.fileName(); - - ID3v2::PopularimeterFrame *f = new ID3v2::PopularimeterFrame(); - f->setEmail("email@example.com"); - f->setRating(200); - f->setCounter(3); - - MPEG::File foo(newname.c_str()); - foo.ID3v2Tag()->addFrame(f); - foo.save(); - - MPEG::File bar(newname.c_str()); - CPPUNIT_ASSERT_EQUAL(String("email@example.com"), dynamic_cast<ID3v2::PopularimeterFrame *>(bar.ID3v2Tag()->frameList("POPM").front())->email()); - CPPUNIT_ASSERT_EQUAL(200, dynamic_cast<ID3v2::PopularimeterFrame *>(bar.ID3v2Tag()->frameList("POPM").front())->rating()); - } - - // http://bugs.kde.org/show_bug.cgi?id=150481 - void testParseRelativeVolumeFrame() - { - ID3v2::RelativeVolumeFrame f( - ByteVector("RVA2" // Frame ID - "\x00\x00\x00\x0B" // Frame size - "\x00\x00" // Frame flags - "ident\x00" // Identification - "\x02" // Type of channel - "\x00\x0F" // Volume adjustment - "\x08" // Bits representing peak - "\x45", 21)); // Peak volume - CPPUNIT_ASSERT_EQUAL(String("ident"), f.identification()); - CPPUNIT_ASSERT_EQUAL(15.0f / 512.0f, - f.volumeAdjustment(ID3v2::RelativeVolumeFrame::FrontRight)); - CPPUNIT_ASSERT_EQUAL((uchar)8, - f.peakVolume(ID3v2::RelativeVolumeFrame::FrontRight).bitsRepresentingPeak); - CPPUNIT_ASSERT_EQUAL(ByteVector("\x45"), - f.peakVolume(ID3v2::RelativeVolumeFrame::FrontRight).peakVolume); - } - - void testParseUniqueFileIdentifierFrame() - { - ID3v2::UniqueFileIdentifierFrame f( - ByteVector("UFID" // Frame ID - "\x00\x00\x00\x09" // Frame size - "\x00\x00" // Frame flags - "owner\x00" // Owner identifier - "\x00\x01\x02", 19)); // Identifier - CPPUNIT_ASSERT_EQUAL(String("owner"), - f.owner()); - CPPUNIT_ASSERT_EQUAL(ByteVector("\x00\x01\x02", 3), - f.identifier()); - } - - void testParseEmptyUniqueFileIdentifierFrame() - { - ID3v2::UniqueFileIdentifierFrame f( - ByteVector("UFID" // Frame ID - "\x00\x00\x00\x01" // Frame size - "\x00\x00" // Frame flags - "\x00" // Owner identifier - "", 11)); // Identifier - CPPUNIT_ASSERT_EQUAL(String(), - f.owner()); - CPPUNIT_ASSERT_EQUAL(ByteVector(), - f.identifier()); - } - - void testParseUrlLinkFrame() - { - ID3v2::UrlLinkFrame f( - ByteVector("WOAF" // Frame ID - "\x00\x00\x00\x12" // Frame size - "\x00\x00" // Frame flags - "http://example.com", 28)); // URL - CPPUNIT_ASSERT_EQUAL(String("http://example.com"), f.url()); - } - - void testRenderUrlLinkFrame() - { - ID3v2::UrlLinkFrame f("WOAF"); - f.setUrl("http://example.com"); - CPPUNIT_ASSERT_EQUAL( - ByteVector("WOAF" // Frame ID - "\x00\x00\x00\x12" // Frame size - "\x00\x00" // Frame flags - "http://example.com", 28), // URL - f.render()); - } - - void testParseUserUrlLinkFrame() - { - ID3v2::UserUrlLinkFrame f( - ByteVector("WXXX" // Frame ID - "\x00\x00\x00\x17" // Frame size - "\x00\x00" // Frame flags - "\x00" // Text encoding - "foo\x00" // Description - "http://example.com", 33)); // URL - CPPUNIT_ASSERT_EQUAL(String("foo"), f.description()); - CPPUNIT_ASSERT_EQUAL(String("http://example.com"), f.url()); - } - - void testRenderUserUrlLinkFrame() - { - ID3v2::UserUrlLinkFrame f; - f.setDescription("foo"); - f.setUrl("http://example.com"); - CPPUNIT_ASSERT_EQUAL( - ByteVector("WXXX" // Frame ID - "\x00\x00\x00\x17" // Frame size - "\x00\x00" // Frame flags - "\x00" // Text encoding - "foo\x00" // Description - "http://example.com", 33), // URL - f.render()); - } - - void testParseOwnershipFrame() - { - ID3v2::OwnershipFrame f( - ByteVector("OWNE" // Frame ID - "\x00\x00\x00\x19" // Frame size - "\x00\x00" // Frame flags - "\x00" // Text encoding - "GBP1.99\x00" // Price paid - "20120905" // Date of purchase - "Beatport", 35)); // Seller - CPPUNIT_ASSERT_EQUAL(String("GBP1.99"), f.pricePaid()); - CPPUNIT_ASSERT_EQUAL(String("20120905"), f.datePurchased()); - CPPUNIT_ASSERT_EQUAL(String("Beatport"), f.seller()); - } - - void testRenderOwnershipFrame() - { - ID3v2::OwnershipFrame f; - f.setPricePaid("GBP1.99"); - f.setDatePurchased("20120905"); - f.setSeller("Beatport"); - CPPUNIT_ASSERT_EQUAL( - ByteVector("OWNE" // Frame ID - "\x00\x00\x00\x19" // Frame size - "\x00\x00" // Frame flags - "\x00" // Text encoding - "GBP1.99\x00" // Price paid - "20120905" // Date of purchase - "Beatport", 35), // URL - f.render()); - } - - void testItunes24FrameSize() - { - MPEG::File f(TEST_FILE_PATH_C("005411.id3"), false); - CPPUNIT_ASSERT(f.tag()); - CPPUNIT_ASSERT(f.ID3v2Tag()->frameListMap().contains("TIT2")); - CPPUNIT_ASSERT_EQUAL(String("Sunshine Superman"), f.ID3v2Tag()->frameListMap()["TIT2"].front()->toString()); - } - - void testSaveUTF16Comment() - { - String::Type defaultEncoding = ID3v2::FrameFactory::instance()->defaultTextEncoding(); - ScopedFileCopy copy("xing", ".mp3"); - string newname = copy.fileName(); - ID3v2::FrameFactory::instance()->setDefaultTextEncoding(String::UTF16); - MPEG::File foo(newname.c_str()); - foo.strip(); - foo.tag()->setComment("Test comment!"); - foo.save(); - MPEG::File bar(newname.c_str()); - CPPUNIT_ASSERT_EQUAL(String("Test comment!"), bar.tag()->comment()); - ID3v2::FrameFactory::instance()->setDefaultTextEncoding(defaultEncoding); - } - - void testUpdateGenre23_1() - { - // "Refinement" is the same as the ID3v1 genre - duplicate - ID3v2::FrameFactory *factory = ID3v2::FrameFactory::instance(); - ByteVector data = ByteVector("TCON" // Frame ID - "\x00\x00\x00\x10" // Frame size - "\x00\x00" // Frame flags - "\x00" // Encoding - "(22)Death Metal", 26); // Text - ID3v2::TextIdentificationFrame *frame = - static_cast<TagLib::ID3v2::TextIdentificationFrame*>(factory->createFrame(data, TagLib::uint(3))); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), frame->fieldList().size()); - CPPUNIT_ASSERT_EQUAL(String("Death Metal"), frame->fieldList()[0]); - - ID3v2::Tag tag; - tag.addFrame(frame); - CPPUNIT_ASSERT_EQUAL(String("Death Metal"), tag.genre()); - } - - void testUpdateGenre23_2() - { - // "Refinement" is different from the ID3v1 genre - ID3v2::FrameFactory *factory = ID3v2::FrameFactory::instance(); - ByteVector data = ByteVector("TCON" // Frame ID - "\x00\x00\x00\x13" // Frame size - "\x00\x00" // Frame flags - "\x00" // Encoding - "(4)Eurodisco", 23); // Text - ID3v2::TextIdentificationFrame *frame = - static_cast<TagLib::ID3v2::TextIdentificationFrame*>(factory->createFrame(data, TagLib::uint(3))); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), frame->fieldList().size()); - CPPUNIT_ASSERT_EQUAL(String("4"), frame->fieldList()[0]); - CPPUNIT_ASSERT_EQUAL(String("Eurodisco"), frame->fieldList()[1]); - - ID3v2::Tag tag; - tag.addFrame(frame); - CPPUNIT_ASSERT_EQUAL(String("Disco Eurodisco"), tag.genre()); - } - - void testUpdateGenre24() - { - ID3v2::FrameFactory *factory = ID3v2::FrameFactory::instance(); - ByteVector data = ByteVector("TCON" // Frame ID - "\x00\x00\x00\x0D" // Frame size - "\x00\x00" // Frame flags - "\0" // Encoding - "14\0Eurodisco", 23); // Text - ID3v2::TextIdentificationFrame *frame = - static_cast<TagLib::ID3v2::TextIdentificationFrame*>(factory->createFrame(data, TagLib::uint(4))); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), frame->fieldList().size()); - CPPUNIT_ASSERT_EQUAL(String("14"), frame->fieldList()[0]); - CPPUNIT_ASSERT_EQUAL(String("Eurodisco"), frame->fieldList()[1]); - - ID3v2::Tag tag; - tag.addFrame(frame); - CPPUNIT_ASSERT_EQUAL(String("R&B Eurodisco"), tag.genre()); - } - - void testUpdateDate22() - { - MPEG::File f(TEST_FILE_PATH_C("id3v22-tda.mp3"), false); - CPPUNIT_ASSERT(f.tag()); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(2010), f.tag()->year()); - } - - void testUpdateFullDate22() - { - MPEG::File f(TEST_FILE_PATH_C("id3v22-tda.mp3"), false); - CPPUNIT_ASSERT(f.tag()); - CPPUNIT_ASSERT_EQUAL(String("2010-04-03"), f.ID3v2Tag()->frameListMap()["TDRC"].front()->toString()); - } - - void testDowngradeTo23() - { - ScopedFileCopy copy("xing", ".mp3"); - string newname = copy.fileName(); - - ID3v2::TextIdentificationFrame *tf; - MPEG::File foo(newname.c_str()); - tf = new ID3v2::TextIdentificationFrame("TDOR", String::Latin1); - tf->setText("2011-03-16"); - foo.ID3v2Tag()->addFrame(tf); - tf = new ID3v2::TextIdentificationFrame("TDRC", String::Latin1); - tf->setText("2012-04-17T12:01"); - foo.ID3v2Tag()->addFrame(tf); - tf = new ID3v2::TextIdentificationFrame("TMCL", String::Latin1); - tf->setText(StringList().append("Guitar").append("Artist 1").append("Drums").append("Artist 2")); - foo.ID3v2Tag()->addFrame(tf); - tf = new ID3v2::TextIdentificationFrame("TIPL", String::Latin1); - tf->setText(StringList().append("Producer").append("Artist 3").append("Mastering").append("Artist 4")); - foo.ID3v2Tag()->addFrame(tf); - foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TDRL", String::Latin1)); - foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TDTG", String::Latin1)); - foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TMOO", String::Latin1)); - foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TPRO", String::Latin1)); - foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TSOA", String::Latin1)); - foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TSOT", String::Latin1)); - foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TSST", String::Latin1)); - foo.ID3v2Tag()->addFrame(new ID3v2::TextIdentificationFrame("TSOP", String::Latin1)); - foo.save(MPEG::File::AllTags, true, 3); - - MPEG::File bar(newname.c_str()); - tf = static_cast<ID3v2::TextIdentificationFrame *>(bar.ID3v2Tag()->frameList("TDOR").front()); - CPPUNIT_ASSERT(tf); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), tf->fieldList().size()); - CPPUNIT_ASSERT_EQUAL(String("2011"), tf->fieldList().front()); - tf = static_cast<ID3v2::TextIdentificationFrame *>(bar.ID3v2Tag()->frameList("TDRC").front()); - CPPUNIT_ASSERT(tf); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), tf->fieldList().size()); - CPPUNIT_ASSERT_EQUAL(String("2012"), tf->fieldList().front()); - tf = dynamic_cast<ID3v2::TextIdentificationFrame *>(bar.ID3v2Tag()->frameList("TIPL").front()); - CPPUNIT_ASSERT(tf); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(8), tf->fieldList().size()); - CPPUNIT_ASSERT_EQUAL(String("Guitar"), tf->fieldList()[0]); - CPPUNIT_ASSERT_EQUAL(String("Artist 1"), tf->fieldList()[1]); - CPPUNIT_ASSERT_EQUAL(String("Drums"), tf->fieldList()[2]); - CPPUNIT_ASSERT_EQUAL(String("Artist 2"), tf->fieldList()[3]); - CPPUNIT_ASSERT_EQUAL(String("Producer"), tf->fieldList()[4]); - CPPUNIT_ASSERT_EQUAL(String("Artist 3"), tf->fieldList()[5]); - CPPUNIT_ASSERT_EQUAL(String("Mastering"), tf->fieldList()[6]); - CPPUNIT_ASSERT_EQUAL(String("Artist 4"), tf->fieldList()[7]); - CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TDRL")); - CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TDTG")); - CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TMOO")); - CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TPRO")); - CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TSOA")); - CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TSOT")); - CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TSST")); - CPPUNIT_ASSERT(!bar.ID3v2Tag()->frameListMap().contains("TSOP")); - } - - void testCompressedFrameWithBrokenLength() - { - MPEG::File f(TEST_FILE_PATH_C("compressed_id3_frame.mp3"), false); - CPPUNIT_ASSERT(f.ID3v2Tag()->frameListMap().contains("APIC")); - -#ifdef HAVE_ZLIB - - ID3v2::AttachedPictureFrame *frame - = dynamic_cast<TagLib::ID3v2::AttachedPictureFrame*>(f.ID3v2Tag()->frameListMap()["APIC"].front()); - CPPUNIT_ASSERT(frame); - CPPUNIT_ASSERT_EQUAL(String("image/bmp"), frame->mimeType()); - CPPUNIT_ASSERT_EQUAL(ID3v2::AttachedPictureFrame::Other, frame->type()); - CPPUNIT_ASSERT_EQUAL(String(""), frame->description()); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(86414), frame->picture().size()); - -#else - - // Skip the test if ZLIB is not installed. - // The message "Compressed frames are currently not supported." will be displayed. - - ID3v2::UnknownFrame *frame - = dynamic_cast<TagLib::ID3v2::UnknownFrame*>(f.ID3v2Tag()->frameListMap()["APIC"].front()); - CPPUNIT_ASSERT(frame); - -#endif - } - - void testW000() - { - MPEG::File f(TEST_FILE_PATH_C("w000.mp3"), false); - CPPUNIT_ASSERT(f.ID3v2Tag()->frameListMap().contains("W000")); - ID3v2::UrlLinkFrame *frame = - dynamic_cast<TagLib::ID3v2::UrlLinkFrame*>(f.ID3v2Tag()->frameListMap()["W000"].front()); - CPPUNIT_ASSERT(frame); - CPPUNIT_ASSERT_EQUAL(String("lukas.lalinsky@example.com____"), frame->url()); - } - - void testPropertyInterface() - { - ScopedFileCopy copy("rare_frames", ".mp3"); - string newname = copy.fileName(); - MPEG::File f(newname.c_str()); - PropertyMap dict = f.ID3v2Tag(false)->properties(); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(6), dict.size()); - - CPPUNIT_ASSERT(dict.contains("USERTEXTDESCRIPTION1")); - CPPUNIT_ASSERT(dict.contains("QuodLibet::USERTEXTDESCRIPTION2")); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), dict["USERTEXTDESCRIPTION1"].size()); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), dict["QuodLibet::USERTEXTDESCRIPTION2"].size()); - CPPUNIT_ASSERT_EQUAL(String("userTextData1"), dict["USERTEXTDESCRIPTION1"][0]); - CPPUNIT_ASSERT_EQUAL(String("userTextData2"), dict["USERTEXTDESCRIPTION1"][1]); - CPPUNIT_ASSERT_EQUAL(String("userTextData1"), dict["QuodLibet::USERTEXTDESCRIPTION2"][0]); - CPPUNIT_ASSERT_EQUAL(String("userTextData2"), dict["QuodLibet::USERTEXTDESCRIPTION2"][1]); - - CPPUNIT_ASSERT_EQUAL(String("Pop"), dict["GENRE"].front()); - - CPPUNIT_ASSERT_EQUAL(String("http://a.user.url"), dict["URL:USERURL"].front()); - - CPPUNIT_ASSERT_EQUAL(String("http://a.user.url/with/empty/description"), dict["URL"].front()); - CPPUNIT_ASSERT_EQUAL(String("A COMMENT"), dict["COMMENT"].front()); - - CPPUNIT_ASSERT_EQUAL(1u, dict.unsupportedData().size()); - CPPUNIT_ASSERT_EQUAL(String("UFID/supermihi@web.de"), dict.unsupportedData().front()); - } - - void testPropertyInterface2() - { - ID3v2::Tag tag; - ID3v2::UnsynchronizedLyricsFrame *frame1 = new ID3v2::UnsynchronizedLyricsFrame(); - frame1->setDescription("test"); - frame1->setText("la-la-la test"); - tag.addFrame(frame1); - - ID3v2::UnsynchronizedLyricsFrame *frame2 = new ID3v2::UnsynchronizedLyricsFrame(); - frame2->setDescription(""); - frame2->setText("la-la-la nodescription"); - tag.addFrame(frame2); - - ID3v2::AttachedPictureFrame *frame3 = new ID3v2::AttachedPictureFrame(); - frame3->setDescription("test picture"); - tag.addFrame(frame3); - - ID3v2::TextIdentificationFrame *frame4 = new ID3v2::TextIdentificationFrame("TIPL"); - frame4->setText("single value is invalid for TIPL"); - tag.addFrame(frame4); - - ID3v2::TextIdentificationFrame *frame5 = new ID3v2::TextIdentificationFrame("TMCL"); - StringList tmclData; - tmclData.append("VIOLIN"); - tmclData.append("a violinist"); - tmclData.append("PIANO"); - tmclData.append("a pianist"); - frame5->setText(tmclData); - tag.addFrame(frame5); - - ID3v2::UniqueFileIdentifierFrame *frame6 = new ID3v2::UniqueFileIdentifierFrame("http://musicbrainz.org", "152454b9-19ba-49f3-9fc9-8fc26545cf41"); - tag.addFrame(frame6); - - ID3v2::UniqueFileIdentifierFrame *frame7 = new ID3v2::UniqueFileIdentifierFrame("http://example.com", "123"); - tag.addFrame(frame7); - - ID3v2::UserTextIdentificationFrame *frame8 = new ID3v2::UserTextIdentificationFrame(); - frame8->setDescription("MusicBrainz Album Id"); - frame8->setText("95c454a5-d7e0-4d8f-9900-db04aca98ab3"); - tag.addFrame(frame8); - - PropertyMap properties = tag.properties(); - - CPPUNIT_ASSERT_EQUAL(3u, properties.unsupportedData().size()); - CPPUNIT_ASSERT(properties.unsupportedData().contains("TIPL")); - CPPUNIT_ASSERT(properties.unsupportedData().contains("APIC")); - CPPUNIT_ASSERT(properties.unsupportedData().contains("UFID/http://example.com")); - - CPPUNIT_ASSERT(properties.contains("PERFORMER:VIOLIN")); - CPPUNIT_ASSERT(properties.contains("PERFORMER:PIANO")); - CPPUNIT_ASSERT_EQUAL(String("a violinist"), properties["PERFORMER:VIOLIN"].front()); - CPPUNIT_ASSERT_EQUAL(String("a pianist"), properties["PERFORMER:PIANO"].front()); - - CPPUNIT_ASSERT(properties.contains("LYRICS")); - CPPUNIT_ASSERT(properties.contains("LYRICS:TEST")); - - CPPUNIT_ASSERT(properties.contains("MUSICBRAINZ_TRACKID")); - CPPUNIT_ASSERT_EQUAL(String("152454b9-19ba-49f3-9fc9-8fc26545cf41"), properties["MUSICBRAINZ_TRACKID"].front()); - - CPPUNIT_ASSERT(properties.contains("MUSICBRAINZ_ALBUMID")); - CPPUNIT_ASSERT_EQUAL(String("95c454a5-d7e0-4d8f-9900-db04aca98ab3"), properties["MUSICBRAINZ_ALBUMID"].front()); - - tag.removeUnsupportedProperties(properties.unsupportedData()); - CPPUNIT_ASSERT(tag.frameList("APIC").isEmpty()); - CPPUNIT_ASSERT(tag.frameList("TIPL").isEmpty()); - CPPUNIT_ASSERT_EQUAL((ID3v2::UniqueFileIdentifierFrame *)0, ID3v2::UniqueFileIdentifierFrame::findByOwner(&tag, "http://example.com")); - CPPUNIT_ASSERT_EQUAL(frame6, ID3v2::UniqueFileIdentifierFrame::findByOwner(&tag, "http://musicbrainz.org")); - } - - void testDeleteFrame() - { - ScopedFileCopy copy("rare_frames", ".mp3"); - string newname = copy.fileName(); - MPEG::File f(newname.c_str()); - ID3v2::Tag *t = f.ID3v2Tag(); - ID3v2::Frame *frame = t->frameList("TCON")[0]; - CPPUNIT_ASSERT_EQUAL(1u, t->frameList("TCON").size()); - t->removeFrame(frame, true); - f.save(MPEG::File::ID3v2); - - MPEG::File f2(newname.c_str()); - t = f2.ID3v2Tag(); - CPPUNIT_ASSERT(t->frameList("TCON").isEmpty()); - } - - void testSaveAndStripID3v1ShouldNotAddFrameFromID3v1ToId3v2() - { - ScopedFileCopy copy("xing", ".mp3"); - string newname = copy.fileName(); - - { - MPEG::File foo(newname.c_str()); - foo.tag()->setArtist("Artist"); - foo.save(MPEG::File::ID3v1 | MPEG::File::ID3v2); - } - - { - MPEG::File bar(newname.c_str()); - bar.ID3v2Tag()->removeFrames("TPE1"); - // Should strip ID3v1 here and not add old values to ID3v2 again - bar.save(MPEG::File::ID3v2, true); - } - - MPEG::File f(newname.c_str()); - CPPUNIT_ASSERT(!f.ID3v2Tag()->frameListMap().contains("TPE1")); - } - -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestID3v2); diff --git a/taglib/tests/test_info.cpp b/taglib/tests/test_info.cpp deleted file mode 100644 index 8e0d715..0000000 --- a/taglib/tests/test_info.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include <string> -#include <stdio.h> -#include <infotag.h> -#include <cppunit/extensions/HelperMacros.h> -#include "utils.h" - -using namespace std; -using namespace TagLib; - -class TestInfoTag : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestInfoTag); - CPPUNIT_TEST(testTitle); - CPPUNIT_TEST(testNumericFields); - CPPUNIT_TEST_SUITE_END(); - -public: - void testTitle() - { - RIFF::Info::Tag tag; - - CPPUNIT_ASSERT_EQUAL(String(""), tag.title()); - tag.setTitle("Test title 1"); - tag.setFieldText("TEST", "Dummy Text"); - - CPPUNIT_ASSERT_EQUAL(String("Test title 1"), tag.title()); - - RIFF::Info::FieldListMap map = tag.fieldListMap(); - CPPUNIT_ASSERT_EQUAL(String("Test title 1"), map["INAM"]); - CPPUNIT_ASSERT_EQUAL(String("Dummy Text"), map["TEST"]); - } - - void testNumericFields() - { - RIFF::Info::Tag tag; - - CPPUNIT_ASSERT_EQUAL((uint)0, tag.track()); - tag.setTrack(1234); - CPPUNIT_ASSERT_EQUAL((uint)1234, tag.track()); - CPPUNIT_ASSERT_EQUAL(String("1234"), tag.fieldText("IPRT")); - - CPPUNIT_ASSERT_EQUAL((uint)0, tag.year()); - tag.setYear(1234); - CPPUNIT_ASSERT_EQUAL((uint)1234, tag.year()); - CPPUNIT_ASSERT_EQUAL(String("1234"), tag.fieldText("ICRD")); - } -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestInfoTag); diff --git a/taglib/tests/test_it.cpp b/taglib/tests/test_it.cpp deleted file mode 100644 index be5680e..0000000 --- a/taglib/tests/test_it.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/*************************************************************************** - copyright : (C) 2011 by Mathias Panzenböck - email : grosser.meister.morti@gmx.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * - ***************************************************************************/ - -#include <itfile.h> -#include <tstringlist.h> -#include <cppunit/extensions/HelperMacros.h> -#include "utils.h" - -using namespace std; -using namespace TagLib; -using TagLib::uint; - -static const String titleBefore("test song name"); -static const String titleAfter("changed title"); - -static const String commentBefore( - "This is a sample name.\n" - "In module file formats\n" - "sample names are abused\n" - "as multiline comments.\n" - " "); - -static const String newComment( - "This is a sample name!\n" - "In module file formats\n" - "sample names are abused\n" - "as multiline comments.\n" - "-----------------------------------\n" - "The previous line is truncated but starting with this line\n" - "the comment is not limeted in the line length but to 8000\n" - "additional characters (bytes).\n" - "\n" - "This is because it is saved in the 'message' proportion of\n" - "IT files."); - -static const String commentAfter( - "This is a sample name!\n" - "In module file formats\n" - "sample names are abused\n" - "as multiline comments.\n" - "-------------------------\n" - "The previous line is truncated but starting with this line\n" - "the comment is not limeted in the line length but to 8000\n" - "additional characters (bytes).\n" - "\n" - "This is because it is saved in the 'message' proportion of\n" - "IT files."); - -class TestIT : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestIT); - CPPUNIT_TEST(testReadTags); - CPPUNIT_TEST(testWriteTags); - CPPUNIT_TEST_SUITE_END(); - -public: - void testReadTags() - { - testRead(TEST_FILE_PATH_C("test.it"), titleBefore, commentBefore); - } - - void testWriteTags() - { - ScopedFileCopy copy("test", ".it"); - { - IT::File file(copy.fileName().c_str()); - CPPUNIT_ASSERT(file.tag() != 0); - file.tag()->setTitle(titleAfter); - file.tag()->setComment(newComment); - file.tag()->setTrackerName("won't be saved"); - CPPUNIT_ASSERT(file.save()); - } - testRead(copy.fileName().c_str(), titleAfter, commentAfter); - } - -private: - void testRead(FileName fileName, const String &title, const String &comment) - { - IT::File file(fileName); - - CPPUNIT_ASSERT(file.isValid()); - - IT::Properties *p = file.audioProperties(); - Mod::Tag *t = file.tag(); - - CPPUNIT_ASSERT(0 != p); - CPPUNIT_ASSERT(0 != t); - - CPPUNIT_ASSERT_EQUAL( 0, p->length()); - CPPUNIT_ASSERT_EQUAL( 0, p->bitrate()); - CPPUNIT_ASSERT_EQUAL( 0, p->sampleRate()); - CPPUNIT_ASSERT_EQUAL(64, p->channels()); - CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 0, p->lengthInPatterns()); - CPPUNIT_ASSERT_EQUAL(true, p->stereo()); - CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 0, p->instrumentCount()); - CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 5, p->sampleCount()); - CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 1, p->patternCount()); - CPPUNIT_ASSERT_EQUAL((TagLib::ushort)535, p->version()); - CPPUNIT_ASSERT_EQUAL((TagLib::ushort)532, p->compatibleVersion()); - CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 9, p->flags()); - CPPUNIT_ASSERT_EQUAL((TagLib::uchar)128, p->globalVolume()); - CPPUNIT_ASSERT_EQUAL((TagLib::uchar) 48, p->mixVolume()); - CPPUNIT_ASSERT_EQUAL((TagLib::uchar)125, p->tempo()); - CPPUNIT_ASSERT_EQUAL((TagLib::uchar) 6, p->bpmSpeed()); - CPPUNIT_ASSERT_EQUAL((TagLib::uchar)128, p->panningSeparation()); - CPPUNIT_ASSERT_EQUAL((TagLib::uchar) 0, p->pitchWheelDepth()); - CPPUNIT_ASSERT_EQUAL(title, t->title()); - CPPUNIT_ASSERT_EQUAL(String::null, t->artist()); - CPPUNIT_ASSERT_EQUAL(String::null, t->album()); - CPPUNIT_ASSERT_EQUAL(comment, t->comment()); - CPPUNIT_ASSERT_EQUAL(String::null, t->genre()); - CPPUNIT_ASSERT_EQUAL(0U, t->year()); - CPPUNIT_ASSERT_EQUAL(0U, t->track()); - CPPUNIT_ASSERT_EQUAL(String("Impulse Tracker"), t->trackerName()); - } -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestIT); diff --git a/taglib/tests/test_list.cpp b/taglib/tests/test_list.cpp deleted file mode 100644 index 39cbaf0..0000000 --- a/taglib/tests/test_list.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* Copyright (C) 2003 Scott Wheeler <wheeler@kde.org> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <cppunit/extensions/HelperMacros.h> -#include <tlist.h> - -using namespace std; -using namespace TagLib; - -class TestList : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestList); - CPPUNIT_TEST(testList); - CPPUNIT_TEST_SUITE_END(); - -public: - - void testList() - { - List<int> l1; - List<int> l2; - List<int> l3; - l1.append(2); - l2.append(3); - l2.append(4); - l1.append(l2); - l1.prepend(1); - l3.append(1); - l3.append(2); - l3.append(3); - l3.append(4); - CPPUNIT_ASSERT(l1 == l3); - } - -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestList); diff --git a/taglib/tests/test_map.cpp b/taglib/tests/test_map.cpp deleted file mode 100644 index b6f77aa..0000000 --- a/taglib/tests/test_map.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include <cppunit/extensions/HelperMacros.h> -#include <tstring.h> -#include <tmap.h> - -using namespace std; -using namespace TagLib; - -class TestMap : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestMap); - CPPUNIT_TEST(testInsert); - CPPUNIT_TEST_SUITE_END(); - -public: - - void testInsert() - { - Map<String, int> m; - m.insert("foo", 3); - CPPUNIT_ASSERT_EQUAL(3, m["foo"]); - m.insert("foo", 7); - CPPUNIT_ASSERT_EQUAL(7, m["foo"]); - } - -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestMap); diff --git a/taglib/tests/test_mod.cpp b/taglib/tests/test_mod.cpp deleted file mode 100644 index 0a233c9..0000000 --- a/taglib/tests/test_mod.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/*************************************************************************** - copyright : (C) 2011 by Mathias Panzenböck - email : grosser.meister.morti@gmx.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * - ***************************************************************************/ - -#include <modfile.h> -#include <tpropertymap.h> -#include <cppunit/extensions/HelperMacros.h> -#include "utils.h" - -using namespace std; -using namespace TagLib; - -static const String titleBefore("title of song"); -static const String titleAfter("changed title"); - -static const String commentBefore( - "Instrument names\n" - "are abused as\n" - "comments in\n" - "module file formats.\n" - "-+-+-+-+-+-+-+-+-+-+-+\n" - "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); - -static const String newComment( - "This line will be truncated because it is too long for a mod instrument name.\n" - "This line is ok."); - -static const String commentAfter( - "This line will be trun\n" - "This line is ok.\n" - "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); - -class TestMod : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestMod); - CPPUNIT_TEST(testReadTags); - CPPUNIT_TEST(testWriteTags); - CPPUNIT_TEST(testPropertyInterface); - CPPUNIT_TEST_SUITE_END(); - -public: - void testReadTags() - { - testRead(TEST_FILE_PATH_C("test.mod"), titleBefore, commentBefore); - } - - void testWriteTags() - { - ScopedFileCopy copy("test", ".mod"); - { - Mod::File file(copy.fileName().c_str()); - CPPUNIT_ASSERT(file.tag() != 0); - file.tag()->setTitle(titleAfter); - file.tag()->setComment(newComment); - CPPUNIT_ASSERT(file.save()); - } - testRead(copy.fileName().c_str(), titleAfter, commentAfter); - CPPUNIT_ASSERT(fileEqual( - copy.fileName(), - TEST_FILE_PATH_C("changed.mod"))); - } - - void testPropertyInterface() - { - Mod::Tag t; - PropertyMap properties; - properties["BLA"] = String("bla"); - properties["ARTIST"] = String("artist1"); - properties["ARTIST"].append("artist2"); - properties["TITLE"] = String("title"); - - PropertyMap unsupported = t.setProperties(properties); - CPPUNIT_ASSERT(unsupported.contains("BLA")); - CPPUNIT_ASSERT(unsupported.contains("ARTIST")); - CPPUNIT_ASSERT_EQUAL(properties["ARTIST"], unsupported["ARTIST"]); - CPPUNIT_ASSERT(!unsupported.contains("TITLE")); - } - -private: - void testRead(FileName fileName, const String &title, const String &comment) - { - Mod::File file(fileName); - - CPPUNIT_ASSERT(file.isValid()); - - Mod::Properties *p = file.audioProperties(); - Mod::Tag *t = file.tag(); - - CPPUNIT_ASSERT(0 != p); - CPPUNIT_ASSERT(0 != t); - - CPPUNIT_ASSERT_EQUAL(0, p->length()); - CPPUNIT_ASSERT_EQUAL(0, p->bitrate()); - CPPUNIT_ASSERT_EQUAL(0, p->sampleRate()); - CPPUNIT_ASSERT_EQUAL(8, p->channels()); - CPPUNIT_ASSERT_EQUAL(31U, p->instrumentCount()); - CPPUNIT_ASSERT_EQUAL((uchar)1, p->lengthInPatterns()); - CPPUNIT_ASSERT_EQUAL(title, t->title()); - CPPUNIT_ASSERT_EQUAL(String::null, t->artist()); - CPPUNIT_ASSERT_EQUAL(String::null, t->album()); - CPPUNIT_ASSERT_EQUAL(comment, t->comment()); - CPPUNIT_ASSERT_EQUAL(String::null, t->genre()); - CPPUNIT_ASSERT_EQUAL(0U, t->year()); - CPPUNIT_ASSERT_EQUAL(0U, t->track()); - CPPUNIT_ASSERT_EQUAL(String("StarTrekker"), t->trackerName()); - } -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestMod); diff --git a/taglib/tests/test_mp4.cpp b/taglib/tests/test_mp4.cpp deleted file mode 100644 index 56b6052..0000000 --- a/taglib/tests/test_mp4.cpp +++ /dev/null @@ -1,282 +0,0 @@ -#include <string> -#include <stdio.h> -#include <tag.h> -#include <mp4tag.h> -#include <tbytevectorlist.h> -#include <tpropertymap.h> -#include <mp4atom.h> -#include <mp4file.h> -#include <cppunit/extensions/HelperMacros.h> -#include "utils.h" - -using namespace std; -using namespace TagLib; - -class TestMP4 : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestMP4); - CPPUNIT_TEST(testPropertiesAAC); - CPPUNIT_TEST(testPropertiesALAC); - CPPUNIT_TEST(testFreeForm); - CPPUNIT_TEST(testCheckValid); - CPPUNIT_TEST(testUpdateStco); - CPPUNIT_TEST(testSaveExisingWhenIlstIsLast); - CPPUNIT_TEST(test64BitAtom); - CPPUNIT_TEST(testGnre); - CPPUNIT_TEST(testCovrRead); - CPPUNIT_TEST(testCovrWrite); - CPPUNIT_TEST(testCovrRead2); - CPPUNIT_TEST(testProperties); - CPPUNIT_TEST_SUITE_END(); - -public: - - void testPropertiesAAC() - { - MP4::File f(TEST_FILE_PATH_C("has-tags.m4a")); - CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->length()); - CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->bitrate()); - CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); - CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); - CPPUNIT_ASSERT_EQUAL(16, ((MP4::Properties *)f.audioProperties())->bitsPerSample()); - CPPUNIT_ASSERT_EQUAL(MP4::Properties::AAC, ((MP4::Properties *)f.audioProperties())->codec()); - } - - void testPropertiesALAC() - { - MP4::File f(TEST_FILE_PATH_C("empty_alac.m4a")); - CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->length()); - CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->bitrate()); - CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); - CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); - CPPUNIT_ASSERT_EQUAL(16, ((MP4::Properties *)f.audioProperties())->bitsPerSample()); - CPPUNIT_ASSERT_EQUAL(MP4::Properties::ALAC, ((MP4::Properties *)f.audioProperties())->codec()); - } - - void testCheckValid() - { - MP4::File f(TEST_FILE_PATH_C("empty.aiff")); - CPPUNIT_ASSERT(!f.isValid()); - MP4::File f2(TEST_FILE_PATH_C("has-tags.m4a")); - CPPUNIT_ASSERT(f2.isValid()); - } - - void testUpdateStco() - { - ScopedFileCopy copy("no-tags", ".3g2"); - string filename = copy.fileName(); - - MP4::File *f = new MP4::File(filename.c_str()); - f->tag()->setArtist(ByteVector(3000, 'x')); - - ByteVectorList data1; - { - MP4::Atoms a(f); - MP4::Atom *stco = a.find("moov")->findall("stco", true)[0]; - f->seek(stco->offset + 12); - ByteVector data = f->readBlock(stco->length - 12); - unsigned int count = data.mid(0, 4).toUInt(); - int pos = 4; - while (count--) { - unsigned int offset = data.mid(pos, 4).toUInt(); - f->seek(offset); - data1.append(f->readBlock(20)); - pos += 4; - } - } - - f->save(); - delete f; - f = new MP4::File(filename.c_str()); - - { - MP4::Atoms a(f); - MP4::Atom *stco = a.find("moov")->findall("stco", true)[0]; - f->seek(stco->offset + 12); - ByteVector data = f->readBlock(stco->length - 12); - unsigned int count = data.mid(0, 4).toUInt(); - int pos = 4, i = 0; - while (count--) { - unsigned int offset = data.mid(pos, 4).toUInt(); - f->seek(offset); - CPPUNIT_ASSERT_EQUAL(data1[i], f->readBlock(20)); - pos += 4; - i++; - } - } - - delete f; - } - - void testFreeForm() - { - ScopedFileCopy copy("has-tags", ".m4a"); - string filename = copy.fileName(); - - MP4::File *f = new MP4::File(filename.c_str()); - CPPUNIT_ASSERT(f->tag()->itemListMap().contains("----:com.apple.iTunes:iTunNORM")); - f->tag()->itemListMap()["----:org.kde.TagLib:Foo"] = StringList("Bar"); - f->save(); - delete f; - - f = new MP4::File(filename.c_str()); - CPPUNIT_ASSERT(f->tag()->itemListMap().contains("----:org.kde.TagLib:Foo")); - CPPUNIT_ASSERT_EQUAL(String("Bar"), f->tag()->itemListMap()["----:org.kde.TagLib:Foo"].toStringList()[0]); - f->save(); - delete f; - } - - void testSaveExisingWhenIlstIsLast() - { - ScopedFileCopy copy("ilst-is-last", ".m4a"); - string filename = copy.fileName(); - - MP4::File *f = new MP4::File(filename.c_str()); - CPPUNIT_ASSERT_EQUAL(String("82,164"), f->tag()->itemListMap()["----:com.apple.iTunes:replaygain_track_minmax"].toStringList()[0]); - CPPUNIT_ASSERT_EQUAL(String("Pearl Jam"), f->tag()->artist()); - f->tag()->setComment("foo"); - f->save(); - delete f; - - f = new MP4::File(filename.c_str()); - CPPUNIT_ASSERT_EQUAL(String("82,164"), f->tag()->itemListMap()["----:com.apple.iTunes:replaygain_track_minmax"].toStringList()[0]); - CPPUNIT_ASSERT_EQUAL(String("Pearl Jam"), f->tag()->artist()); - CPPUNIT_ASSERT_EQUAL(String("foo"), f->tag()->comment()); - } - - void test64BitAtom() - { - ScopedFileCopy copy("64bit", ".mp4"); - string filename = copy.fileName(); - - MP4::File *f = new MP4::File(filename.c_str()); - CPPUNIT_ASSERT_EQUAL(true, f->tag()->itemListMap()["cpil"].toBool()); - - MP4::Atoms *atoms = new MP4::Atoms(f); - MP4::Atom *moov = atoms->atoms[0]; - CPPUNIT_ASSERT_EQUAL(long(77), moov->length); - - f->tag()->itemListMap()["pgap"] = true; - f->save(); - - f = new MP4::File(filename.c_str()); - CPPUNIT_ASSERT_EQUAL(true, f->tag()->itemListMap()["cpil"].toBool()); - CPPUNIT_ASSERT_EQUAL(true, f->tag()->itemListMap()["pgap"].toBool()); - - atoms = new MP4::Atoms(f); - moov = atoms->atoms[0]; - // original size + 'pgap' size + padding - CPPUNIT_ASSERT_EQUAL(long(77 + 25 + 974), moov->length); - } - - void testGnre() - { - MP4::File *f = new MP4::File(TEST_FILE_PATH_C("gnre.m4a")); - CPPUNIT_ASSERT_EQUAL(TagLib::String("Ska"), f->tag()->genre()); - delete f; - } - - void testCovrRead() - { - MP4::File *f = new MP4::File(TEST_FILE_PATH_C("has-tags.m4a")); - CPPUNIT_ASSERT(f->tag()->itemListMap().contains("covr")); - MP4::CoverArtList l = f->tag()->itemListMap()["covr"].toCoverArtList(); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), l.size()); - CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, l[0].format()); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(79), l[0].data().size()); - CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::JPEG, l[1].format()); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(287), l[1].data().size()); - delete f; - } - - void testCovrWrite() - { - ScopedFileCopy copy("has-tags", ".m4a"); - string filename = copy.fileName(); - - MP4::File *f = new MP4::File(filename.c_str()); - CPPUNIT_ASSERT(f->tag()->itemListMap().contains("covr")); - MP4::CoverArtList l = f->tag()->itemListMap()["covr"].toCoverArtList(); - l.append(MP4::CoverArt(MP4::CoverArt::PNG, "foo")); - f->tag()->itemListMap()["covr"] = l; - f->save(); - delete f; - - f = new MP4::File(filename.c_str()); - CPPUNIT_ASSERT(f->tag()->itemListMap().contains("covr")); - l = f->tag()->itemListMap()["covr"].toCoverArtList(); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(3), l.size()); - CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, l[0].format()); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(79), l[0].data().size()); - CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::JPEG, l[1].format()); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(287), l[1].data().size()); - CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, l[2].format()); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(3), l[2].data().size()); - delete f; - } - - void testCovrRead2() - { - MP4::File *f = new MP4::File(TEST_FILE_PATH_C("covr-junk.m4a")); - CPPUNIT_ASSERT(f->tag()->itemListMap().contains("covr")); - MP4::CoverArtList l = f->tag()->itemListMap()["covr"].toCoverArtList(); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), l.size()); - CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, l[0].format()); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(79), l[0].data().size()); - CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::JPEG, l[1].format()); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(287), l[1].data().size()); - delete f; - } - - void testProperties() - { - MP4::File f(TEST_FILE_PATH_C("has-tags.m4a")); - - PropertyMap tags = f.properties(); - - CPPUNIT_ASSERT_EQUAL(StringList("Test Artist"), tags["ARTIST"]); - - tags["TRACKNUMBER"] = StringList("2/4"); - tags["DISCNUMBER"] = StringList("3/5"); - tags["BPM"] = StringList("123"); - tags["ARTIST"] = StringList("Foo Bar"); - tags["COMPILATION"] = StringList("1"); - f.setProperties(tags); - - tags = f.properties(); - - CPPUNIT_ASSERT(f.tag()->itemListMap().contains("trkn")); - CPPUNIT_ASSERT_EQUAL(2, f.tag()->itemListMap()["trkn"].toIntPair().first); - CPPUNIT_ASSERT_EQUAL(4, f.tag()->itemListMap()["trkn"].toIntPair().second); - CPPUNIT_ASSERT_EQUAL(StringList("2/4"), tags["TRACKNUMBER"]); - - CPPUNIT_ASSERT(f.tag()->itemListMap().contains("disk")); - CPPUNIT_ASSERT_EQUAL(3, f.tag()->itemListMap()["disk"].toIntPair().first); - CPPUNIT_ASSERT_EQUAL(5, f.tag()->itemListMap()["disk"].toIntPair().second); - CPPUNIT_ASSERT_EQUAL(StringList("3/5"), tags["DISCNUMBER"]); - - CPPUNIT_ASSERT(f.tag()->itemListMap().contains("tmpo")); - CPPUNIT_ASSERT_EQUAL(123, f.tag()->itemListMap()["tmpo"].toInt()); - CPPUNIT_ASSERT_EQUAL(StringList("123"), tags["BPM"]); - - CPPUNIT_ASSERT(f.tag()->itemListMap().contains("\251ART")); - CPPUNIT_ASSERT_EQUAL(StringList("Foo Bar"), f.tag()->itemListMap()["\251ART"].toStringList()); - CPPUNIT_ASSERT_EQUAL(StringList("Foo Bar"), tags["ARTIST"]); - - CPPUNIT_ASSERT(f.tag()->itemListMap().contains("cpil")); - CPPUNIT_ASSERT_EQUAL(true, f.tag()->itemListMap()["cpil"].toBool()); - CPPUNIT_ASSERT_EQUAL(StringList("1"), tags["COMPILATION"]); - - tags["COMPILATION"] = StringList("0"); - f.setProperties(tags); - - tags = f.properties(); - - CPPUNIT_ASSERT(f.tag()->itemListMap().contains("cpil")); - CPPUNIT_ASSERT_EQUAL(false, f.tag()->itemListMap()["cpil"].toBool()); - CPPUNIT_ASSERT_EQUAL(StringList("0"), tags["COMPILATION"]); - } - -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestMP4); diff --git a/taglib/tests/test_mp4coverart.cpp b/taglib/tests/test_mp4coverart.cpp deleted file mode 100644 index 812a2e5..0000000 --- a/taglib/tests/test_mp4coverart.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include <string> -#include <stdio.h> -#include <tag.h> -#include <mp4coverart.h> -#include <cppunit/extensions/HelperMacros.h> -#include "utils.h" - -using namespace std; -using namespace TagLib; - -class TestMP4CoverArt : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestMP4CoverArt); - CPPUNIT_TEST(testSimple); - CPPUNIT_TEST(testList); - CPPUNIT_TEST_SUITE_END(); - -public: - - void testSimple() - { - MP4::CoverArt c(MP4::CoverArt::PNG, "foo"); - CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, c.format()); - CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), c.data()); - - MP4::CoverArt c2(c); - CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, c2.format()); - CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), c2.data()); - - MP4::CoverArt c3 = c; - CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, c3.format()); - CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), c3.data()); - } - - void testList() - { - MP4::CoverArtList l; - l.append(MP4::CoverArt(MP4::CoverArt::PNG, "foo")); - l.append(MP4::CoverArt(MP4::CoverArt::JPEG, "bar")); - - CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, l[0].format()); - CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), l[0].data()); - CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::JPEG, l[1].format()); - CPPUNIT_ASSERT_EQUAL(ByteVector("bar"), l[1].data()); - } - -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestMP4CoverArt); diff --git a/taglib/tests/test_mp4item.cpp b/taglib/tests/test_mp4item.cpp deleted file mode 100644 index 37d3f71..0000000 --- a/taglib/tests/test_mp4item.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include <string> -#include <stdio.h> -#include <tag.h> -#include <mp4coverart.h> -#include <mp4item.h> -#include <cppunit/extensions/HelperMacros.h> -#include "utils.h" - -using namespace std; -using namespace TagLib; - -class TestMP4Item : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestMP4Item); - CPPUNIT_TEST(testCoverArtList); - CPPUNIT_TEST_SUITE_END(); - -public: - - void testCoverArtList() - { - MP4::CoverArtList l; - l.append(MP4::CoverArt(MP4::CoverArt::PNG, "foo")); - l.append(MP4::CoverArt(MP4::CoverArt::JPEG, "bar")); - - MP4::Item i(l); - MP4::CoverArtList l2 = i.toCoverArtList(); - - CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, l[0].format()); - CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), l[0].data()); - CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::JPEG, l[1].format()); - CPPUNIT_ASSERT_EQUAL(ByteVector("bar"), l[1].data()); - } - -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestMP4Item); diff --git a/taglib/tests/test_mpc.cpp b/taglib/tests/test_mpc.cpp deleted file mode 100644 index 12da6ed..0000000 --- a/taglib/tests/test_mpc.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include <cppunit/extensions/HelperMacros.h> -#include <string> -#include <stdio.h> -#include <tag.h> -#include <tstringlist.h> -#include <tbytevectorlist.h> -#include <mpcfile.h> -#include "utils.h" - -using namespace std; -using namespace TagLib; - -class TestMPC : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestMPC); - CPPUNIT_TEST(testPropertiesSV8); - CPPUNIT_TEST(testPropertiesSV7); - CPPUNIT_TEST(testPropertiesSV5); - CPPUNIT_TEST(testPropertiesSV4); - CPPUNIT_TEST_SUITE_END(); - -public: - - void testPropertiesSV8() - { - MPC::File f(TEST_FILE_PATH_C("sv8_header.mpc")); - CPPUNIT_ASSERT_EQUAL(8, f.audioProperties()->mpcVersion()); - CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->length()); - CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->bitrate()); - CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); - CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); - } - - void testPropertiesSV7() - { - MPC::File f(TEST_FILE_PATH_C("click.mpc")); - CPPUNIT_ASSERT_EQUAL(7, f.audioProperties()->mpcVersion()); - CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->length()); - CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->bitrate()); - CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); - CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); - } - - void testPropertiesSV5() - { - MPC::File f(TEST_FILE_PATH_C("sv5_header.mpc")); - CPPUNIT_ASSERT_EQUAL(5, f.audioProperties()->mpcVersion()); - CPPUNIT_ASSERT_EQUAL(26, f.audioProperties()->length()); - CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->bitrate()); - CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); - CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); - } - - void testPropertiesSV4() - { - MPC::File f(TEST_FILE_PATH_C("sv4_header.mpc")); - CPPUNIT_ASSERT_EQUAL(4, f.audioProperties()->mpcVersion()); - CPPUNIT_ASSERT_EQUAL(26, f.audioProperties()->length()); - CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->bitrate()); - CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels()); - CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate()); - } - -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestMPC); diff --git a/taglib/tests/test_mpeg.cpp b/taglib/tests/test_mpeg.cpp deleted file mode 100644 index ad6acc4..0000000 --- a/taglib/tests/test_mpeg.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include <string> -#include <stdio.h> -#include <tstring.h> -#include <mpegfile.h> -#include <id3v2tag.h> -#include <cppunit/extensions/HelperMacros.h> -#include "utils.h" - -using namespace std; -using namespace TagLib; - -class TestMPEG : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestMPEG); - CPPUNIT_TEST(testVersion2DurationWithXingHeader); - CPPUNIT_TEST(testSaveID3v24); - CPPUNIT_TEST(testSaveID3v24WrongParam); - CPPUNIT_TEST(testSaveID3v23); - CPPUNIT_TEST_SUITE_END(); - -public: - - void testVersion2DurationWithXingHeader() - { - MPEG::File f(TEST_FILE_PATH_C("mpeg2.mp3")); - CPPUNIT_ASSERT_EQUAL(5387, f.audioProperties()->length()); - } - - void testSaveID3v24() - { - ScopedFileCopy copy("xing", ".mp3"); - string newname = copy.fileName(); - - String xxx = ByteVector(254, 'X'); - MPEG::File f(newname.c_str()); - CPPUNIT_ASSERT_EQUAL(false, f.hasID3v2Tag()); - - f.tag()->setTitle(xxx); - f.tag()->setArtist("Artist A"); - f.save(MPEG::File::AllTags, true, 4); - CPPUNIT_ASSERT_EQUAL(true, f.hasID3v2Tag()); - - MPEG::File f2(newname.c_str()); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(4), f2.ID3v2Tag()->header()->majorVersion()); - CPPUNIT_ASSERT_EQUAL(String("Artist A"), f2.tag()->artist()); - CPPUNIT_ASSERT_EQUAL(xxx, f2.tag()->title()); - } - - void testSaveID3v24WrongParam() - { - ScopedFileCopy copy("xing", ".mp3"); - string newname = copy.fileName(); - - String xxx = ByteVector(254, 'X'); - MPEG::File f(newname.c_str()); - f.tag()->setTitle(xxx); - f.tag()->setArtist("Artist A"); - f.save(MPEG::File::AllTags, true, 8); - - MPEG::File f2(newname.c_str()); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(4), f2.ID3v2Tag()->header()->majorVersion()); - CPPUNIT_ASSERT_EQUAL(String("Artist A"), f2.tag()->artist()); - CPPUNIT_ASSERT_EQUAL(xxx, f2.tag()->title()); - } - - void testSaveID3v23() - { - ScopedFileCopy copy("xing", ".mp3"); - string newname = copy.fileName(); - - String xxx = ByteVector(254, 'X'); - MPEG::File f(newname.c_str()); - CPPUNIT_ASSERT_EQUAL(false, f.hasID3v2Tag()); - - f.tag()->setTitle(xxx); - f.tag()->setArtist("Artist A"); - f.save(MPEG::File::AllTags, true, 3); - CPPUNIT_ASSERT_EQUAL(true, f.hasID3v2Tag()); - - MPEG::File f2(newname.c_str()); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(3), f2.ID3v2Tag()->header()->majorVersion()); - CPPUNIT_ASSERT_EQUAL(String("Artist A"), f2.tag()->artist()); - CPPUNIT_ASSERT_EQUAL(xxx, f2.tag()->title()); - } - -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestMPEG); diff --git a/taglib/tests/test_ogg.cpp b/taglib/tests/test_ogg.cpp deleted file mode 100644 index c89586a..0000000 --- a/taglib/tests/test_ogg.cpp +++ /dev/null @@ -1,104 +0,0 @@ -#include <string> -#include <stdio.h> -#include <tag.h> -#include <tstringlist.h> -#include <tbytevectorlist.h> -#include <tpropertymap.h> -#include <oggfile.h> -#include <vorbisfile.h> -#include <oggpageheader.h> -#include <cppunit/extensions/HelperMacros.h> -#include "utils.h" - -using namespace std; -using namespace TagLib; - -class TestOGG : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestOGG); - CPPUNIT_TEST(testSimple); - CPPUNIT_TEST(testSplitPackets); - CPPUNIT_TEST(testDictInterface1); - CPPUNIT_TEST(testDictInterface2); - CPPUNIT_TEST_SUITE_END(); - -public: - - void testSimple() - { - ScopedFileCopy copy("empty", ".ogg"); - string newname = copy.fileName(); - - Vorbis::File *f = new Vorbis::File(newname.c_str()); - f->tag()->setArtist("The Artist"); - f->save(); - delete f; - - f = new Vorbis::File(newname.c_str()); - CPPUNIT_ASSERT_EQUAL(String("The Artist"), f->tag()->artist()); - delete f; - } - - void testSplitPackets() - { - ScopedFileCopy copy("empty", ".ogg"); - string newname = copy.fileName(); - - Vorbis::File *f = new Vorbis::File(newname.c_str()); - f->tag()->addField("test", ByteVector(128 * 1024, 'x') + ByteVector(1, '\0')); - f->save(); - delete f; - - f = new Vorbis::File(newname.c_str()); - CPPUNIT_ASSERT_EQUAL(19, f->lastPageHeader()->pageSequenceNumber()); - delete f; - } - - void testDictInterface1() - { - ScopedFileCopy copy("empty", ".ogg"); - string newname = copy.fileName(); - - Vorbis::File *f = new Vorbis::File(newname.c_str()); - - CPPUNIT_ASSERT_EQUAL(TagLib::uint(0), f->tag()->properties().size()); - - PropertyMap newTags; - StringList values("value 1"); - values.append("value 2"); - newTags["ARTIST"] = values; - f->tag()->setProperties(newTags); - - PropertyMap map = f->tag()->properties(); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), map.size()); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), map["ARTIST"].size()); - CPPUNIT_ASSERT_EQUAL(String("value 1"), map["ARTIST"][0]); - delete f; - - } - - void testDictInterface2() - { - ScopedFileCopy copy("test", ".ogg"); - string newname = copy.fileName(); - - Vorbis::File *f = new Vorbis::File(newname.c_str()); - PropertyMap tags = f->tag()->properties(); - - CPPUNIT_ASSERT_EQUAL(TagLib::uint(2), tags["UNUSUALTAG"].size()); - CPPUNIT_ASSERT_EQUAL(String("usual value"), tags["UNUSUALTAG"][0]); - CPPUNIT_ASSERT_EQUAL(String("another value"), tags["UNUSUALTAG"][1]); - CPPUNIT_ASSERT_EQUAL(String("öäüoΣø", String::UTF8), tags["UNICODETAG"][0]); - - tags["UNICODETAG"][0] = String("νεω ναλυε", String::UTF8); - tags.erase("UNUSUALTAG"); - f->tag()->setProperties(tags); - CPPUNIT_ASSERT_EQUAL(String("νεω ναλυε", String::UTF8), f->tag()->properties()["UNICODETAG"][0]); - CPPUNIT_ASSERT_EQUAL(false, f->tag()->properties().contains("UNUSUALTAG")); - - delete f; - } - -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestOGG); diff --git a/taglib/tests/test_oggflac.cpp b/taglib/tests/test_oggflac.cpp deleted file mode 100644 index 1cdb24b..0000000 --- a/taglib/tests/test_oggflac.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include <string> -#include <stdio.h> -#include <tag.h> -#include <tstringlist.h> -#include <tbytevectorlist.h> -#include <oggfile.h> -#include <oggflacfile.h> -#include <cppunit/extensions/HelperMacros.h> -#include "utils.h" - -using namespace std; -using namespace TagLib; - -class TestOggFLAC : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestOggFLAC); - CPPUNIT_TEST(testFramingBit); - CPPUNIT_TEST_SUITE_END(); - -public: - - void testFramingBit() - { - ScopedFileCopy copy("empty_flac", ".oga"); - string newname = copy.fileName(); - - Ogg::FLAC::File *f = new Ogg::FLAC::File(newname.c_str()); - f->tag()->setArtist("The Artist"); - f->save(); - delete f; - - f = new Ogg::FLAC::File(newname.c_str()); - CPPUNIT_ASSERT_EQUAL(String("The Artist"), f->tag()->artist()); - - f->seek(0, File::End); - int size = f->tell(); - CPPUNIT_ASSERT_EQUAL(9134, size); - - delete f; - } - -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestOggFLAC); diff --git a/taglib/tests/test_opus.cpp b/taglib/tests/test_opus.cpp deleted file mode 100644 index 769d398..0000000 --- a/taglib/tests/test_opus.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include <string> -#include <stdio.h> -#include <tag.h> -#include <tbytevectorlist.h> -#include <opusfile.h> -#include <cppunit/extensions/HelperMacros.h> -#include "utils.h" - -using namespace std; -using namespace TagLib; - -class TestOpus : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestOpus); - CPPUNIT_TEST(testProperties); - CPPUNIT_TEST(testReadComments); - CPPUNIT_TEST(testWriteComments); - CPPUNIT_TEST_SUITE_END(); - -public: - - void testProperties() - { - Ogg::Opus::File f(TEST_FILE_PATH_C("correctness_gain_silent_output.opus")); - CPPUNIT_ASSERT_EQUAL(7, f.audioProperties()->length()); - CPPUNIT_ASSERT_EQUAL(0, f.audioProperties()->bitrate()); - CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->channels()); - CPPUNIT_ASSERT_EQUAL(48000, f.audioProperties()->sampleRate()); - CPPUNIT_ASSERT_EQUAL(48000, ((Ogg::Opus::Properties *)f.audioProperties())->inputSampleRate()); - } - - void testReadComments() - { - Ogg::Opus::File f(TEST_FILE_PATH_C("correctness_gain_silent_output.opus")); - CPPUNIT_ASSERT_EQUAL(StringList("Xiph.Org Opus testvectormaker"), f.tag()->fieldListMap()["ENCODER"]); - CPPUNIT_ASSERT(f.tag()->fieldListMap().contains("TESTDESCRIPTION")); - CPPUNIT_ASSERT(!f.tag()->fieldListMap().contains("ARTIST")); - CPPUNIT_ASSERT_EQUAL(String("libopus 0.9.11-66-g64c2dd7"), f.tag()->vendorID()); - } - - void testWriteComments() - { - ScopedFileCopy copy("correctness_gain_silent_output", ".opus"); - string filename = copy.fileName(); - - Ogg::Opus::File *f = new Ogg::Opus::File(filename.c_str()); - f->tag()->setArtist("Your Tester"); - f->save(); - delete f; - - f = new Ogg::Opus::File(filename.c_str()); - CPPUNIT_ASSERT_EQUAL(StringList("Xiph.Org Opus testvectormaker"), f->tag()->fieldListMap()["ENCODER"]); - CPPUNIT_ASSERT(f->tag()->fieldListMap().contains("TESTDESCRIPTION")); - CPPUNIT_ASSERT_EQUAL(StringList("Your Tester"), f->tag()->fieldListMap()["ARTIST"]); - CPPUNIT_ASSERT_EQUAL(String("libopus 0.9.11-66-g64c2dd7"), f->tag()->vendorID()); - delete f; - } - -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestOpus); diff --git a/taglib/tests/test_propertymap.cpp b/taglib/tests/test_propertymap.cpp deleted file mode 100644 index d0b2fbb..0000000 --- a/taglib/tests/test_propertymap.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include <cppunit/extensions/HelperMacros.h> -#include <tpropertymap.h> -class TestPropertyMap : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestPropertyMap); - CPPUNIT_TEST(testInvalidKeys); - CPPUNIT_TEST_SUITE_END(); - -public: - void testInvalidKeys() - { - TagLib::PropertyMap map1; - CPPUNIT_ASSERT(map1.isEmpty()); - map1["ÄÖÜ"].append("test"); - CPPUNIT_ASSERT_EQUAL(map1.size(), 1u); - - TagLib::PropertyMap map2; - map2["ÄÖÜ"].append("test"); - CPPUNIT_ASSERT(map1 == map2); - CPPUNIT_ASSERT(map1.contains(map2)); - - map2["ARTIST"] = TagLib::String("Test Artist"); - CPPUNIT_ASSERT(map1 != map2); - CPPUNIT_ASSERT(map2.contains(map1)); - - map2["ÄÖÜ"].append("test 2"); - CPPUNIT_ASSERT(!map2.contains(map1)); - - } -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestPropertyMap); diff --git a/taglib/tests/test_riff.cpp b/taglib/tests/test_riff.cpp deleted file mode 100644 index 8e120d0..0000000 --- a/taglib/tests/test_riff.cpp +++ /dev/null @@ -1,198 +0,0 @@ -#include <string> -#include <stdio.h> -#include <tag.h> -#include <tbytevectorlist.h> -#include <rifffile.h> -#include <cppunit/extensions/HelperMacros.h> -#include "utils.h" - -using namespace std; -using namespace TagLib; - -class PublicRIFF : public RIFF::File -{ -public: - PublicRIFF(FileName file) : RIFF::File(file, BigEndian) {}; - TagLib::uint riffSize() { return RIFF::File::riffSize(); }; - TagLib::uint chunkCount() { return RIFF::File::chunkCount(); }; - TagLib::uint chunkOffset(TagLib::uint i) { return RIFF::File::chunkOffset(i); }; - TagLib::uint chunkPadding(TagLib::uint i) { return RIFF::File::chunkPadding(i); }; - TagLib::uint chunkDataSize(TagLib::uint i) { return RIFF::File::chunkDataSize(i); }; - ByteVector chunkName(TagLib::uint i) { return RIFF::File::chunkName(i); }; - ByteVector chunkData(TagLib::uint i) { return RIFF::File::chunkData(i); }; - void setChunkData(const ByteVector &name, const ByteVector &data) { - RIFF::File::setChunkData(name, data); - }; - virtual TagLib::Tag* tag() const { return 0; }; - virtual TagLib::AudioProperties* audioProperties() const { return 0;}; - virtual bool save() { return false; }; -}; - -class TestRIFF : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestRIFF); - CPPUNIT_TEST(testPadding); - CPPUNIT_TEST(testLastChunkAtEvenPosition); - CPPUNIT_TEST(testLastChunkAtEvenPosition2); - CPPUNIT_TEST(testLastChunkAtEvenPosition3); - CPPUNIT_TEST_SUITE_END(); - -public: - - void testPadding() - { - ScopedFileCopy copy("empty", ".aiff"); - string filename = copy.fileName(); - - PublicRIFF *f = new PublicRIFF(filename.c_str()); - CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f->chunkName(2)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(0x1728 + 8), f->chunkOffset(2)); - - f->setChunkData("TEST", "foo"); - delete f; - - f = new PublicRIFF(filename.c_str()); - CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f->chunkName(2)); - CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), f->chunkData(2)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(3), f->chunkDataSize(2)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(0x1728 + 8), f->chunkOffset(2)); - - f->setChunkData("SSND", "abcd"); - - CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(1)); - CPPUNIT_ASSERT_EQUAL(ByteVector("abcd"), f->chunkData(1)); - - f->seek(f->chunkOffset(1)); - CPPUNIT_ASSERT_EQUAL(ByteVector("abcd"), f->readBlock(4)); - - CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f->chunkName(2)); - CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), f->chunkData(2)); - - f->seek(f->chunkOffset(2)); - CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), f->readBlock(3)); - - delete f; - - f = new PublicRIFF(filename.c_str()); - - CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(1)); - CPPUNIT_ASSERT_EQUAL(ByteVector("abcd"), f->chunkData(1)); - - CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f->chunkName(2)); - CPPUNIT_ASSERT_EQUAL(ByteVector("foo"), f->chunkData(2)); - } - - void testLastChunkAtEvenPosition() - { - ScopedFileCopy copy("noise", ".aif"); - string filename = copy.fileName(); - - PublicRIFF *f = new PublicRIFF(filename.c_str()); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(0xff0 + 8), f->chunkOffset(2)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(311), f->chunkDataSize(2)); - CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(2)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), f->chunkPadding(2)); - CPPUNIT_ASSERT_EQUAL(long(4400), f->length()); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(4399 - 8), f->riffSize()); - f->setChunkData("TEST", "abcd"); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(4088), f->chunkOffset(2)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(311), f->chunkDataSize(2)); - CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(2)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), f->chunkPadding(2)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(4408), f->chunkOffset(3)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(4), f->chunkDataSize(3)); - CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f->chunkName(3)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(0), f->chunkPadding(3)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(4412 - 8), f->riffSize()); - delete f; - - f = new PublicRIFF(filename.c_str()); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(4088), f->chunkOffset(2)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(311), f->chunkDataSize(2)); - CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(2)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), f->chunkPadding(2)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(4408), f->chunkOffset(3)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(4), f->chunkDataSize(3)); - CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f->chunkName(3)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(0), f->chunkPadding(3)); - CPPUNIT_ASSERT_EQUAL(long(4412), f->length()); - delete f; - } - - void testLastChunkAtEvenPosition2() - { - ScopedFileCopy copy("noise_odd", ".aif"); - string filename = copy.fileName(); - - PublicRIFF *f = new PublicRIFF(filename.c_str()); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(0xff0 + 8), f->chunkOffset(2)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(311), f->chunkDataSize(2)); - CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(2)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(0), f->chunkPadding(2)); - CPPUNIT_ASSERT_EQUAL(long(4399), f->length()); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(4399 - 8), f->riffSize()); - f->setChunkData("TEST", "abcd"); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(4088), f->chunkOffset(2)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(311), f->chunkDataSize(2)); - CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(2)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), f->chunkPadding(2)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(4408), f->chunkOffset(3)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(4), f->chunkDataSize(3)); - CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f->chunkName(3)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(0), f->chunkPadding(3)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(4412 - 8), f->riffSize()); - delete f; - - f = new PublicRIFF(filename.c_str()); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(4088), f->chunkOffset(2)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(311), f->chunkDataSize(2)); - CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(2)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), f->chunkPadding(2)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(4408), f->chunkOffset(3)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(4), f->chunkDataSize(3)); - CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f->chunkName(3)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(0), f->chunkPadding(3)); - CPPUNIT_ASSERT_EQUAL(long(4412), f->length()); - delete f; - } - - void testLastChunkAtEvenPosition3() - { - ScopedFileCopy copy("noise_odd", ".aif"); - string filename = copy.fileName(); - - PublicRIFF *f = new PublicRIFF(filename.c_str()); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(0xff0 + 8), f->chunkOffset(2)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(311), f->chunkDataSize(2)); - CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(2)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(0), f->chunkPadding(2)); - CPPUNIT_ASSERT_EQUAL(long(4399), f->length()); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(4399 - 8), f->riffSize()); - f->setChunkData("TEST", "abc"); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(4088), f->chunkOffset(2)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(311), f->chunkDataSize(2)); - CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(2)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), f->chunkPadding(2)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(4408), f->chunkOffset(3)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(3), f->chunkDataSize(3)); - CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f->chunkName(3)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), f->chunkPadding(3)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(4411 - 8), f->riffSize()); - delete f; - - f = new PublicRIFF(filename.c_str()); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(4088), f->chunkOffset(2)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(311), f->chunkDataSize(2)); - CPPUNIT_ASSERT_EQUAL(ByteVector("SSND"), f->chunkName(2)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), f->chunkPadding(2)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(4408), f->chunkOffset(3)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(3), f->chunkDataSize(3)); - CPPUNIT_ASSERT_EQUAL(ByteVector("TEST"), f->chunkName(3)); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(1), f->chunkPadding(3)); - CPPUNIT_ASSERT_EQUAL(long(4412), f->length()); - delete f; - } - -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestRIFF); diff --git a/taglib/tests/test_s3m.cpp b/taglib/tests/test_s3m.cpp deleted file mode 100644 index 24a4c6e..0000000 --- a/taglib/tests/test_s3m.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/*************************************************************************** - copyright : (C) 2011 by Mathias Panzenböck - email : grosser.meister.morti@gmx.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * - ***************************************************************************/ - -#include <s3mfile.h> -#include <cppunit/extensions/HelperMacros.h> -#include "utils.h" - -using namespace std; -using namespace TagLib; - -static const String titleBefore("test song name"); -static const String titleAfter("changed title"); - -static const String commentBefore( - "This is an instrument name.\n" - "Module file formats\n" - "abuse instrument names\n" - "as multiline comments.\n" - " "); - -static const String newComment( - "This is an instrument name!\n" - "Module file formats\n" - "abuse instrument names\n" - "as multiline comments.\n" - "-----------------------------------\n" - "This line will be dropped and the previous is truncated."); - -static const String commentAfter( - "This is an instrument name!\n" - "Module file formats\n" - "abuse instrument names\n" - "as multiline comments.\n" - "---------------------------"); - -class TestS3M : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestS3M); - CPPUNIT_TEST(testReadTags); - CPPUNIT_TEST(testWriteTags); - CPPUNIT_TEST_SUITE_END(); - -public: - void testReadTags() - { - testRead(TEST_FILE_PATH_C("test.s3m"), titleBefore, commentBefore); - } - - void testWriteTags() - { - ScopedFileCopy copy("test", ".s3m"); - { - S3M::File file(copy.fileName().c_str()); - CPPUNIT_ASSERT(file.tag() != 0); - file.tag()->setTitle(titleAfter); - file.tag()->setComment(newComment); - file.tag()->setTrackerName("won't be saved"); - CPPUNIT_ASSERT(file.save()); - } - testRead(copy.fileName().c_str(), titleAfter, commentAfter); - CPPUNIT_ASSERT(fileEqual( - copy.fileName(), - TEST_FILE_PATH_C("changed.s3m"))); - } - -private: - void testRead(FileName fileName, const String &title, const String &comment) - { - S3M::File file(fileName); - - CPPUNIT_ASSERT(file.isValid()); - - S3M::Properties *p = file.audioProperties(); - Mod::Tag *t = file.tag(); - - CPPUNIT_ASSERT(0 != p); - CPPUNIT_ASSERT(0 != t); - - CPPUNIT_ASSERT_EQUAL( 0, p->length()); - CPPUNIT_ASSERT_EQUAL( 0, p->bitrate()); - CPPUNIT_ASSERT_EQUAL( 0, p->sampleRate()); - CPPUNIT_ASSERT_EQUAL(16, p->channels()); - CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 0, p->lengthInPatterns()); - CPPUNIT_ASSERT_EQUAL(false, p->stereo()); - CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 5, p->sampleCount()); - CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 1, p->patternCount()); - CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 0, p->flags()); - CPPUNIT_ASSERT_EQUAL((TagLib::ushort)4896, p->trackerVersion()); - CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 2, p->fileFormatVersion()); - CPPUNIT_ASSERT_EQUAL((TagLib::uchar) 64, p->globalVolume()); - CPPUNIT_ASSERT_EQUAL((TagLib::uchar) 48, p->masterVolume()); - CPPUNIT_ASSERT_EQUAL((TagLib::uchar)125, p->tempo()); - CPPUNIT_ASSERT_EQUAL((TagLib::uchar) 6, p->bpmSpeed()); - CPPUNIT_ASSERT_EQUAL(title, t->title()); - CPPUNIT_ASSERT_EQUAL(String::null, t->artist()); - CPPUNIT_ASSERT_EQUAL(String::null, t->album()); - CPPUNIT_ASSERT_EQUAL(comment, t->comment()); - CPPUNIT_ASSERT_EQUAL(String::null, t->genre()); - CPPUNIT_ASSERT_EQUAL(0U, t->year()); - CPPUNIT_ASSERT_EQUAL(0U, t->track()); - CPPUNIT_ASSERT_EQUAL(String("ScreamTracker III"), t->trackerName()); - } -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestS3M); diff --git a/taglib/tests/test_string.cpp b/taglib/tests/test_string.cpp deleted file mode 100644 index a815a0b..0000000 --- a/taglib/tests/test_string.cpp +++ /dev/null @@ -1,233 +0,0 @@ -/* Copyright (C) 2003 Scott Wheeler <wheeler@kde.org> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <tstring.h> -#include <string.h> -#include <cppunit/extensions/HelperMacros.h> - -using namespace std; -using namespace TagLib; - -class TestString : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestString); - CPPUNIT_TEST(testString); - CPPUNIT_TEST(testRfind); - CPPUNIT_TEST(testUTF16Encode); - CPPUNIT_TEST(testUTF16Decode); - CPPUNIT_TEST(testUTF16DecodeInvalidBOM); - CPPUNIT_TEST(testUTF16DecodeEmptyWithBOM); - CPPUNIT_TEST(testAppendCharDetach); - CPPUNIT_TEST(testAppendStringDetach); - CPPUNIT_TEST(testToInt); - CPPUNIT_TEST(testSubstr); - CPPUNIT_TEST(testNewline); - CPPUNIT_TEST_SUITE_END(); - -public: - - void testString() - { - String s = "taglib string"; - ByteVector v = "taglib string"; - CPPUNIT_ASSERT(v == s.data(String::Latin1)); - - char str[] = "taglib string"; - CPPUNIT_ASSERT(strcmp(s.toCString(), str) == 0); - - String unicode("José Carlos", String::UTF8); - CPPUNIT_ASSERT(strcmp(unicode.toCString(), "Jos\xe9 Carlos") == 0); - - String latin = "Jos\xe9 Carlos"; - CPPUNIT_ASSERT(strcmp(latin.toCString(true), "José Carlos") == 0); - - String c; - c = "1"; - CPPUNIT_ASSERT(c == L"1"); - - c = L'\u4E00'; - CPPUNIT_ASSERT(c == L"\u4E00"); - - String unicode2(unicode.to8Bit(true), String::UTF8); - CPPUNIT_ASSERT(unicode == unicode2); - - String unicode3(L"\u65E5\u672C\u8A9E"); - CPPUNIT_ASSERT(*(unicode3.toCWString() + 1) == L'\u672C'); - - CPPUNIT_ASSERT(strcmp(String::number(0).toCString(), "0") == 0); - CPPUNIT_ASSERT(strcmp(String::number(12345678).toCString(), "12345678") == 0); - CPPUNIT_ASSERT(strcmp(String::number(-12345678).toCString(), "-12345678") == 0); - - String n = "123"; - CPPUNIT_ASSERT(n.toInt() == 123); - - n = "-123"; - CPPUNIT_ASSERT(n.toInt() == -123); - - CPPUNIT_ASSERT(String("0").toInt() == 0); - CPPUNIT_ASSERT(String("1").toInt() == 1); - - CPPUNIT_ASSERT(String(" foo ").stripWhiteSpace() == String("foo")); - CPPUNIT_ASSERT(String("foo ").stripWhiteSpace() == String("foo")); - CPPUNIT_ASSERT(String(" foo").stripWhiteSpace() == String("foo")); - - CPPUNIT_ASSERT(memcmp(String("foo").data(String::Latin1).data(), "foo", 3) == 0); - CPPUNIT_ASSERT(memcmp(String("f").data(String::Latin1).data(), "f", 1) == 0); - - ByteVector utf16 = unicode.data(String::UTF16); - - // Check to make sure that the BOM is there and that the data size is correct - - CPPUNIT_ASSERT(utf16.size() == 2 + (unicode.size() * 2)); - - CPPUNIT_ASSERT(unicode == String(utf16, String::UTF16)); - } - - void testUTF16Encode() - { - String a("foo"); - ByteVector b("\0f\0o\0o", 6); - ByteVector c("f\0o\0o\0", 6); - ByteVector d("\377\376f\0o\0o\0", 8); - CPPUNIT_ASSERT(a.data(String::UTF16BE) != a.data(String::UTF16LE)); - CPPUNIT_ASSERT(b == a.data(String::UTF16BE)); - CPPUNIT_ASSERT(c == a.data(String::UTF16LE)); - CPPUNIT_ASSERT_EQUAL(d, a.data(String::UTF16)); - } - - void testUTF16Decode() - { - String a("foo"); - ByteVector b("\0f\0o\0o", 6); - ByteVector c("f\0o\0o\0", 6); - ByteVector d("\377\376f\0o\0o\0", 8); - CPPUNIT_ASSERT_EQUAL(a, String(b, String::UTF16BE)); - CPPUNIT_ASSERT_EQUAL(a, String(c, String::UTF16LE)); - CPPUNIT_ASSERT_EQUAL(a, String(d, String::UTF16)); - } - - // this test is expected to print "TagLib: String::prepare() - - // Invalid UTF16 string." on the console 3 times - void testUTF16DecodeInvalidBOM() - { - ByteVector b(" ", 1); - ByteVector c(" ", 2); - ByteVector d(" \0f\0o\0o", 8); - CPPUNIT_ASSERT_EQUAL(String(), String(b, String::UTF16)); - CPPUNIT_ASSERT_EQUAL(String(), String(c, String::UTF16)); - CPPUNIT_ASSERT_EQUAL(String(), String(d, String::UTF16)); - } - - void testUTF16DecodeEmptyWithBOM() - { - ByteVector a("\377\376", 2); - ByteVector b("\376\377", 2); - CPPUNIT_ASSERT_EQUAL(String(), String(a, String::UTF16)); - CPPUNIT_ASSERT_EQUAL(String(), String(b, String::UTF16)); - } - - void testAppendStringDetach() - { - String a("a"); - String b = a; - a += "b"; - CPPUNIT_ASSERT_EQUAL(String("ab"), a); - CPPUNIT_ASSERT_EQUAL(String("a"), b); - } - - void testAppendCharDetach() - { - String a("a"); - String b = a; - a += 'b'; - CPPUNIT_ASSERT_EQUAL(String("ab"), a); - CPPUNIT_ASSERT_EQUAL(String("a"), b); - } - - void testRfind() - { - CPPUNIT_ASSERT_EQUAL(-1, String("foo.bar").rfind(".", 0)); - CPPUNIT_ASSERT_EQUAL(-1, String("foo.bar").rfind(".", 1)); - CPPUNIT_ASSERT_EQUAL(-1, String("foo.bar").rfind(".", 2)); - CPPUNIT_ASSERT_EQUAL(3, String("foo.bar").rfind(".", 3)); - CPPUNIT_ASSERT_EQUAL(3, String("foo.bar").rfind(".", 4)); - CPPUNIT_ASSERT_EQUAL(3, String("foo.bar").rfind(".", 5)); - CPPUNIT_ASSERT_EQUAL(3, String("foo.bar").rfind(".", 6)); - CPPUNIT_ASSERT_EQUAL(3, String("foo.bar").rfind(".", 7)); - CPPUNIT_ASSERT_EQUAL(3, String("foo.bar").rfind(".")); - } - - void testToInt() - { - bool ok; - CPPUNIT_ASSERT_EQUAL(String("123").toInt(&ok), 123); - CPPUNIT_ASSERT_EQUAL(ok, true); - - CPPUNIT_ASSERT_EQUAL(String("-123").toInt(&ok), -123); - CPPUNIT_ASSERT_EQUAL(ok, true); - - CPPUNIT_ASSERT_EQUAL(String("abc").toInt(&ok), 0); - CPPUNIT_ASSERT_EQUAL(ok, false); - - CPPUNIT_ASSERT_EQUAL(String("1x").toInt(&ok), 1); - CPPUNIT_ASSERT_EQUAL(ok, false); - - CPPUNIT_ASSERT_EQUAL(String("").toInt(&ok), 0); - CPPUNIT_ASSERT_EQUAL(ok, false); - - CPPUNIT_ASSERT_EQUAL(String("-").toInt(&ok), 0); - CPPUNIT_ASSERT_EQUAL(ok, false); - - CPPUNIT_ASSERT_EQUAL(String("123").toInt(), 123); - CPPUNIT_ASSERT_EQUAL(String("-123").toInt(), -123); - CPPUNIT_ASSERT_EQUAL(String("123aa").toInt(), 123); - CPPUNIT_ASSERT_EQUAL(String("-123aa").toInt(), -123); - } - - void testSubstr() - { - CPPUNIT_ASSERT_EQUAL(String("01"), String("0123456").substr(0, 2)); - CPPUNIT_ASSERT_EQUAL(String("12"), String("0123456").substr(1, 2)); - CPPUNIT_ASSERT_EQUAL(String("123456"), String("0123456").substr(1, 200)); - } - - void testNewline() - { - ByteVector cr("abc\x0dxyz", 7); - ByteVector lf("abc\x0axyz", 7); - ByteVector crlf("abc\x0d\x0axyz", 8); - - CPPUNIT_ASSERT_EQUAL(uint(7), String(cr).size()); - CPPUNIT_ASSERT_EQUAL(uint(7), String(lf).size()); - CPPUNIT_ASSERT_EQUAL(uint(8), String(crlf).size()); - - CPPUNIT_ASSERT_EQUAL(L'\x0d', String(cr)[3]); - CPPUNIT_ASSERT_EQUAL(L'\x0a', String(lf)[3]); - CPPUNIT_ASSERT_EQUAL(L'\x0d', String(crlf)[3]); - CPPUNIT_ASSERT_EQUAL(L'\x0a', String(crlf)[4]); - } - -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestString); diff --git a/taglib/tests/test_synchdata.cpp b/taglib/tests/test_synchdata.cpp deleted file mode 100644 index 2e3021e..0000000 --- a/taglib/tests/test_synchdata.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* Copyright (C) 2003 Scott Wheeler <wheeler@kde.org> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <id3v2synchdata.h> -#include <cppunit/extensions/HelperMacros.h> - -using namespace std; -using namespace TagLib; - -class TestID3v2SynchData : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestID3v2SynchData); - CPPUNIT_TEST(test1); - CPPUNIT_TEST(test2); - CPPUNIT_TEST(test3); - CPPUNIT_TEST(testToUIntBroken); - CPPUNIT_TEST(testToUIntBrokenAndTooLarge); - CPPUNIT_TEST(testDecode1); - CPPUNIT_TEST(testDecode2); - CPPUNIT_TEST_SUITE_END(); - -public: - - void test1() - { - char data[] = { 0, 0, 0, 127 }; - ByteVector v(data, 4); - - CPPUNIT_ASSERT_EQUAL(ID3v2::SynchData::toUInt(v), TagLib::uint(127)); - CPPUNIT_ASSERT_EQUAL(ID3v2::SynchData::fromUInt(127), v); - } - - void test2() - { - char data[] = { 0, 0, 1, 0 }; - ByteVector v(data, 4); - - CPPUNIT_ASSERT_EQUAL(ID3v2::SynchData::toUInt(v), TagLib::uint(128)); - CPPUNIT_ASSERT_EQUAL(ID3v2::SynchData::fromUInt(128), v); - } - - void test3() - { - char data[] = { 0, 0, 1, 1 }; - ByteVector v(data, 4); - - CPPUNIT_ASSERT_EQUAL(ID3v2::SynchData::toUInt(v), TagLib::uint(129)); - CPPUNIT_ASSERT_EQUAL(ID3v2::SynchData::fromUInt(129), v); - } - - void testToUIntBroken() - { - char data[] = { 0, 0, 0, -1 }; - char data2[] = { 0, 0, -1, -1 }; - - CPPUNIT_ASSERT_EQUAL(TagLib::uint(255), ID3v2::SynchData::toUInt(ByteVector(data, 4))); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(65535), ID3v2::SynchData::toUInt(ByteVector(data2, 4))); - } - - void testToUIntBrokenAndTooLarge() - { - char data[] = { 0, 0, 0, -1, 0 }; - ByteVector v(data, 5); - - CPPUNIT_ASSERT_EQUAL(TagLib::uint(255), ID3v2::SynchData::toUInt(v)); - } - - void testDecode1() - { - ByteVector a("\xff\x00\x00", 3); - a = ID3v2::SynchData::decode(a); - CPPUNIT_ASSERT_EQUAL((unsigned int)2, a.size()); - CPPUNIT_ASSERT_EQUAL(ByteVector("\xff\x00", 2), a); - } - - void testDecode2() - { - ByteVector a("\xff\x44", 2); - a = ID3v2::SynchData::decode(a); - CPPUNIT_ASSERT_EQUAL((unsigned int)2, a.size()); - CPPUNIT_ASSERT_EQUAL(ByteVector("\xff\x44", 2), a); - } - -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestID3v2SynchData); diff --git a/taglib/tests/test_trueaudio.cpp b/taglib/tests/test_trueaudio.cpp deleted file mode 100644 index 5ff114c..0000000 --- a/taglib/tests/test_trueaudio.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include <cppunit/extensions/HelperMacros.h> -#include <string> -#include <stdio.h> -#include <trueaudiofile.h> -#include "utils.h" - -using namespace std; -using namespace TagLib; - -class TestTrueAudio : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestTrueAudio); - CPPUNIT_TEST(testReadPropertiesWithoutID3v2); - CPPUNIT_TEST_SUITE_END(); - -public: - - void testReadPropertiesWithoutID3v2() - { - TrueAudio::File f(TEST_FILE_PATH_C("empty.tta")); - CPPUNIT_ASSERT(f.audioProperties()); - CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->length()); - } - -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestTrueAudio); diff --git a/taglib/tests/test_wav.cpp b/taglib/tests/test_wav.cpp deleted file mode 100644 index d17ce2c..0000000 --- a/taglib/tests/test_wav.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include <cppunit/extensions/HelperMacros.h> -#include <string> -#include <stdio.h> -#include <tag.h> -#include <tbytevectorlist.h> -#include <wavfile.h> -#include "utils.h" - -using namespace std; -using namespace TagLib; - -class TestWAV : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestWAV); - CPPUNIT_TEST(testLength); - CPPUNIT_TEST(testZeroSizeDataChunk); - CPPUNIT_TEST_SUITE_END(); - -public: - - void testLength() - { - RIFF::WAV::File f(TEST_FILE_PATH_C("empty.wav")); - CPPUNIT_ASSERT_EQUAL(true, f.isValid()); - CPPUNIT_ASSERT_EQUAL(3, f.audioProperties()->length()); - } - - void testZeroSizeDataChunk() - { - RIFF::WAV::File f(TEST_FILE_PATH_C("zero-size-chunk.wav")); - CPPUNIT_ASSERT_EQUAL(false, f.isValid()); - } - -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestWAV); diff --git a/taglib/tests/test_wavpack.cpp b/taglib/tests/test_wavpack.cpp deleted file mode 100644 index 085fa2d..0000000 --- a/taglib/tests/test_wavpack.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include <cppunit/extensions/HelperMacros.h> -#include <string> -#include <stdio.h> -#include <tag.h> -#include <tbytevectorlist.h> -#include <wavpackfile.h> -#include "utils.h" - -using namespace std; -using namespace TagLib; - -class TestWavPack : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestWavPack); - CPPUNIT_TEST(testBasic); - CPPUNIT_TEST(testLengthScan); - CPPUNIT_TEST_SUITE_END(); - -public: - - void testBasic() - { - WavPack::File f(TEST_FILE_PATH_C("no_length.wv")); - WavPack::Properties *props = f.audioProperties(); - CPPUNIT_ASSERT_EQUAL(44100, props->sampleRate()); - CPPUNIT_ASSERT_EQUAL(2, props->channels()); - CPPUNIT_ASSERT_EQUAL(1, props->bitrate()); - CPPUNIT_ASSERT_EQUAL(0x407, props->version()); - } - - void testLengthScan() - { - WavPack::File f(TEST_FILE_PATH_C("no_length.wv")); - WavPack::Properties *props = f.audioProperties(); - CPPUNIT_ASSERT_EQUAL(4, props->length()); - } - -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestWavPack); diff --git a/taglib/tests/test_xiphcomment.cpp b/taglib/tests/test_xiphcomment.cpp deleted file mode 100644 index 6526229..0000000 --- a/taglib/tests/test_xiphcomment.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include <string> -#include <stdio.h> -#include <xiphcomment.h> -#include <tpropertymap.h> -#include <tdebug.h> -#include <cppunit/extensions/HelperMacros.h> -#include "utils.h" - -using namespace std; -using namespace TagLib; - -class TestXiphComment : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestXiphComment); - CPPUNIT_TEST(testYear); - CPPUNIT_TEST(testSetYear); - CPPUNIT_TEST(testTrack); - CPPUNIT_TEST(testSetTrack); - CPPUNIT_TEST(testInvalidKeys); - CPPUNIT_TEST_SUITE_END(); - -public: - - void testYear() - { - Ogg::XiphComment cmt; - CPPUNIT_ASSERT_EQUAL(TagLib::uint(0), cmt.year()); - cmt.addField("YEAR", "2009"); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(2009), cmt.year()); - cmt.addField("DATE", "2008"); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(2008), cmt.year()); - } - - void testSetYear() - { - Ogg::XiphComment cmt; - cmt.addField("YEAR", "2009"); - cmt.addField("DATE", "2008"); - cmt.setYear(1995); - CPPUNIT_ASSERT(cmt.fieldListMap()["YEAR"].isEmpty()); - CPPUNIT_ASSERT_EQUAL(String("1995"), cmt.fieldListMap()["DATE"].front()); - } - - void testTrack() - { - Ogg::XiphComment cmt; - CPPUNIT_ASSERT_EQUAL(TagLib::uint(0), cmt.track()); - cmt.addField("TRACKNUM", "7"); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(7), cmt.track()); - cmt.addField("TRACKNUMBER", "8"); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(8), cmt.track()); - } - - void testSetTrack() - { - Ogg::XiphComment cmt; - cmt.addField("TRACKNUM", "7"); - cmt.addField("TRACKNUMBER", "8"); - cmt.setTrack(3); - CPPUNIT_ASSERT(cmt.fieldListMap()["TRACKNUM"].isEmpty()); - CPPUNIT_ASSERT_EQUAL(String("3"), cmt.fieldListMap()["TRACKNUMBER"].front()); - } - - void testInvalidKeys() - { - PropertyMap map; - map[""] = String("invalid key: empty string"); - map["A=B"] = String("invalid key: contains '='"); - map["A~B"] = String("invalid key: contains '~'"); - - Ogg::XiphComment cmt; - PropertyMap unsuccessful = cmt.setProperties(map); - CPPUNIT_ASSERT_EQUAL(TagLib::uint(3), unsuccessful.size()); - CPPUNIT_ASSERT(cmt.properties().isEmpty()); - } - -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestXiphComment); diff --git a/taglib/tests/test_xm.cpp b/taglib/tests/test_xm.cpp deleted file mode 100644 index 2808653..0000000 --- a/taglib/tests/test_xm.cpp +++ /dev/null @@ -1,216 +0,0 @@ -/*************************************************************************** - copyright : (C) 2011 by Mathias Panzenböck - email : grosser.meister.morti@gmx.net - ***************************************************************************/ - -/*************************************************************************** - * This library is free software; you can redistribute it and/or modify * - * it under the terms of the GNU Lesser General Public License version * - * 2.1 as published by the Free Software Foundation. * - * * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * - * MA 02110-1301 USA * - ***************************************************************************/ - -#include <xmfile.h> -#include <cppunit/extensions/HelperMacros.h> -#include "utils.h" - -using namespace std; -using namespace TagLib; - -static const String titleBefore("title of song"); -static const String titleAfter("changed title"); - -static const String trackerNameBefore("MilkyTracker "); -static const String trackerNameAfter("TagLib"); - -static const String commentBefore( - "Instrument names\n" - "are abused as\n" - "comments in\n" - "module file formats.\n" - "-+-+-+-+-+-+-+-+-+-+-+\n" - "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - "\n\n\n" - "Sample\n" - "names\n" - "are sometimes\n" - "also abused as\n" - "comments."); - -static const String newCommentShort( - "Instrument names\n" - "are abused as\n" - "comments in\n" - "module file formats.\n" - "======================\n" - "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - "\n\n\n" - "Sample names\n" - "are sometimes\n" - "also abused as\n" - "comments."); - -static const String newCommentLong( - "Instrument names\n" - "are abused as\n" - "comments in\n" - "module file formats.\n" - "======================\n" - "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - "\n\n\n" - "Sample names\n" - "are sometimes\n" - "also abused as\n" - "comments.\n" - "\n\n\n\n\n\n\n" - "TEST"); - -static const String commentAfter( - "Instrument names\n" - "are abused as\n" - "comments in\n" - "module file formats.\n" - "======================\n" - "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - "\n\n\n" - "Sample names\n" - "are sometimes\n" - "also abused as\n" - "comments.\n"); - -class TestXM : public CppUnit::TestFixture -{ - CPPUNIT_TEST_SUITE(TestXM); - CPPUNIT_TEST(testReadTags); - CPPUNIT_TEST(testReadStrippedTags); - CPPUNIT_TEST(testWriteTagsShort); - CPPUNIT_TEST(testWriteTagsLong); - CPPUNIT_TEST_SUITE_END(); - -public: - void testReadTags() - { - testRead(TEST_FILE_PATH_C("test.xm"), titleBefore, - commentBefore, trackerNameBefore); - } - - void testReadStrippedTags() - { - XM::File file(TEST_FILE_PATH_C("stripped.xm")); - CPPUNIT_ASSERT(file.isValid()); - - XM::Properties *p = file.audioProperties(); - Mod::Tag *t = file.tag(); - - CPPUNIT_ASSERT(0 != p); - CPPUNIT_ASSERT(0 != t); - - CPPUNIT_ASSERT_EQUAL(0, p->length()); - CPPUNIT_ASSERT_EQUAL(0, p->bitrate()); - CPPUNIT_ASSERT_EQUAL(0, p->sampleRate()); - CPPUNIT_ASSERT_EQUAL(8, p->channels()); - CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 1, p->lengthInPatterns()); - CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 0, p->version()); - CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 0 , p->restartPosition()); - CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 1, p->patternCount()); - CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 0, p->instrumentCount()); - CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 1, p->flags()); - CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 6, p->tempo()); - CPPUNIT_ASSERT_EQUAL((TagLib::ushort)125, p->bpmSpeed()); - CPPUNIT_ASSERT_EQUAL(titleBefore, t->title()); - CPPUNIT_ASSERT_EQUAL(String::null, t->artist()); - CPPUNIT_ASSERT_EQUAL(String::null, t->album()); - CPPUNIT_ASSERT_EQUAL(String::null, t->comment()); - CPPUNIT_ASSERT_EQUAL(String::null, t->genre()); - CPPUNIT_ASSERT_EQUAL(0U, t->year()); - CPPUNIT_ASSERT_EQUAL(0U, t->track()); - CPPUNIT_ASSERT_EQUAL(String::null, t->trackerName()); - } - - void testWriteTagsShort() - { - testWriteTags(newCommentShort); - } - - void testWriteTagsLong() - { - testWriteTags(newCommentLong); - } - -private: - void testRead(FileName fileName, const String &title, - const String &comment, const String &trackerName) - { - XM::File file(fileName); - - CPPUNIT_ASSERT(file.isValid()); - - XM::Properties *p = file.audioProperties(); - Mod::Tag *t = file.tag(); - - CPPUNIT_ASSERT(0 != p); - CPPUNIT_ASSERT(0 != t); - - CPPUNIT_ASSERT_EQUAL(0, p->length()); - CPPUNIT_ASSERT_EQUAL(0, p->bitrate()); - CPPUNIT_ASSERT_EQUAL(0, p->sampleRate()); - CPPUNIT_ASSERT_EQUAL(8, p->channels()); - CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 1, p->lengthInPatterns()); - CPPUNIT_ASSERT_EQUAL((TagLib::ushort)260, p->version()); - CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 0, p->restartPosition()); - CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 1, p->patternCount()); - CPPUNIT_ASSERT_EQUAL((TagLib::ushort)128, p->instrumentCount()); - CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 1, p->flags()); - CPPUNIT_ASSERT_EQUAL((TagLib::ushort) 6, p->tempo()); - CPPUNIT_ASSERT_EQUAL((TagLib::ushort)125, p->bpmSpeed()); - CPPUNIT_ASSERT_EQUAL(title, t->title()); - CPPUNIT_ASSERT_EQUAL(String::null, t->artist()); - CPPUNIT_ASSERT_EQUAL(String::null, t->album()); - CPPUNIT_ASSERT_EQUAL(comment, t->comment()); - CPPUNIT_ASSERT_EQUAL(String::null, t->genre()); - CPPUNIT_ASSERT_EQUAL(0U, t->year()); - CPPUNIT_ASSERT_EQUAL(0U, t->track()); - CPPUNIT_ASSERT_EQUAL(trackerName, t->trackerName()); - } - - void testWriteTags(const String &comment) - { - ScopedFileCopy copy("test", ".xm"); - { - XM::File file(copy.fileName().c_str()); - CPPUNIT_ASSERT(file.tag() != 0); - file.tag()->setTitle(titleAfter); - file.tag()->setComment(comment); - file.tag()->setTrackerName(trackerNameAfter); - CPPUNIT_ASSERT(file.save()); - } - testRead(copy.fileName().c_str(), titleAfter, - commentAfter, trackerNameAfter); - CPPUNIT_ASSERT(fileEqual( - copy.fileName(), - TEST_FILE_PATH_C("changed.xm"))); - } -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(TestXM); diff --git a/taglib/tests/utils.h b/taglib/tests/utils.h deleted file mode 100644 index 00cef62..0000000 --- a/taglib/tests/utils.h +++ /dev/null @@ -1,104 +0,0 @@ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#ifdef _WIN32 -#include <windows.h> -#else -#include <unistd.h> -#include <fcntl.h> -#include <sys/fcntl.h> -#include <sys/stat.h> -#endif -#include <stdio.h> -#include <string.h> -#include <string> -#include <fstream> - -using namespace std; - -inline string testFilePath(const string &filename) -{ - return string(TESTS_DIR "data/") + filename; -} - -#define TEST_FILE_PATH_C(f) testFilePath(f).c_str() - -inline string copyFile(const string &filename, const string &ext) -{ - string newname = string(tempnam(NULL, NULL)) + ext; - string oldname = testFilePath(filename) + ext; -#ifdef _WIN32 - CopyFile(oldname.c_str(), newname.c_str(), FALSE); - SetFileAttributes(newname.c_str(), GetFileAttributes(newname.c_str()) & ~FILE_ATTRIBUTE_READONLY); -#else - char buffer[4096]; - int bytes; - int inf = open(oldname.c_str(), O_RDONLY); - int outf = open(newname.c_str(), O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR); - while((bytes = read(inf, buffer, sizeof(buffer))) > 0) - write(outf, buffer, bytes); - close(outf); - close(inf); -#endif - return newname; -} - -inline void deleteFile(const string &filename) -{ - remove(filename.c_str()); -} - -inline bool fileEqual(const string &filename1, const string &filename2) -{ - char buf1[BUFSIZ]; - char buf2[BUFSIZ]; - - ifstream stream1(filename1.c_str(), ios_base::in | ios_base::binary); - ifstream stream2(filename2.c_str(), ios_base::in | ios_base::binary); - - if(!stream1 && !stream2) return true; - if(!stream1 || !stream2) return false; - - for(;;) - { - stream1.read(buf1, BUFSIZ); - stream2.read(buf2, BUFSIZ); - - streamsize n1 = stream1.gcount(); - streamsize n2 = stream2.gcount(); - - if(n1 != n2) return false; - - if(n1 == 0) break; - - if(memcmp(buf1, buf2, n1) != 0) return false; - } - - return stream1.good() == stream2.good(); -} - -class ScopedFileCopy -{ -public: - ScopedFileCopy(const string &filename, const string &ext, bool deleteFile=true) - { - m_deleteFile = deleteFile; - m_filename = copyFile(filename, ext); - } - - ~ScopedFileCopy() - { - if(m_deleteFile) - deleteFile(m_filename); - } - - string fileName() - { - return m_filename; - } - -private: - bool m_deleteFile; - string m_filename; -};