26 Commits

Author SHA1 Message Date
Urs Fleisch
7d86716194 Version 2.1.1 2025-06-29 17:35:45 +02:00
Urs Fleisch
eb749ac55b Use ldexpl() instead of ldexp()
This will fix "warning: conversion from ‘long double’ to
‘double’ may change value [-Wfloat-conversion]".
2025-06-25 22:08:09 +02:00
Urs Fleisch
148cc9a921 Fix conversion compiler warnings
Using a release build with GCC 14.2.0 and -Wextra -Wconversion -Wall.
The generated binaries are not changed by this commit.
2025-06-25 22:08:09 +02:00
Urs Fleisch
88d6b18b4f Convert IPLS to TIPL and TMCL (#1274)
The involvement/involvee pairs which are supported for TIPL properties
(ARRANGER, ENGINEER, PRODUCER, DJ-MIX, MIX) are left in the TIPL
frame, other pairs are moved to a TMCL frame. This will result in a
consistent behavior for both ID3v2.3 and ID3v2.4 tags produced by
MusicBrainz Picard.
2025-06-21 10:45:43 +02:00
Urs Fleisch
d61a333f27 Map lowercase MusicBrainz TIPL keys to properties (#1274) 2025-06-21 10:45:43 +02:00
Urs Fleisch
e73517d058 CMake targets with TAGLIB_STATIC compile definition (#1277) 2025-06-20 10:19:01 +02:00
Urs Fleisch
6563ceaafa C bindings: Include missing wchar header in tag_c.h (#1273)
In C++, wchar_t is a built-in fundamental type, but in C, it is not.
Compilation with MinGW will fail without a header included which
defines wchar_t (wchar.h or stddef.h). The other compilers used in our
CI (gcc on Ubuntu, clang on macOS and MSVC on Windows) seem to
know wchar_t without an include.
2025-06-14 08:53:30 +02:00
Urs Fleisch
c57431e903 GitHub Actions: Build with MinGW 2025-06-14 08:53:30 +02:00
Urs Fleisch
42dcfec86b Use tag_c.h as first include in build with C compiler (#1273)
This will fail on MinGW because its gcc does not have wchar_t without
including wchar.h. With g++ as used with test_tag_c.cpp, the problem is
undetected because g++ supports wchar_t without including wchar.h.
2025-06-14 08:53:30 +02:00
Urs Fleisch
d48f02030d Version 2.1 2025-05-21 21:05:30 +02:00
Jamie
3ccc390155 Add file_new and file_new_type wchar variants for C binding (#1271) 2025-05-16 17:01:23 +02:00
Urs Fleisch
fbbead3efd Support custom temp and tests directories (#1268) (#1270)
The following user-settable values for CMake are supported:

- TESTS_DIR: Tests directory, is path to unit test data when 'data' is
  appended. Can be used to run the unit tests on a target.
- TESTS_TMPDIR: Directory for temporary files created during unit tests,
  system tmpdir is used if undefined. Has to be defined on systems
  without global temporary directory.
2025-05-01 19:55:46 +02:00
Urs Fleisch
ee1931b811 Compile time configuration of supported formats (#1262)
CMake options WITH_APE, WITH_ASF, WITH_DSF, WITH_MOD, WITH_MP4,
WITH_RIFF, WITH_SHORTEN, WITH_TRUEAUDIO, WITH_VORBIS, by default,
they are all ON.
2025-02-02 12:24:26 +01:00
Stephen Booth
648f5e5882 Add Shorten (SHN) support (#1257)
* Add Shorten (SHN) support

* Add `<cmath>` include and use `std::log2`

* Use `uintptr_t` for buffer size calculations

* Work around `byteSwap` not using fixed width types

* Remove four-character codes

* Attempt to fix `static_assert`

* Revert previous commit

* Update `read_uint`* functions

* Use ByteVector for byte swaps

* Use different ByteVector ctor

* Rework variable-length input to use ByteVector

* Rename some variables

* Naming and formatting cleanup

* Add basic Shorten tests

* Rename a constant

* Rename `internalFileType` to `fileType`

* Add documentation on `fileType` meaning

* Add DO_NOT_DOCUMENT guard

* Fix shadowVariable issues reported by cppcheck

cppcheck --enable=all --inline-suppr \
  --suppress=noExplicitConstructor --suppress=unusedFunction \
  --suppress=missingIncludeSystem --project=compile_commands.json

* Formatting cleanup

* More explicit types

Reason for these changes: getRiceGolombCode(k, uInt32CodeSize) was
called with int k for uint32_t& argument.
There was also a warning from MSVC for line 299:
warning C4267: 'argument': conversion from 'size_t' to 'int'

* Additional explicit types

* Rename `SHN` namespace to `Shorten`

Also rename files to match

---------

Co-authored-by: Urs Fleisch <ufleisch@users.sourceforge.net>
2024-12-30 07:23:11 -06:00
Stephen Booth
c1c60ebeea Use fixed width types (#1258)
Use fixed width types in `byteSwap` functions
2024-12-22 07:02:05 -06:00
Urs Fleisch
3bc0ea0ecb Preserve unicode encoding when downgrading to ID3v2.3 (#1259) (#1260) 2024-12-22 12:07:25 +01:00
Christian Schmitz
225c73e181 Fixed warning about shadowing variable (#1254)
You can't name parameter and structure field the same as complier frequently complain about this.
2024-11-22 06:55:34 +01:00
Urs Fleisch
90f62a3c94 Do not store too large FLAC metadata blocks (#1249) (#1250)
The size of FLAC metadata blocks is stored in only 24 bits. Remove
blocks exceeding this limit when saving FLAC and Ogg FLAC files.
2024-11-14 17:43:18 +01:00
Urs Fleisch
5b6f9ef848 Fix segfaults with String and ByteVector nullptr arguments (#1247) (#1248) 2024-11-02 06:39:21 +01:00
Urs Fleisch
e3de03501f Version 2.0.2 2024-08-24 06:40:41 +02:00
Urs Fleisch
1bd0d711ca Support older utfcpp versions with utf8cpp CMake target (#1243) (#1244)
This affects for example openSUSE Leap 15.6, which installs
utfcpp 3.2.1 in its own folder.
Now not only utf8::cpp, but also utf8cpp is supported as a CMake
target.
2024-08-15 12:44:17 +02:00
nekiwo
7c85fcaa81 Remove 'using namespace std' to avoid potential conflicts in example files (#1241)
Co-authored-by: nekiwo <nekiwo@users.noreply.github.com>
2024-08-05 21:54:33 +02:00
Urs Fleisch
cbe54d2f40 Support free form tags with MP4 properties (#1239) (#1240) 2024-07-29 20:24:33 +02:00
Urs Fleisch
c4ed590032 tagwriter option -p not working properly (#1236) (#1237)
The -p option of tagwriter sample does not work.
This is because the picture file is open in text mode instead of binary.
Also, the isFile function does not work on Windows in 32 bit mode with
large files. Using _stat64 instead of stat solves the problem.
2024-07-19 12:25:46 +02:00
Stephen Booth
f3fb4d83a4 Skip unknown MP4 boxes (#1231) 2024-05-18 06:45:10 +02:00
Urs Fleisch
3d4428726e Fix parsing of ID3v2.2 frames (#1228) 2024-05-18 06:43:00 +02:00
72 changed files with 3183 additions and 700 deletions

View File

@@ -9,10 +9,14 @@ jobs:
build:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
os: [ubuntu-latest, macos-latest, windows-latest, windows-2025]
include:
- os: windows-latest
cmake_extra_args: '-DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake"'
- os: windows-2025
cmake_extra_args: '-G "MinGW Makefiles" -DCPPUNIT_INCLUDE_DIR="$env:GITHUB_WORKSPACE/pkg/usr/local/include" -DCPPUNIT_LIBRARIES="$($env:GITHUB_WORKSPACE -replace "\\", "/")/pkg/usr/local/lib/libcppunit.dll.a" -DCPPUNIT_INSTALLED_VERSION="1.15.1"'
# The windows-2025 runner is used for MinGW.
name: ${{ matrix.os == 'windows-2025' && 'mingw' || matrix.os }}
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
@@ -32,6 +36,24 @@ jobs:
run: vcpkg install cppunit utfcpp zlib --triplet x64-windows
if: matrix.os == 'windows-latest'
- name: Set up MinGW
shell: bash
run: |
# Fetch utf8cpp, build cppunit
git submodule update --init
# Fails with fatal error: cppunit/config-auto.h: No such file or directory
# vcpkg install cppunit utfcpp zlib --triplet x64-mingw-dynamic
# Probably not working with CMake and MinGW, so we have to build it ourselves.
curl -sL "https://dev-www.libreoffice.org/src/cppunit-1.15.1.tar.gz" | tar xz
mkdir -p build_cppunit
(cd build_cppunit && MAKE=mingw32-make ../cppunit-1.15.1/configure \
--enable-shared=yes --enable-static=no \
--disable-dependency-tracking --disable-doxygen)
find build_cppunit -name Makefile -exec sed -i 's/\($[({]SHELL[)}]\)/"\1"/' {} \;
sed -i 's/^\(SUBDIRS.*\) examples\(.*\)$/\1\2/' build_cppunit/Makefile
(cd build_cppunit && mingw32-make -j$(nproc) install DESTDIR=$(cd .. && pwd)/pkg)
if: matrix.os == 'windows-2025'
- name: Configure
run: >
cmake -B${{github.workspace}}/build
@@ -41,12 +63,12 @@ jobs:
${{ matrix.cmake_extra_args }}
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel
- name: Test
working-directory: ${{github.workspace}}/build
run: ctest -C ${{env.BUILD_TYPE}} -V --no-tests=error
if: matrix.os != 'windows-latest'
if: matrix.os != 'windows-latest' && matrix.os != 'windows-2025'
- name: Test Windows
working-directory: ${{github.workspace}}/build
@@ -57,3 +79,10 @@ jobs:
$env:Path += ";$env:VCPKG_INSTALLATION_ROOT\packages\zlib_x64-windows\bin"
ctest -C ${{env.BUILD_TYPE}} -V --no-tests=error
if: matrix.os == 'windows-latest'
- name: Test MinGW
working-directory: ${{github.workspace}}/build
run: |
$env:Path += ";$PWD/taglib;$PWD/bindings/c;${{github.workspace}}/pkg/usr/local/bin"
ctest -C ${{env.BUILD_TYPE}} -V --no-tests=error
if: matrix.os == 'windows-2025'

View File

@@ -1,3 +1,31 @@
TagLib 2.1.1 (June 30, 2025)
============================
* Map ID3v2.3 IPLS frames to both ID3v2.4 TIPL and TMCL to have a consistent
behavior when using MusicBrainz tags with the property map interface.
* Fix missing include for `wchar_t` when using C bindings with MinGW.
TagLib 2.1 (May 31, 2025)
=========================
* Support for Shorten (SHN) files.
* Compile time configuration of supported formats: WITH_APE, WITH_ASF, ...
* Compile time configuration of data and temporary directories for unit tests:
TESTS_DIR and TESTS_TMPDIR.
* C bindings: Added taglib_file_new_wchar() and taglib_file_new_type_wchar().
* Preserve unicode encoding when downgrading to ID3v2.3.
* Do not store FLAC metadata blocks which are too large.
* Fix segfaults with String and ByteVector nullptr arguments.
TagLib 2.0.2 (Aug 24, 2024)
===========================
* Fix parsing of ID3v2.2 frames.
* Tolerate MP4 files with unknown atom types as generated by Android tools.
* Support setting properties with arbitrary names in MP4 tags.
* Windows: Fix "-p" option in tagwriter example.
* Support building with older utfcpp versions.
TagLib 2.0.1 (Apr 9, 2024)
==========================

View File

@@ -19,9 +19,6 @@ if(APPLE)
set(FRAMEWORK_INSTALL_DIR "/Library/Frameworks" CACHE STRING "Directory to install frameworks to.")
endif()
endif()
if(NOT BUILD_SHARED_LIBS)
add_definitions(-DTAGLIB_STATIC)
endif()
option(ENABLE_STATIC_RUNTIME "Visual Studio, link with runtime statically" OFF)
option(ENABLE_CCACHE "Use ccache when building libtag" OFF)
@@ -48,7 +45,10 @@ set(TAGLIB_INSTALL_SUFFIX "" CACHE STRING
"Suffix added to installed files (include directory, libraries, .pc)")
add_definitions(-DHAVE_CONFIG_H)
set(TESTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/tests/")
set(TESTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/tests/" CACHE STRING
"Tests directory, is path to unit test data when 'data' is appended")
set(TESTS_TMPDIR "" CACHE STRING
"Directory for temporary files created during unit tests, system tmpdir is used if undefined")
if(CMAKE_C_COMPILER_ID MATCHES "^(GNU|Clang|AppleClang)$")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
@@ -92,11 +92,21 @@ endif()
# Minor version: increase it if you add ABI compatible features.
# Patch version: increase it for bug fix releases.
set(TAGLIB_SOVERSION_MAJOR 2)
set(TAGLIB_SOVERSION_MINOR 0)
set(TAGLIB_SOVERSION_MINOR 1)
set(TAGLIB_SOVERSION_PATCH 1)
include(ConfigureChecks.cmake)
option(WITH_APE "Build with APE, MPC, WavPack" ON)
option(WITH_ASF "Build with ASF" ON)
option(WITH_DSF "Build with DSF" ON)
option(WITH_MOD "Build with Tracker modules" ON)
option(WITH_MP4 "Build with MP4" ON)
option(WITH_RIFF "Build with AIFF, RIFF, WAV" ON)
option(WITH_SHORTEN "Build with Shorten" ON)
option(WITH_TRUEAUDIO "Build with TrueAudio" ON)
option(WITH_VORBIS "Build with Vorbis, FLAC, Ogg, Opus" ON)
# Determine whether zlib is installed.
option(WITH_ZLIB "Build with ZLIB" ON)
@@ -178,6 +188,36 @@ else()
endif()
endif()
if(WITH_APE)
set(TAGLIB_WITH_APE TRUE)
endif()
if(WITH_ASF)
set(TAGLIB_WITH_ASF TRUE)
endif()
if(WITH_DSF)
set(TAGLIB_WITH_DSF TRUE)
endif()
if(WITH_MOD)
set(TAGLIB_WITH_MOD TRUE)
endif()
if(WITH_MP4)
set(TAGLIB_WITH_MP4 TRUE)
endif()
if(WITH_RIFF)
set(TAGLIB_WITH_RIFF TRUE)
endif()
if(WITH_SHORTEN)
set(TAGLIB_WITH_SHORTEN TRUE)
endif()
if(WITH_TRUEAUDIO)
set(TAGLIB_WITH_TRUEAUDIO TRUE)
endif()
if(WITH_VORBIS)
set(TAGLIB_WITH_VORBIS TRUE)
endif()
configure_file(taglib/taglib_config.h.cmake "${CMAKE_CURRENT_BINARY_DIR}/taglib_config.h")
add_subdirectory(taglib)
if(BUILD_BINDINGS)

View File

@@ -42,6 +42,9 @@ CMakeLists.txt file.
| `TAGLIB_INSTALL_SUFFIX` | Suffix added to installed libraries, includes, ... |
| `ENABLE_STATIC_RUNTIME` | Link with MSVC runtime statically |
| `BUILD_FRAMEWORK` | Build a macOS framework |
| `TESTS_DIR` | Where to find unit test data (with data appended) |
| `TESTS_TMPDIR` | Where to create temporary files in unit tests |
If you want to install TagLib 2 alongside TagLib 1, you can use
`-DTAGLIB_INSTALL_SUFFIX=-2` and make sure that `BUILD_EXAMPLES` is not `ON`
@@ -49,6 +52,30 @@ for both versions. The installed files will then include bin/taglib-2-config,
include/taglib-2, cmake/taglib-2, pkgconfig/taglib-2.pc,
pkgconfig/taglib_c-2.pc and the libraries have a suffix "-2".
### Compile Time Configuration of Supported Formats
To reduce the size of the library, it is possible to switch off supported file
formats. By default, all formats are enabled. Support for MPEG files (MP3, AAC)
and ID3 tags cannot be disabled. The following CMake options are available:
| Option | Description |
|-------------------------|----------------------------------------------------|
| `WITH_APE` | Build with APE, MPC, WavPack (default ON) |
| `WITH_ASF` | Build with ASF (default ON) |
| `WITH_DSF` | Build with DSF (default ON) |
| `WITH_MOD` | Build with Tracker modules (default ON) |
| `WITH_MP4` | Build with MP4 (default ON) |
| `WITH_RIFF` | Build with AIFF, RIFF, WAV (default ON) |
| `WITH_SHORTEN` | Build with Shorten (default ON) |
| `WITH_TRUEAUDIO` | Build with TrueAudio (default ON) |
| `WITH_VORBIS` | Build with Vorbis, FLAC, Ogg, Opus (default ON) |
Note that disabling formats will remove exported symbols from the library and
thus break binary compatibility. These options should therefore only be used
if the library is built specifically for a certain project. The public header
files still contain the full API, if you use TagLib with a reduced set of
formats, you can include taglib_config.h and use its definitions (prefixed with
`TAGLIB_`, e.g. `TAGLIB_WITH_APE`), as it is done in examples/framelist.cpp.
## Dependencies
@@ -438,3 +465,54 @@ cmake --build build_mingw --config Release
PATH=$PATH:$TAGLIB_PREFIX/bin
build_mingw/tagreader /path/to/audio-file
```
## Android
### Using vcpkg
The bash script below can be used to build TagLib for Android using vcpkg.
It must be started in the parent folder of the taglib source folder and will
build in a folder _android_build_ and install into _android_pkg_.
The package and the unit tests are then transferred to an Android device
and the unit tests are run on the device.
Note that `TESTS_TMPDIR` is set because there is no system-wide temporary folder
on Android. `TESTS_DIR` is set to run the tests on the target.
```
# You may have to adapt the NDK and vcpkg paths and the ABI/triplet.
export ANDROID_NDK_HOME=$HOME/Development/android-sdk/ndk/23.1.7779620
export VCPKG_ROOT=$HOME/Development/vcpkg
PATH=$PATH:$VCPKG_ROOT
# armeabi-v7a/arm-android or arm64-v8a/arm64-android or x86/x86-android or x86_64/x64-android
android_abi=armeabi-v7a
vcpkg_target_triplet=arm-android
vcpkg_toolchain_file=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake
android_toolchain_file=$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake
vcpkg install --triplet $vcpkg_target_triplet utfcpp zlib cppunit
cmake -B android_build -S taglib \
-DCMAKE_TOOLCHAIN_FILE=$vcpkg_toolchain_file \
-DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=$android_toolchain_file \
-DVCPKG_TARGET_TRIPLET=$vcpkg_target_triplet \
-DANDROID_ABI=$android_abi \
-GNinja -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=Release \
-DVISIBILITY_HIDDEN=ON -DENABLE_CCACHE=ON -DBUILD_EXAMPLES=ON -DBUILD_TESTING=ON \
-DTESTS_DIR=/data/local/tmp/tests/ -DTESTS_TMPDIR=/data/local/tmp
cmake --build android_build --config Release
cmake --install android_build --config Release --prefix android_pkg --strip
cp -a android_build/tests/test_runner android_pkg/bin/
if hash adb 2>/dev/null; then
adb push android_pkg /data/local/tmp/
adb push android_build/tests/test_runner /data/local/tmp/tests/test_runner
adb push taglib/tests/data /data/local/tmp/tests/
adb shell "env LD_LIBRARY_PATH=/data/local/tmp/android_pkg/lib /data/local/tmp/tests/test_runner"
# You could also try an example binary:
# adb shell "env LD_LIBRARY_PATH=/data/local/tmp/android_pkg/lib /data/local/tmp/android_pkg/bin/tagreader '/sdcard/Music/Some Album/A Track.mp3'"
fi
```

View File

@@ -1,31 +1,69 @@
include_directories(
set(tag_c_HDR_DIRS
${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
${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/ape
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/it
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/mod
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/s3m
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/xm
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/ogg/opus
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/dsf
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/dsdiff
)
if(WITH_ASF)
set(tag_c_HDR_DIRS ${tag_c_HDR_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/asf
)
endif()
if(WITH_VORBIS)
set(tag_c_HDR_DIRS ${tag_c_HDR_DIRS}
${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/ogg/speex
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/ogg/opus
)
endif()
if(WITH_APE)
set(tag_c_HDR_DIRS ${tag_c_HDR_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/mpc
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/wavpack
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/ape
)
endif()
if(WITH_MP4)
set(tag_c_HDR_DIRS ${tag_c_HDR_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/mp4
)
endif()
if(WITH_TRUEAUDIO)
set(tag_c_HDR_DIRS ${tag_c_HDR_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/trueaudio
)
endif()
if(WITH_RIFF)
set(tag_c_HDR_DIRS ${tag_c_HDR_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/riff
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/riff/aiff
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/riff/wav
)
endif()
if(WITH_MOD)
set(tag_c_HDR_DIRS ${tag_c_HDR_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/it
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/mod
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/s3m
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/xm
)
endif()
if(WITH_DSF)
set(tag_c_HDR_DIRS ${tag_c_HDR_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/dsf
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/dsdiff
)
endif()
if(WITH_SHORTEN)
set(tag_c_HDR_DIRS ${tag_c_HDR_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/shorten
)
endif()
include_directories(${tag_c_HDR_DIRS})
set(tag_c_HDRS tag_c.h)
@@ -74,6 +112,9 @@ set_target_properties(tag_c PROPERTIES
DEFINE_SYMBOL MAKE_TAGLIB_C_LIB
INSTALL_NAME_DIR ${CMAKE_INSTALL_FULL_LIBDIR}
)
if(NOT BUILD_SHARED_LIBS)
target_compile_definitions(tag_c PUBLIC TAGLIB_STATIC)
endif()
if(TAGLIB_INSTALL_SUFFIX)
if(BUILD_SHARED_LIBS)

View File

@@ -29,34 +29,57 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "taglib_config.h"
#include "tstringlist.h"
#include "tbytevectorstream.h"
#include "tiostream.h"
#include "tfile.h"
#include "tpropertymap.h"
#include "fileref.h"
#include "asffile.h"
#include "vorbisfile.h"
#include "mpegfile.h"
#include "tag.h"
#include "id3v2framefactory.h"
#ifdef TAGLIB_WITH_ASF
#include "asffile.h"
#endif
#ifdef TAGLIB_WITH_VORBIS
#include "vorbisfile.h"
#include "flacfile.h"
#include "oggflacfile.h"
#include "speexfile.h"
#include "opusfile.h"
#endif
#ifdef TAGLIB_WITH_APE
#include "mpcfile.h"
#include "wavpackfile.h"
#include "speexfile.h"
#endif
#ifdef TAGLIB_WITH_TRUEAUDIO
#include "trueaudiofile.h"
#endif
#ifdef TAGLIB_WITH_MP4
#include "mp4file.h"
#endif
#ifdef TAGLIB_WITH_RIFF
#include "aifffile.h"
#include "wavfile.h"
#endif
#ifdef TAGLIB_WITH_APE
#include "apefile.h"
#endif
#ifdef TAGLIB_WITH_MOD
#include "itfile.h"
#include "modfile.h"
#include "s3mfile.h"
#include "xmfile.h"
#include "opusfile.h"
#endif
#ifdef TAGLIB_WITH_DSF
#include "dsffile.h"
#include "dsdifffile.h"
#include "tag.h"
#include "id3v2framefactory.h"
#endif
#ifdef TAGLIB_WITH_SHORTEN
#include "shortenfile.h"
#endif
using namespace TagLib;
@@ -126,49 +149,73 @@ TagLib_File *taglib_file_new(const char *filename)
return reinterpret_cast<TagLib_File *>(new FileRef(filename));
}
TagLib_File *taglib_file_new_type(const char *filename, TagLib_File_Type type)
#ifdef _WIN32
TagLib_File *taglib_file_new_wchar(const wchar_t *filename)
{
return reinterpret_cast<TagLib_File *>(new FileRef(filename));
}
#endif
template<typename T>
TagLib_File *taglib_file_new_type_any_char(const T *filename, TagLib_File_Type type)
{
File *file = NULL;
switch(type) {
case TagLib_File_MPEG:
file = new MPEG::File(filename);
break;
#ifdef TAGLIB_WITH_VORBIS
case TagLib_File_OggVorbis:
file = new Ogg::Vorbis::File(filename);
break;
case TagLib_File_FLAC:
file = new FLAC::File(filename);
break;
case TagLib_File_MPC:
file = new MPC::File(filename);
break;
case TagLib_File_OggFlac:
file = new Ogg::FLAC::File(filename);
break;
case TagLib_File_WavPack:
file = new WavPack::File(filename);
break;
case TagLib_File_Speex:
file = new Ogg::Speex::File(filename);
break;
case TagLib_File_Opus:
file = new Ogg::Opus::File(filename);
break;
#endif
#ifdef TAGLIB_WITH_APE
case TagLib_File_MPC:
file = new MPC::File(filename);
break;
case TagLib_File_WavPack:
file = new WavPack::File(filename);
break;
case TagLib_File_APE:
file = new APE::File(filename);
break;
#endif
#ifdef TAGLIB_WITH_TRUEAUDIO
case TagLib_File_TrueAudio:
file = new TrueAudio::File(filename);
break;
#endif
#ifdef TAGLIB_WITH_MP4
case TagLib_File_MP4:
file = new MP4::File(filename);
break;
#endif
#ifdef TAGLIB_WITH_ASF
case TagLib_File_ASF:
file = new ASF::File(filename);
break;
#endif
#ifdef TAGLIB_WITH_RIFF
case TagLib_File_AIFF:
file = new RIFF::AIFF::File(filename);
break;
case TagLib_File_WAV:
file = new RIFF::WAV::File(filename);
break;
case TagLib_File_APE:
file = new APE::File(filename);
break;
#endif
#ifdef TAGLIB_WITH_MOD
case TagLib_File_IT:
file = new IT::File(filename);
break;
@@ -181,21 +228,38 @@ TagLib_File *taglib_file_new_type(const char *filename, TagLib_File_Type type)
case TagLib_File_XM:
file = new XM::File(filename);
break;
case TagLib_File_Opus:
file = new Ogg::Opus::File(filename);
break;
#endif
#ifdef TAGLIB_WITH_DSF
case TagLib_File_DSF:
file = new DSF::File(filename);
break;
case TagLib_File_DSDIFF:
file = new DSDIFF::File(filename);
break;
#endif
#ifdef TAGLIB_WITH_SHORTEN
case TagLib_File_SHORTEN:
file = new Shorten::File(filename);
break;
#endif
default:
break;
}
return file ? reinterpret_cast<TagLib_File *>(new FileRef(file)) : NULL;
}
TagLib_File *taglib_file_new_type(const char *filename, TagLib_File_Type type)
{
return taglib_file_new_type_any_char(filename, type);
}
#ifdef _WIN32
TagLib_File *taglib_file_new_type_wchar(const wchar_t *filename, TagLib_File_Type type)
{
return taglib_file_new_type_any_char(filename, type);
}
#endif
TagLib_File *taglib_file_new_iostream(TagLib_IOStream *stream)
{
return reinterpret_cast<TagLib_File *>(

View File

@@ -43,6 +43,7 @@ extern "C" {
#define TAGLIB_C_EXPORT
#endif
#include <wchar.h>
#ifdef _MSC_VER
/* minwindef.h contains typedef int BOOL */
#include <windows.h>
@@ -130,7 +131,8 @@ typedef enum {
TagLib_File_XM,
TagLib_File_Opus,
TagLib_File_DSF,
TagLib_File_DSDIFF
TagLib_File_DSDIFF,
TagLib_File_SHORTEN
} TagLib_File_Type;
/*!
@@ -141,12 +143,18 @@ typedef enum {
* be opened.
*/
TAGLIB_C_EXPORT TagLib_File *taglib_file_new(const char *filename);
#ifdef _WIN32
TAGLIB_C_EXPORT TagLib_File *taglib_file_new_wchar(const wchar_t *filename);
#endif
/*!
* 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);
#ifdef _WIN32
TAGLIB_C_EXPORT TagLib_File *taglib_file_new_type_wchar(const wchar_t *filename, TagLib_File_Type type);
#endif
/*!
* Creates a TagLib file from a \a stream.

View File

@@ -20,5 +20,6 @@
#cmakedefine TRACE_IN_RELEASE 1
#cmakedefine TESTS_DIR "@TESTS_DIR@"
#cmakedefine TESTS_TMPDIR "@TESTS_TMPDIR@"
#endif

View File

@@ -25,6 +25,7 @@
#include <iostream>
#include <cstdlib>
#include "taglib_config.h"
#include "tbytevector.h"
#include "mpegfile.h"
#include "id3v2tag.h"
@@ -32,9 +33,10 @@
#include "id3v2header.h"
#include "commentsframe.h"
#include "id3v1tag.h"
#ifdef TAGLIB_WITH_APE
#include "apetag.h"
#endif
using namespace std;
using namespace TagLib;
int main(int argc, char *argv[])
@@ -44,7 +46,7 @@ int main(int argc, char *argv[])
for(int i = 1; i < argc; i++) {
cout << "******************** \"" << argv[i] << "\"********************" << endl;
std::cout << "******************** \"" << argv[i] << "\"********************" << std::endl;
MPEG::File f(argv[i]);
@@ -52,62 +54,64 @@ int main(int argc, char *argv[])
if(id3v2tag) {
cout << "ID3v2."
std::cout << "ID3v2."
<< id3v2tag->header()->majorVersion()
<< "."
<< id3v2tag->header()->revisionNumber()
<< ", "
<< id3v2tag->header()->tagSize()
<< " bytes in tag"
<< endl;
<< std::endl;
const auto &frames = id3v2tag->frameList();
for(auto it = frames.begin(); it != frames.end(); it++) {
cout << (*it)->frameID();
std::cout << (*it)->frameID();
if(auto comment = dynamic_cast<ID3v2::CommentsFrame *>(*it))
if(!comment->description().isEmpty())
cout << " [" << comment->description() << "]";
std::cout << " [" << comment->description() << "]";
cout << " - \"" << (*it)->toString() << "\"" << endl;
std::cout << " - \"" << (*it)->toString() << "\"" << std::endl;
}
}
else
cout << "file does not have a valid id3v2 tag" << endl;
std::cout << "file does not have a valid id3v2 tag" << std::endl;
cout << endl << "ID3v1" << endl;
std::cout << std::endl << "ID3v1" << std::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;
std::cout << "title - \"" << id3v1tag->title() << "\"" << std::endl;
std::cout << "artist - \"" << id3v1tag->artist() << "\"" << std::endl;
std::cout << "album - \"" << id3v1tag->album() << "\"" << std::endl;
std::cout << "year - \"" << id3v1tag->year() << "\"" << std::endl;
std::cout << "comment - \"" << id3v1tag->comment() << "\"" << std::endl;
std::cout << "track - \"" << id3v1tag->track() << "\"" << std::endl;
std::cout << "genre - \"" << id3v1tag->genre() << "\"" << std::endl;
}
else
cout << "file does not have a valid id3v1 tag" << endl;
std::cout << "file does not have a valid id3v1 tag" << std::endl;
#ifdef TAGLIB_WITH_APE
APE::Tag *ape = f.APETag();
cout << endl << "APE" << endl;
std::cout << std::endl << "APE" << std::endl;
if(ape) {
const auto &items = ape->itemListMap();
for(auto it = items.begin(); it != items.end(); ++it)
{
if((*it).second.type() != APE::Item::Binary)
cout << (*it).first << " - \"" << (*it).second.toString() << "\"" << endl;
std::cout << (*it).first << " - \"" << (*it).second.toString() << "\"" << std::endl;
else
cout << (*it).first << " - Binary data (" << (*it).second.binaryData().size() << " bytes)" << endl;
std::cout << (*it).first << " - Binary data (" << (*it).second.binaryData().size() << " bytes)" << std::endl;
}
}
else
cout << "file does not have a valid APE tag" << endl;
std::cout << "file does not have a valid APE tag" << std::endl;
#endif
cout << endl;
std::cout << std::endl;
}
}

View File

@@ -32,13 +32,11 @@
#include "fileref.h"
#include "tag.h"
using namespace std;
int main(int argc, char *argv[])
{
for(int i = 1; i < argc; i++) {
cout << "******************** \"" << argv[i] << "\" ********************" << endl;
std::cout << "******************** \"" << argv[i] << "\" ********************" << std::endl;
TagLib::FileRef f(argv[i]);
@@ -46,14 +44,14 @@ int main(int argc, char *argv[])
TagLib::Tag *tag = f.tag();
cout << "-- TAG (basic) --" << endl;
cout << "title - \"" << tag->title() << "\"" << endl;
cout << "artist - \"" << tag->artist() << "\"" << endl;
cout << "album - \"" << tag->album() << "\"" << endl;
cout << "year - \"" << tag->year() << "\"" << endl;
cout << "comment - \"" << tag->comment() << "\"" << endl;
cout << "track - \"" << tag->track() << "\"" << endl;
cout << "genre - \"" << tag->genre() << "\"" << endl;
std::cout << "-- TAG (basic) --" << std::endl;
std::cout << "title - \"" << tag->title() << "\"" << std::endl;
std::cout << "artist - \"" << tag->artist() << "\"" << std::endl;
std::cout << "album - \"" << tag->album() << "\"" << std::endl;
std::cout << "year - \"" << tag->year() << "\"" << std::endl;
std::cout << "comment - \"" << tag->comment() << "\"" << std::endl;
std::cout << "track - \"" << tag->track() << "\"" << std::endl;
std::cout << "genre - \"" << tag->genre() << "\"" << std::endl;
TagLib::PropertyMap tags = f.properties();
if(!tags.isEmpty()) {
@@ -64,10 +62,10 @@ int main(int argc, char *argv[])
}
}
cout << "-- TAG (properties) --" << endl;
std::cout << "-- TAG (properties) --" << std::endl;
for(auto j = tags.cbegin(); j != tags.cend(); ++j) {
for(auto k = j->second.begin(); k != j->second.end(); ++k) {
cout << left << std::setfill(' ') << std::setw(longest) << j->first << " - " << '"' << *k << '"' << endl;
std::cout << std::left << std::setfill(' ') << std::setw(longest) << j->first << " - " << '"' << *k << '"' << std::endl;
}
}
}
@@ -76,13 +74,13 @@ int main(int argc, char *argv[])
for(const auto &name : names) {
const auto& properties = f.complexProperties(name);
for(const auto &property : properties) {
cout << name << ":" << endl;
std::cout << name << ":" << std::endl;
for(const auto &[key, value] : property) {
cout << " " << left << std::setfill(' ') << std::setw(11) << key << " - ";
std::cout << " " << std::left << std::setfill(' ') << std::setw(11) << key << " - ";
if(value.type() == TagLib::Variant::ByteVector) {
cout << "(" << value.value<TagLib::ByteVector>().size() << " bytes)" << endl;
std::cout << "(" << value.value<TagLib::ByteVector>().size() << " bytes)" << std::endl;
/* The picture could be extracted using:
ofstream picture;
std::ofstream picture;
TagLib::String fn(argv[i]);
int slashPos = fn.rfind('/');
int dotPos = fn.rfind('.');
@@ -90,13 +88,13 @@ int main(int argc, char *argv[])
fn = fn.substr(slashPos + 1, dotPos - slashPos - 1);
}
fn += ".jpg";
picture.open(fn.toCString(), ios_base::out | ios_base::binary);
picture.open(fn.toCString(), std::ios_base::out | std::ios_base::binary);
picture << value.value<TagLib::ByteVector>();
picture.close();
*/
}
else {
cout << value << endl;
std::cout << value << std::endl;
}
}
}
@@ -110,12 +108,13 @@ int main(int argc, char *argv[])
int seconds = properties->lengthInSeconds() % 60;
int minutes = (properties->lengthInSeconds() - seconds) / 60;
cout << "-- AUDIO --" << endl;
cout << "bitrate - " << properties->bitrate() << endl;
cout << "sample rate - " << properties->sampleRate() << endl;
cout << "channels - " << properties->channels() << endl;
cout << "length - " << minutes << ":" << setfill('0') << setw(2) << right << seconds << endl;
std::cout << "-- AUDIO --" << std::endl;
std::cout << "bitrate - " << properties->bitrate() << std::endl;
std::cout << "sample rate - " << properties->sampleRate() << std::endl;
std::cout << "channels - " << properties->channels() << std::endl;
std::cout << "length - " << minutes << ":" << std::setfill('0') << std::setw(2) << std::right << seconds << std::endl;
}
}
return 0;
}

View File

@@ -22,11 +22,11 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "tag_c.h"
#include <stdio.h>
#include <string.h>
#include "tag_c.h"
#ifndef FALSE
#define FALSE 0
#endif

View File

@@ -39,8 +39,6 @@
#include "fileref.h"
#include "tag.h"
using namespace std;
bool isArgument(const char *s)
{
return strlen(s) == 2 && s[0] == '-';
@@ -48,32 +46,33 @@ bool isArgument(const char *s)
bool isFile(const char *s)
{
struct stat st;
#ifdef _WIN32
return ::stat(s, &st) == 0 && (st.st_mode & (S_IFREG));
struct _stat64 st;
return ::_stat64(s, &st) == 0 && (st.st_mode & S_IFREG);
#else
struct stat st;
return ::stat(s, &st) == 0 && (st.st_mode & (S_IFREG | S_IFLNK));
#endif
}
void usage()
{
cout << endl;
cout << "Usage: tagwriter <fields> <files>" << endl;
cout << endl;
cout << "Where the valid fields are:" << endl;
cout << " -t <title>" << 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 << " -R <tagname> <tagvalue>" << endl;
cout << " -I <tagname> <tagvalue>" << endl;
cout << " -D <tagname>" << endl;
cout << " -p <picturefile> <description> (\"\" \"\" to remove)" << endl;
cout << endl;
std::cout << std::endl;
std::cout << "Usage: tagwriter <fields> <files>" << std::endl;
std::cout << std::endl;
std::cout << "Where the valid fields are:" << std::endl;
std::cout << " -t <title>" << std::endl;
std::cout << " -a <artist>" << std::endl;
std::cout << " -A <album>" << std::endl;
std::cout << " -c <comment>" << std::endl;
std::cout << " -g <genre>" << std::endl;
std::cout << " -y <year>" << std::endl;
std::cout << " -T <track>" << std::endl;
std::cout << " -R <tagname> <tagvalue>" << std::endl;
std::cout << " -I <tagname> <tagvalue>" << std::endl;
std::cout << " -D <tagname>" << std::endl;
std::cout << " -p <picturefile> <description> (\"\" \"\" to remove)" << std::endl;
std::cout << std::endl;
exit(1);
}
@@ -87,10 +86,10 @@ void checkForRejectedProperties(const TagLib::PropertyMap &tags)
longest = i->first.size();
}
}
cout << "-- rejected TAGs (properties) --" << endl;
std::cout << "-- rejected TAGs (properties) --" << std::endl;
for(auto i = tags.begin(); i != tags.end(); ++i) {
for(auto j = i->second.begin(); j != i->second.end(); ++j) {
cout << left << std::setw(longest) << i->first << " - " << '"' << *j << '"' << endl;
std::cout << std::left << std::setw(longest) << i->first << " - " << '"' << *j << '"' << std::endl;
}
}
}
@@ -176,12 +175,12 @@ int main(int argc, char *argv[])
numArgsConsumed = 3;
if(!value.isEmpty()) {
if(!isFile(value.toCString())) {
cout << value.toCString() << " not found." << endl;
std::cout << value.toCString() << " not found." << std::endl;
return 1;
}
ifstream picture;
picture.open(value.toCString());
stringstream buffer;
std::ifstream picture;
picture.open(value.toCString(), std::ios::in | std::ios::binary);
std::stringstream buffer;
buffer << picture.rdbuf();
picture.close();
TagLib::String buf(buffer.str());

View File

@@ -1,38 +1,77 @@
set(CMAKE_INCLUDE_CURRENT_DIR ON)
include_directories(
set(tag_HDR_DIRS
${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
${CMAKE_CURRENT_SOURCE_DIR}/dsf
${CMAKE_CURRENT_SOURCE_DIR}/dsdiff
)
if(WITH_ASF)
set(tag_HDR_DIRS ${tag_HDR_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/asf
)
endif()
if(WITH_VORBIS)
set(tag_HDR_DIRS ${tag_HDR_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/ogg
${CMAKE_CURRENT_SOURCE_DIR}/ogg/flac
${CMAKE_CURRENT_SOURCE_DIR}/flac
${CMAKE_CURRENT_SOURCE_DIR}/ogg/vorbis
${CMAKE_CURRENT_SOURCE_DIR}/ogg/speex
${CMAKE_CURRENT_SOURCE_DIR}/ogg/opus
)
endif()
if(WITH_APE)
set(tag_HDR_DIRS ${tag_HDR_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/mpc
${CMAKE_CURRENT_SOURCE_DIR}/ape
${CMAKE_CURRENT_SOURCE_DIR}/wavpack
)
endif()
if(WITH_MP4)
set(tag_HDR_DIRS ${tag_HDR_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/mp4
)
endif()
if(WITH_TRUEAUDIO)
set(tag_HDR_DIRS ${tag_HDR_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/trueaudio
)
endif()
if(WITH_RIFF)
set(tag_HDR_DIRS ${tag_HDR_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/riff
${CMAKE_CURRENT_SOURCE_DIR}/riff/aiff
${CMAKE_CURRENT_SOURCE_DIR}/riff/wav
)
endif()
if(WITH_MOD)
set(tag_HDR_DIRS ${tag_HDR_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/mod
${CMAKE_CURRENT_SOURCE_DIR}/s3m
${CMAKE_CURRENT_SOURCE_DIR}/it
${CMAKE_CURRENT_SOURCE_DIR}/xm
)
endif()
if(WITH_DSF)
set(tag_HDR_DIRS ${tag_HDR_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/dsf
${CMAKE_CURRENT_SOURCE_DIR}/dsdiff
)
endif()
if(WITH_SHORTEN)
set(tag_HDR_DIRS ${tag_HDR_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/shorten
)
endif()
include_directories(${tag_HDR_DIRS})
set(tag_HDRS
tag.h
fileref.h
audioproperties.h
taglib_export.h
${CMAKE_CURRENT_BINARY_DIR}/../taglib_config.h
toolkit/taglib.h
toolkit/tstring.h
toolkit/tlist.h
@@ -82,66 +121,105 @@ set(tag_HDRS
mpeg/id3v2/frames/chapterframe.h
mpeg/id3v2/frames/tableofcontentsframe.h
mpeg/id3v2/frames/podcastframe.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
mp4/mp4itemfactory.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
dsf/dsffile.h
dsf/dsfproperties.h
dsdiff/dsdifffile.h
dsdiff/dsdiffproperties.h
dsdiff/dsdiffdiintag.h
)
if(WITH_VORBIS)
set(tag_HDRS ${tag_HDRS}
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
)
endif()
if(WITH_APE)
set(tag_HDRS ${tag_HDRS}
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
)
endif()
if(WITH_TRUEAUDIO)
set(tag_HDRS ${tag_HDRS}
trueaudio/trueaudiofile.h
trueaudio/trueaudioproperties.h
)
endif()
if(WITH_RIFF)
set(tag_HDRS ${tag_HDRS}
riff/rifffile.h
riff/aiff/aifffile.h
riff/aiff/aiffproperties.h
riff/wav/wavfile.h
riff/wav/wavproperties.h
riff/wav/infotag.h
)
endif()
if(WITH_ASF)
set(tag_HDRS ${tag_HDRS}
asf/asffile.h
asf/asfproperties.h
asf/asftag.h
asf/asfattribute.h
asf/asfpicture.h
)
endif()
if(WITH_MP4)
set(tag_HDRS ${tag_HDRS}
mp4/mp4file.h
mp4/mp4atom.h
mp4/mp4tag.h
mp4/mp4item.h
mp4/mp4properties.h
mp4/mp4coverart.h
mp4/mp4itemfactory.h
)
endif()
if(WITH_MOD)
set(tag_HDRS ${tag_HDRS}
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
)
endif()
if(WITH_DSF)
set(tag_HDRS ${tag_HDRS}
dsf/dsffile.h
dsf/dsfproperties.h
dsdiff/dsdifffile.h
dsdiff/dsdiffproperties.h
dsdiff/dsdiffdiintag.h
)
endif()
if(WITH_SHORTEN)
set(tag_HDRS ${tag_HDRS}
shorten/shortenfile.h
shorten/shortenproperties.h
shorten/shortentag.h
)
endif()
set(mpeg_SRCS
mpeg/mpegfile.cpp
@@ -185,128 +263,152 @@ set(frames_SRCS
mpeg/id3v2/frames/podcastframe.cpp
)
set(ogg_SRCS
ogg/oggfile.cpp
ogg/oggpage.cpp
ogg/oggpageheader.cpp
ogg/xiphcomment.cpp
)
if(WITH_VORBIS)
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(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(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(oggflacs_SRCS
ogg/flac/oggflacfile.cpp
)
set(mpc_SRCS
mpc/mpcfile.cpp
mpc/mpcproperties.cpp
)
set(speex_SRCS
ogg/speex/speexfile.cpp
ogg/speex/speexproperties.cpp
)
set(mp4_SRCS
mp4/mp4file.cpp
mp4/mp4atom.cpp
mp4/mp4tag.cpp
mp4/mp4item.cpp
mp4/mp4properties.cpp
mp4/mp4coverart.cpp
mp4/mp4itemfactory.cpp
)
set(opus_SRCS
ogg/opus/opusfile.cpp
ogg/opus/opusproperties.cpp
)
endif()
set(ape_SRCS
ape/apetag.cpp
ape/apefooter.cpp
ape/apeitem.cpp
ape/apefile.cpp
ape/apeproperties.cpp
)
if(WITH_APE)
set(mpc_SRCS
mpc/mpcfile.cpp
mpc/mpcproperties.cpp
)
set(wavpack_SRCS
wavpack/wavpackfile.cpp
wavpack/wavpackproperties.cpp
)
set(ape_SRCS
ape/apetag.cpp
ape/apefooter.cpp
ape/apeitem.cpp
ape/apefile.cpp
ape/apeproperties.cpp
)
set(speex_SRCS
ogg/speex/speexfile.cpp
ogg/speex/speexproperties.cpp
)
set(wavpack_SRCS
wavpack/wavpackfile.cpp
wavpack/wavpackproperties.cpp
)
endif()
set(opus_SRCS
ogg/opus/opusfile.cpp
ogg/opus/opusproperties.cpp
)
if(WITH_MP4)
set(mp4_SRCS
mp4/mp4file.cpp
mp4/mp4atom.cpp
mp4/mp4tag.cpp
mp4/mp4item.cpp
mp4/mp4properties.cpp
mp4/mp4coverart.cpp
mp4/mp4itemfactory.cpp
)
endif()
set(trueaudio_SRCS
trueaudio/trueaudiofile.cpp
trueaudio/trueaudioproperties.cpp
)
if(WITH_TRUEAUDIO)
set(trueaudio_SRCS
trueaudio/trueaudiofile.cpp
trueaudio/trueaudioproperties.cpp
)
endif()
set(asf_SRCS
asf/asftag.cpp
asf/asffile.cpp
asf/asfproperties.cpp
asf/asfattribute.cpp
asf/asfpicture.cpp
)
if(WITH_ASF)
set(asf_SRCS
asf/asftag.cpp
asf/asffile.cpp
asf/asfproperties.cpp
asf/asfattribute.cpp
asf/asfpicture.cpp
)
endif()
set(riff_SRCS
riff/rifffile.cpp
)
if(WITH_RIFF)
set(riff_SRCS
riff/rifffile.cpp
)
set(aiff_SRCS
riff/aiff/aifffile.cpp
riff/aiff/aiffproperties.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(wav_SRCS
riff/wav/wavfile.cpp
riff/wav/wavproperties.cpp
riff/wav/infotag.cpp
)
endif()
set(mod_SRCS
mod/modfilebase.cpp
mod/modfile.cpp
mod/modtag.cpp
mod/modproperties.cpp
)
if(WITH_MOD)
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(s3m_SRCS
s3m/s3mfile.cpp
s3m/s3mproperties.cpp
)
set(it_SRCS
it/itfile.cpp
it/itproperties.cpp
)
set(it_SRCS
it/itfile.cpp
it/itproperties.cpp
)
set(xm_SRCS
xm/xmfile.cpp
xm/xmproperties.cpp
)
set(xm_SRCS
xm/xmfile.cpp
xm/xmproperties.cpp
)
endif()
set(dsf_SRCS
dsf/dsffile.cpp
dsf/dsfproperties.cpp
)
if(WITH_DSF)
set(dsf_SRCS
dsf/dsffile.cpp
dsf/dsfproperties.cpp
)
set(dsdiff_SRCS
dsdiff/dsdifffile.cpp
dsdiff/dsdiffproperties.cpp
dsdiff/dsdiffdiintag.cpp
)
set(dsdiff_SRCS
dsdiff/dsdifffile.cpp
dsdiff/dsdiffproperties.cpp
dsdiff/dsdiffdiintag.cpp
)
endif()
if(WITH_SHORTEN)
set(shorten_SRCS
shorten/shortenfile.cpp
shorten/shortenproperties.cpp
shorten/shortentag.cpp
)
endif()
set(toolkit_SRCS
toolkit/tstring.cpp
@@ -331,7 +433,7 @@ set(tag_LIB_SRCS
${vorbis_SRCS} ${oggflacs_SRCS} ${mpc_SRCS} ${ape_SRCS} ${toolkit_SRCS} ${flacs_SRCS}
${wavpack_SRCS} ${speex_SRCS} ${trueaudio_SRCS} ${riff_SRCS} ${aiff_SRCS} ${wav_SRCS}
${asf_SRCS} ${mp4_SRCS} ${mod_SRCS} ${s3m_SRCS} ${it_SRCS} ${xm_SRCS} ${opus_SRCS}
${dsf_SRCS} ${dsdiff_SRCS}
${dsf_SRCS} ${dsdiff_SRCS} ${shorten_SRCS}
tag.cpp
tagunion.cpp
fileref.cpp
@@ -347,7 +449,7 @@ target_include_directories(tag INTERFACE
)
target_link_libraries(tag
PRIVATE $<$<TARGET_EXISTS:utf8::cpp>:utf8::cpp>
PRIVATE $<IF:$<TARGET_EXISTS:utf8::cpp>,utf8::cpp,$<$<TARGET_EXISTS:utf8cpp>:utf8cpp>>
$<$<TARGET_EXISTS:ZLIB::ZLIB>:ZLIB::ZLIB>
)
@@ -359,6 +461,9 @@ set_target_properties(tag PROPERTIES
INTERFACE_LINK_LIBRARIES "${ZLIB_INTERFACE_LINK_LIBRARIES}"
PUBLIC_HEADER "${tag_HDRS}"
)
if(NOT BUILD_SHARED_LIBS)
target_compile_definitions(tag PUBLIC TAGLIB_STATIC)
endif()
if(VISIBILITY_HIDDEN)
set_target_properties(tag PROPERTIES C_VISIBILITY_PRESET hidden)
set_target_properties(tag PROPERTIES CXX_VISIBILITY_PRESET hidden)

View File

@@ -139,7 +139,7 @@ void APE::Properties::read(File *file, offset_t streamLength)
if(d->sampleFrames > 0 && d->sampleRate > 0) {
const auto length = static_cast<double>(d->sampleFrames) * 1000.0 / d->sampleRate;
d->length = static_cast<int>(length + 0.5);
d->bitrate = static_cast<int>(streamLength * 8.0 / length + 0.5);
d->bitrate = static_cast<int>(static_cast<double>(streamLength) * 8.0 / length + 0.5);
}
}

View File

@@ -302,16 +302,16 @@ ByteVector ASF::Attribute::render(const String &name, int kind) const
if(kind == 0) {
data = renderString(name, true) +
ByteVector::fromShort(static_cast<int>(d->type), false) +
ByteVector::fromShort(data.size(), false) +
ByteVector::fromShort(static_cast<short>(d->type), false) +
ByteVector::fromShort(static_cast<short>(data.size()), false) +
data;
}
else {
ByteVector nameData = renderString(name);
data = ByteVector::fromShort(kind == 2 ? d->language : 0, false) +
ByteVector::fromShort(d->stream, false) +
ByteVector::fromShort(nameData.size(), false) +
ByteVector::fromShort(static_cast<int>(d->type), false) +
data = ByteVector::fromShort(static_cast<short>(kind == 2 ? d->language : 0), false) +
ByteVector::fromShort(static_cast<short>(d->stream), false) +
ByteVector::fromShort(static_cast<short>(nameData.size()), false) +
ByteVector::fromShort(static_cast<short>(d->type), false) +
ByteVector::fromUInt(data.size(), false) +
nameData +
data;

View File

@@ -221,7 +221,8 @@ void ASF::File::FilePrivate::FilePropertiesObject::parse(ASF::File *file, long l
const long long duration = data.toLongLong(40, false);
const long long preroll = data.toLongLong(56, false);
file->d->properties->setLengthInMilliseconds(static_cast<int>(duration / 10000.0 - preroll + 0.5));
file->d->properties->setLengthInMilliseconds(
static_cast<int>(static_cast<double>(duration) / 10000.0 - static_cast<double>(preroll) + 0.5));
}
ByteVector ASF::File::FilePrivate::StreamPropertiesObject::guid() const
@@ -271,11 +272,11 @@ ByteVector ASF::File::FilePrivate::ContentDescriptionObject::render(ASF::File *f
const ByteVector v4 = renderString(file->d->tag->comment());
const ByteVector v5 = renderString(file->d->tag->rating());
data.clear();
data.append(ByteVector::fromShort(v1.size(), false));
data.append(ByteVector::fromShort(v2.size(), false));
data.append(ByteVector::fromShort(v3.size(), false));
data.append(ByteVector::fromShort(v4.size(), false));
data.append(ByteVector::fromShort(v5.size(), false));
data.append(ByteVector::fromShort(static_cast<short>(v1.size()), false));
data.append(ByteVector::fromShort(static_cast<short>(v2.size()), false));
data.append(ByteVector::fromShort(static_cast<short>(v3.size()), false));
data.append(ByteVector::fromShort(static_cast<short>(v4.size()), false));
data.append(ByteVector::fromShort(static_cast<short>(v5.size()), false));
data.append(v1);
data.append(v2);
data.append(v3);
@@ -302,7 +303,7 @@ void ASF::File::FilePrivate::ExtendedContentDescriptionObject::parse(ASF::File *
ByteVector ASF::File::FilePrivate::ExtendedContentDescriptionObject::render(ASF::File *file)
{
data.clear();
data.append(ByteVector::fromShort(attributeData.size(), false));
data.append(ByteVector::fromShort(static_cast<short>(attributeData.size()), false));
data.append(attributeData.toByteVector(""));
return BaseObject::render(file);
}
@@ -325,7 +326,7 @@ void ASF::File::FilePrivate::MetadataObject::parse(ASF::File *file, long long /*
ByteVector ASF::File::FilePrivate::MetadataObject::render(ASF::File *file)
{
data.clear();
data.append(ByteVector::fromShort(attributeData.size(), false));
data.append(ByteVector::fromShort(static_cast<short>(attributeData.size()), false));
data.append(attributeData.toByteVector(""));
return BaseObject::render(file);
}
@@ -348,7 +349,7 @@ void ASF::File::FilePrivate::MetadataLibraryObject::parse(ASF::File *file, long
ByteVector ASF::File::FilePrivate::MetadataLibraryObject::render(ASF::File *file)
{
data.clear();
data.append(ByteVector::fromShort(attributeData.size(), false));
data.append(ByteVector::fromShort(static_cast<short>(attributeData.size()), false));
data.append(attributeData.toByteVector(""));
return BaseObject::render(file);
}

View File

@@ -90,7 +90,7 @@ namespace TagLib
{
ByteVector data = str.data(String::UTF16LE) + ByteVector::fromShort(0, false);
if(includeLength) {
data = ByteVector::fromShort(data.size(), false) + data;
data = ByteVector::fromShort(static_cast<short>(data.size()), false) + data;
}
return data;
}

View File

@@ -26,7 +26,7 @@
#ifndef TAGLIB_DSDIFFFILE_H
#define TAGLIB_DSDIFFFILE_H
#include "rifffile.h"
#include "tfile.h"
#include "id3v2tag.h"
#include "dsdiffproperties.h"
#include "dsdiffdiintag.h"

View File

@@ -58,7 +58,7 @@ DSDIFF::Properties::Properties(unsigned int sampleRate,
d->sampleRate = sampleRate;
d->bitrate = bitrate;
d->length = d->sampleRate > 0
? static_cast<int>(d->sampleCount * 1000.0 / d->sampleRate + 0.5)
? static_cast<int>(static_cast<double>(d->sampleCount) * 1000.0 / d->sampleRate + 0.5)
: 0;
}

View File

@@ -59,7 +59,7 @@ bool DSF::File::isSupported(IOStream *stream)
return id.startsWith("DSD ");
}
DSF::File::File(FileName file, bool readProperties,
DSF::File::File(FileName file, bool,
AudioProperties::ReadStyle propertiesStyle,
ID3v2::FrameFactory *frameFactory) :
TagLib::File(file),
@@ -69,7 +69,7 @@ DSF::File::File(FileName file, bool readProperties,
read(propertiesStyle);
}
DSF::File::File(IOStream *stream, bool readProperties,
DSF::File::File(IOStream *stream, bool,
AudioProperties::ReadStyle propertiesStyle,
ID3v2::FrameFactory *frameFactory) :
TagLib::File(stream),

View File

@@ -129,6 +129,6 @@ void DSF::Properties::read(const ByteVector &data)
d->bitrate = static_cast<unsigned int>(
d->samplingFrequency * d->bitsPerSample * d->channelNum / 1000.0 + 0.5);
d->length = d->samplingFrequency > 0
? static_cast<unsigned int>(d->sampleCount * 1000.0 / d->samplingFrequency + 0.5)
? static_cast<unsigned int>(static_cast<double>(d->sampleCount) * 1000.0 / d->samplingFrequency + 0.5)
: 0;
}

View File

@@ -32,31 +32,51 @@
#include <cstring>
#include <utility>
#include "taglib_config.h"
#include "tfilestream.h"
#include "tpropertymap.h"
#include "tstringlist.h"
#include "tvariant.h"
#include "tdebug.h"
#include "aifffile.h"
#include "apefile.h"
#include "asffile.h"
#include "flacfile.h"
#include "itfile.h"
#include "modfile.h"
#include "mp4file.h"
#include "mpcfile.h"
#include "mpegfile.h"
#ifdef TAGLIB_WITH_RIFF
#include "aifffile.h"
#include "wavfile.h"
#endif
#ifdef TAGLIB_WITH_APE
#include "apefile.h"
#include "mpcfile.h"
#include "wavpackfile.h"
#endif
#ifdef TAGLIB_WITH_ASF
#include "asffile.h"
#endif
#ifdef TAGLIB_WITH_VORBIS
#include "flacfile.h"
#include "speexfile.h"
#include "vorbisfile.h"
#include "oggflacfile.h"
#include "opusfile.h"
#include "s3mfile.h"
#include "speexfile.h"
#include "trueaudiofile.h"
#include "vorbisfile.h"
#include "wavfile.h"
#include "wavpackfile.h"
#endif
#ifdef TAGLIB_WITH_MOD
#include "itfile.h"
#include "modfile.h"
#include "xmfile.h"
#include "s3mfile.h"
#endif
#ifdef TAGLIB_WITH_MP4
#include "mp4file.h"
#endif
#ifdef TAGLIB_WITH_TRUEAUDIO
#include "trueaudiofile.h"
#endif
#ifdef TAGLIB_WITH_DSF
#include "dsffile.h"
#include "dsdifffile.h"
#endif
#ifdef TAGLIB_WITH_SHORTEN
#include "shortenfile.h"
#endif
using namespace TagLib;
@@ -135,6 +155,7 @@ namespace
if(ext == "MP3" || ext == "MP2" || ext == "AAC")
file = new MPEG::File(stream, readAudioProperties, audioPropertiesStyle);
#ifdef TAGLIB_WITH_VORBIS
else if(ext == "OGG")
file = new Ogg::Vorbis::File(stream, readAudioProperties, audioPropertiesStyle);
else if(ext == "OGA") {
@@ -147,26 +168,38 @@ namespace
}
else if(ext == "FLAC")
file = new FLAC::File(stream, readAudioProperties, audioPropertiesStyle);
else if(ext == "MPC")
file = new MPC::File(stream, readAudioProperties, audioPropertiesStyle);
else if(ext == "WV")
file = new WavPack::File(stream, readAudioProperties, audioPropertiesStyle);
else if(ext == "SPX")
file = new Ogg::Speex::File(stream, readAudioProperties, audioPropertiesStyle);
else if(ext == "OPUS")
file = new Ogg::Opus::File(stream, readAudioProperties, audioPropertiesStyle);
#endif
#ifdef TAGLIB_WITH_APE
else if(ext == "MPC")
file = new MPC::File(stream, readAudioProperties, audioPropertiesStyle);
else if(ext == "WV")
file = new WavPack::File(stream, readAudioProperties, audioPropertiesStyle);
else if(ext == "APE")
file = new APE::File(stream, readAudioProperties, audioPropertiesStyle);
#endif
#ifdef TAGLIB_WITH_TRUEAUDIO
else if(ext == "TTA")
file = new TrueAudio::File(stream, readAudioProperties, audioPropertiesStyle);
#endif
#ifdef TAGLIB_WITH_MP4
else if(ext == "M4A" || ext == "M4R" || ext == "M4B" || ext == "M4P" || ext == "MP4" || ext == "3G2" || ext == "M4V")
file = new MP4::File(stream, readAudioProperties, audioPropertiesStyle);
#endif
#ifdef TAGLIB_WITH_ASF
else if(ext == "WMA" || ext == "ASF")
file = new ASF::File(stream, readAudioProperties, audioPropertiesStyle);
#endif
#ifdef TAGLIB_WITH_RIFF
else if(ext == "AIF" || ext == "AIFF" || ext == "AFC" || ext == "AIFC")
file = new RIFF::AIFF::File(stream, readAudioProperties, audioPropertiesStyle);
else if(ext == "WAV")
file = new RIFF::WAV::File(stream, readAudioProperties, audioPropertiesStyle);
else if(ext == "APE")
file = new APE::File(stream, readAudioProperties, audioPropertiesStyle);
#endif
#ifdef TAGLIB_WITH_MOD
// module, nst and wow are possible but uncommon extensions
else if(ext == "MOD" || ext == "MODULE" || ext == "NST" || ext == "WOW")
file = new Mod::File(stream, readAudioProperties, audioPropertiesStyle);
@@ -176,10 +209,17 @@ namespace
file = new IT::File(stream, readAudioProperties, audioPropertiesStyle);
else if(ext == "XM")
file = new XM::File(stream, readAudioProperties, audioPropertiesStyle);
#endif
#ifdef TAGLIB_WITH_DSF
else if(ext == "DSF")
file = new DSF::File(stream, readAudioProperties, audioPropertiesStyle);
else if(ext == "DFF" || ext == "DSDIFF")
file = new DSDIFF::File(stream, readAudioProperties, audioPropertiesStyle);
#endif
#ifdef TAGLIB_WITH_SHORTEN
else if(ext == "SHN")
file = new Shorten::File(stream, readAudioProperties, audioPropertiesStyle);
#endif
// if file is not valid, leave it to content-based detection.
@@ -201,36 +241,54 @@ namespace
if(MPEG::File::isSupported(stream))
file = new MPEG::File(stream, readAudioProperties, audioPropertiesStyle);
#ifdef TAGLIB_WITH_VORBIS
else if(Ogg::Vorbis::File::isSupported(stream))
file = new Ogg::Vorbis::File(stream, readAudioProperties, audioPropertiesStyle);
else if(Ogg::FLAC::File::isSupported(stream))
file = new Ogg::FLAC::File(stream, readAudioProperties, audioPropertiesStyle);
else if(FLAC::File::isSupported(stream))
file = new FLAC::File(stream, readAudioProperties, audioPropertiesStyle);
else if(MPC::File::isSupported(stream))
file = new MPC::File(stream, readAudioProperties, audioPropertiesStyle);
else if(WavPack::File::isSupported(stream))
file = new WavPack::File(stream, readAudioProperties, audioPropertiesStyle);
else if(Ogg::Speex::File::isSupported(stream))
file = new Ogg::Speex::File(stream, readAudioProperties, audioPropertiesStyle);
else if(Ogg::Opus::File::isSupported(stream))
file = new Ogg::Opus::File(stream, readAudioProperties, audioPropertiesStyle);
#endif
#ifdef TAGLIB_WITH_APE
else if(MPC::File::isSupported(stream))
file = new MPC::File(stream, readAudioProperties, audioPropertiesStyle);
else if(WavPack::File::isSupported(stream))
file = new WavPack::File(stream, readAudioProperties, audioPropertiesStyle);
else if(APE::File::isSupported(stream))
file = new APE::File(stream, readAudioProperties, audioPropertiesStyle);
#endif
#ifdef TAGLIB_WITH_TRUEAUDIO
else if(TrueAudio::File::isSupported(stream))
file = new TrueAudio::File(stream, readAudioProperties, audioPropertiesStyle);
#endif
#ifdef TAGLIB_WITH_MP4
else if(MP4::File::isSupported(stream))
file = new MP4::File(stream, readAudioProperties, audioPropertiesStyle);
#endif
#ifdef TAGLIB_WITH_ASF
else if(ASF::File::isSupported(stream))
file = new ASF::File(stream, readAudioProperties, audioPropertiesStyle);
#endif
#ifdef TAGLIB_WITH_RIFF
else if(RIFF::AIFF::File::isSupported(stream))
file = new RIFF::AIFF::File(stream, readAudioProperties, audioPropertiesStyle);
else if(RIFF::WAV::File::isSupported(stream))
file = new RIFF::WAV::File(stream, readAudioProperties, audioPropertiesStyle);
else if(APE::File::isSupported(stream))
file = new APE::File(stream, readAudioProperties, audioPropertiesStyle);
#endif
#ifdef TAGLIB_WITH_DSF
else if(DSF::File::isSupported(stream))
file = new DSF::File(stream, readAudioProperties, audioPropertiesStyle);
else if(DSDIFF::File::isSupported(stream))
file = new DSDIFF::File(stream, readAudioProperties, audioPropertiesStyle);
#endif
#ifdef TAGLIB_WITH_SHORTEN
else if(Shorten::File::isSupported(stream))
file = new Shorten::File(stream, readAudioProperties, audioPropertiesStyle);
#endif
// isSupported() only does a quick check, so double check the file here.
@@ -263,7 +321,7 @@ public:
return !file || !file->isValid();
}
bool isNullWithDebugMessage(const String &methodName) const
bool isNullWithDebugMessage([[maybe_unused]] const String &methodName) const
{
if(isNull()) {
debug("FileRef::" + methodName + "() - Called without a valid file.");
@@ -400,17 +458,25 @@ StringList FileRef::defaultFileExtensions()
{
StringList l;
l.append("mp3");
l.append("mp2");
l.append("aac");
#ifdef TAGLIB_WITH_VORBIS
l.append("ogg");
l.append("flac");
l.append("oga");
l.append("opus");
l.append("mp3");
l.append("mp2");
l.append("spx");
#endif
#ifdef TAGLIB_WITH_APE
l.append("mpc");
l.append("wv");
l.append("spx");
l.append("ape");
#endif
#ifdef TAGLIB_WITH_TRUEAUDIO
l.append("tta");
l.append("aac");
#endif
#ifdef TAGLIB_WITH_MP4
l.append("m4a");
l.append("m4r");
l.append("m4b");
@@ -418,14 +484,19 @@ StringList FileRef::defaultFileExtensions()
l.append("3g2");
l.append("mp4");
l.append("m4v");
#endif
#ifdef TAGLIB_WITH_ASF
l.append("wma");
l.append("asf");
#endif
#ifdef TAGLIB_WITH_RIFF
l.append("aif");
l.append("aiff");
l.append("afc");
l.append("aifc");
l.append("wav");
l.append("ape");
#endif
#ifdef TAGLIB_WITH_MOD
l.append("mod");
l.append("module"); // alias for "mod"
l.append("nst"); // alias for "mod"
@@ -433,9 +504,15 @@ StringList FileRef::defaultFileExtensions()
l.append("s3m");
l.append("it");
l.append("xm");
#endif
#ifdef TAGLIB_WITH_DSF
l.append("dsf");
l.append("dff");
l.append("dsdiff"); // alias for "dff"
#endif
#ifdef TAGLIB_WITH_SHORTEN
l.append("shn");
#endif
return l;
}

View File

@@ -265,12 +265,19 @@ bool FLAC::File::save()
// Render data for the metadata blocks
ByteVector data;
for(const auto &block : std::as_const(d->blocks)) {
ByteVector blockData = block->render();
for(auto it = d->blocks.begin(); it != d->blocks.end();) {
ByteVector blockData = (*it)->render();
ByteVector blockHeader = ByteVector::fromUInt(blockData.size());
blockHeader[0] = block->code();
if(blockHeader[0] != 0) {
debug("FLAC::File::save() -- Removing too large block.");
delete *it;
it = d->blocks.erase(it);
continue;
}
blockHeader[0] = static_cast<char>((*it)->code());
data.append(blockHeader);
data.append(blockData);
++it;
}
// Compute the amount of padding, and append that to data.

View File

@@ -134,7 +134,7 @@ void FLAC::Properties::read(const ByteVector &data, offset_t streamLength)
if(d->sampleFrames > 0 && d->sampleRate > 0) {
const auto length = static_cast<double>(d->sampleFrames) * 1000.0 / d->sampleRate;
d->length = static_cast<int>(length + 0.5);
d->bitrate = static_cast<int>(streamLength * 8.0 / length + 0.5);
d->bitrate = static_cast<int>(static_cast<double>(streamLength) * 8.0 / length + 0.5);
}
if(data.size() >= pos + 16)

View File

@@ -167,7 +167,7 @@ bool IT::File::save()
if(messageOffset + messageLength >= fileSize) {
// append new message
seek(54);
writeU16L(message.size());
writeU16L(static_cast<unsigned short>(message.size()));
writeU32L(messageOffset);
seek(messageOffset);
writeBlock(message);

View File

@@ -95,13 +95,6 @@ MP4::Atom::Atom(File *file)
}
d->name = header.mid(4, 4);
for(int i = 0; i < 4; ++i) {
if(const char ch = d->name.at(i); (ch < ' ' || ch > '~') && ch != '\251') {
debug("MP4: Invalid atom type");
d->length = 0;
file->seek(0, File::End);
}
}
for(auto c : containers) {
if(d->name == c) {

View File

@@ -60,8 +60,8 @@ namespace TagLib {
#ifndef DO_NOT_DOCUMENT
struct AtomData {
AtomData(AtomDataType type, const ByteVector &data) :
type(type), data(data) { }
AtomData(AtomDataType ptype, const ByteVector &pdata) :
type(ptype), data(pdata) { }
AtomDataType type;
int locale { 0 };
ByteVector data;

View File

@@ -35,6 +35,12 @@
using namespace TagLib;
using namespace MP4;
namespace {
constexpr char freeFormPrefix[] = "----:com.apple.iTunes:";
} // namespace
class ItemFactory::ItemFactoryPrivate
{
public:
@@ -231,7 +237,11 @@ String ItemFactory::propertyKeyForName(const ByteVector &name) const
if(d->propertyKeyForName.isEmpty()) {
d->propertyKeyForName = namePropertyMap();
}
return d->propertyKeyForName.value(name);
String key = d->propertyKeyForName.value(name);
if(key.isEmpty() && name.startsWith(freeFormPrefix)) {
key = name.mid(std::size(freeFormPrefix) - 1);
}
return key;
}
ByteVector ItemFactory::nameForPropertyKey(const String &key) const
@@ -244,7 +254,14 @@ ByteVector ItemFactory::nameForPropertyKey(const String &key) const
d->nameForPropertyKey[t] = k;
}
}
return d->nameForPropertyKey.value(key);
ByteVector name = d->nameForPropertyKey.value(key);
if(name.isEmpty() && !key.isEmpty()) {
const auto &firstChar = key[0];
if(firstChar >= 'A' && firstChar <= 'Z') {
name = (freeFormPrefix + key).data(String::UTF8);
}
}
return name;
}
////////////////////////////////////////////////////////////////////////////////
@@ -383,7 +400,7 @@ Map<ByteVector, String> ItemFactory::namePropertyMap() const
}
MP4::AtomDataList ItemFactory::parseData2(
const MP4::Atom *atom, const ByteVector &data, int expectedFlags,
const MP4::Atom *, const ByteVector &data, int expectedFlags,
bool freeForm)
{
AtomDataList result;
@@ -646,7 +663,7 @@ ByteVector ItemFactory::renderInt(
const ByteVector &name, const MP4::Item &item)
{
ByteVectorList data;
data.append(ByteVector::fromShort(item.toInt()));
data.append(ByteVector::fromShort(static_cast<short>(item.toInt())));
return renderData(name, TypeInteger, data);
}
@@ -686,8 +703,8 @@ ByteVector ItemFactory::renderIntPair(
{
ByteVectorList data;
data.append(ByteVector(2, '\0') +
ByteVector::fromShort(item.toIntPair().first) +
ByteVector::fromShort(item.toIntPair().second) +
ByteVector::fromShort(static_cast<short>(item.toIntPair().first)) +
ByteVector::fromShort(static_cast<short>(item.toIntPair().second)) +
ByteVector(2, '\0'));
return renderData(name, TypeImplicit, data);
}
@@ -697,8 +714,8 @@ ByteVector ItemFactory::renderIntPairNoTrailing(
{
ByteVectorList data;
data.append(ByteVector(2, '\0') +
ByteVector::fromShort(item.toIntPair().first) +
ByteVector::fromShort(item.toIntPair().second));
ByteVector::fromShort(static_cast<short>(item.toIntPair().first)) +
ByteVector::fromShort(static_cast<short>(item.toIntPair().second)));
return renderData(name, TypeImplicit, data);
}

View File

@@ -196,7 +196,7 @@ MP4::Properties::read(File *file, const Atoms *atoms)
}
}
if(unit > 0 && length > 0)
d->length = static_cast<int>(length * 1000.0 / unit + 0.5);
d->length = static_cast<int>(static_cast<double>(length) * 1000.0 / static_cast<double>(unit) + 0.5);
MP4::Atom *atom = trak->find("mdia", "minf", "stbl", "stsd");
if(!atom) {

View File

@@ -229,7 +229,7 @@ void MPC::Properties::readSV8(File *file, offset_t streamLength)
frameCount > 0 && d->sampleRate > 0) {
const auto length = static_cast<double>(frameCount) * 1000.0 / d->sampleRate;
d->length = static_cast<int>(length + 0.5);
d->bitrate = static_cast<int>(streamLength * 8.0 / length + 0.5);
d->bitrate = static_cast<int>(static_cast<double>(streamLength) * 8.0 / length + 0.5);
}
}
else if (packetType == "RG") {
@@ -331,6 +331,6 @@ void MPC::Properties::readSV7(const ByteVector &data, offset_t streamLength)
d->length = static_cast<int>(length + 0.5);
if(d->bitrate == 0)
d->bitrate = static_cast<int>(streamLength * 8.0 / length + 0.5);
d->bitrate = static_cast<int>(static_cast<double>(streamLength) * 8.0 / length + 0.5);
}
}

View File

@@ -176,7 +176,7 @@ void ID3v1::Tag::setComment(const String &s)
void ID3v1::Tag::setGenre(const String &s)
{
d->genre = ID3v1::genreIndex(s);
d->genre = static_cast<unsigned char>(ID3v1::genreIndex(s));
}
void ID3v1::Tag::setYear(unsigned int i)
@@ -186,7 +186,7 @@ void ID3v1::Tag::setYear(unsigned int i)
void ID3v1::Tag::setTrack(unsigned int i)
{
d->track = i < 256 ? i : 0;
d->track = static_cast<unsigned char>(i < 256 ? i : 0);
}
unsigned int ID3v1::Tag::genreNumber() const
@@ -196,7 +196,7 @@ unsigned int ID3v1::Tag::genreNumber() const
void ID3v1::Tag::setGenreNumber(unsigned int i)
{
d->genre = i < 256 ? i : 255;
d->genre = static_cast<unsigned char>(i < 256 ? i : 255);
}
void ID3v1::Tag::setStringHandler(const StringHandler *handler)

View File

@@ -315,7 +315,7 @@ PropertyMap TextIdentificationFrame::makeTIPLProperties() const
const StringList l = fieldList();
for(auto it = l.begin(); it != l.end(); ++it) {
auto found = std::find_if(involvedPeople.begin(), involvedPeople.end(),
[=](const auto &person) { return *it == person.first; });
[=](const auto &person) { return it->upper() == person.first; });
if(found != involvedPeople.end()) {
map.insert(found->second, (++it)->split(","));
}

View File

@@ -357,6 +357,49 @@ void FrameFactory::rebuildAggregateFrames(ID3v2::Tag *tag) const
}
}
}
if(tag->header()->majorVersion() < 4 &&
tag->frameList("TIPL").size() == 1 &&
tag->frameList("TMCL").size() == 0)
{
// FrameFactory::updateFrame() has mapped IPLS (ID3v2.3)/ IPL (ID3v2.2)
// to TIPL (ID3v2.4). However, the musicians should be rather in TMCL.
// Move all involvement/involvee pairs which are not supported by the
// TIPL property map interface to a TMCL frame.
if(auto tipl =
dynamic_cast<TextIdentificationFrame *>(tag->frameList("TIPL").front())) {
if(StringList tiplValues = tipl->toStringList(); tiplValues.size() % 2 == 0) {
static StringList tiplKeys;
if(tiplKeys.isEmpty()) {
for(const auto &kv : TextIdentificationFrame::involvedPeopleMap()) {
tiplKeys.append(kv.second);
}
}
StringList tmclValues;
for(auto it = tiplValues.begin(); it != tiplValues.end();) {
const String involvement = *it;
if(!tiplKeys.contains(involvement.upper())) {
tmclValues.append(involvement);
it = tiplValues.erase(it);
tmclValues.append(*it);
it = tiplValues.erase(it);
} else {
++it;
++it;
}
}
if(!tmclValues.isEmpty()) {
auto tmcl = new TextIdentificationFrame("TMCL");
tmcl->setText(tmclValues);
tag->addFrame(tmcl);
if(!tiplValues.isEmpty()) {
tipl->setText(tiplValues);
} else {
tag->removeFrame(tipl);
}
}
}
}
}
}
String::Type FrameFactory::defaultTextEncoding() const

View File

@@ -56,6 +56,28 @@ namespace
constexpr long MinPaddingSize = 1024;
constexpr long MaxPaddingSize = 1024 * 1024;
/*!
* Downgrade ID3v2.4 text \a encoding to value supported by ID3v2.3.
*/
String::Type downgradeTextEncoding(String::Type encoding)
{
return encoding == String::Latin1 ? String::Latin1 : String::UTF16;
}
/*!
* Downgrade ID3v2.4 text encoding to value supported by ID3v2.3.
* \param frame1 first contributing ID3v2.4 frame, can be null
* \param frame2 second contributing ID3v2.4 frame, can be null
* \return ID3v2.3 encoding suitable for both contributing source frames.
*/
String::Type downgradeTextEncoding(ID3v2::TextIdentificationFrame *frame1,
ID3v2::TextIdentificationFrame *frame2)
{
return (!frame1 || frame1->textEncoding() == String::Latin1) &&
(!frame2 || frame2->textEncoding() == String::Latin1)
? String::Latin1 : String::UTF16;
}
} // namespace
class ID3v2::Tag::TagPrivate
@@ -578,7 +600,8 @@ void ID3v2::Tag::downgradeFrames(FrameList *frames, FrameList *newFrames) const
String content = frameTDOR->toString();
if(content.size() >= 4) {
auto frameTORY = new ID3v2::TextIdentificationFrame("TORY", String::Latin1);
auto frameTORY = new ID3v2::TextIdentificationFrame(
"TORY", downgradeTextEncoding(frameTDOR->textEncoding()));
frameTORY->setText(content.substr(0, 4));
frames->append(frameTORY);
newFrames->append(frameTORY);
@@ -587,17 +610,20 @@ void ID3v2::Tag::downgradeFrames(FrameList *frames, FrameList *newFrames) const
if(frameTDRC) {
if(String content = frameTDRC->toString(); content.size() >= 4) {
auto frameTYER = new ID3v2::TextIdentificationFrame("TYER", String::Latin1);
auto frameTYER = new ID3v2::TextIdentificationFrame(
"TYER", downgradeTextEncoding(frameTDRC->textEncoding()));
frameTYER->setText(content.substr(0, 4));
frames->append(frameTYER);
newFrames->append(frameTYER);
if(content.size() >= 10 && content[4] == '-' && content[7] == '-') {
auto frameTDAT = new ID3v2::TextIdentificationFrame("TDAT", String::Latin1);
auto frameTDAT = new ID3v2::TextIdentificationFrame(
"TDAT", downgradeTextEncoding(frameTDRC->textEncoding()));
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] == ':') {
auto frameTIME = new ID3v2::TextIdentificationFrame("TIME", String::Latin1);
auto frameTIME = new ID3v2::TextIdentificationFrame(
"TIME", downgradeTextEncoding(frameTDRC->textEncoding()));
frameTIME->setText(content.substr(11, 2) + content.substr(14, 2));
frames->append(frameTIME);
newFrames->append(frameTIME);
@@ -607,7 +633,8 @@ void ID3v2::Tag::downgradeFrames(FrameList *frames, FrameList *newFrames) const
}
if(frameTIPL || frameTMCL) {
auto frameIPLS = new ID3v2::TextIdentificationFrame("IPLS", String::Latin1);
auto frameIPLS = new ID3v2::TextIdentificationFrame(
"IPLS", downgradeTextEncoding(frameTIPL, frameTMCL));
StringList people;
@@ -653,7 +680,8 @@ void ID3v2::Tag::downgradeFrames(FrameList *frames, FrameList *newFrames) const
if(!genreText.isEmpty())
combined += genreText;
frameTCON = new ID3v2::TextIdentificationFrame("TCON", String::Latin1);
frameTCON = new ID3v2::TextIdentificationFrame(
"TCON", downgradeTextEncoding(frameTCON->textEncoding()));
frameTCON->setText(combined);
frames->append(frameTCON);
newFrames->append(frameTCON);
@@ -843,8 +871,10 @@ void ID3v2::Tag::parse(const ByteVector &origData)
break;
}
Frame *frame = d->factory->createFrame(data.mid(frameDataPosition),
&d->header);
const ByteVector origData = data.mid(frameDataPosition);
const Header *tagHeader = &d->header;
unsigned int headerVersion = tagHeader->majorVersion();
Frame *frame = d->factory->createFrame(origData, tagHeader);
if(!frame)
return;
@@ -856,7 +886,15 @@ void ID3v2::Tag::parse(const ByteVector &origData)
return;
}
frameDataPosition += frame->size() + frame->headerSize();
if(frame->header()->version() == headerVersion) {
frameDataPosition += frame->size() + frame->headerSize();
} else {
// The frame was converted to another version, e.g. from 2.2 to 2.4.
// We must advance the frame data position according to the original
// frame, not the converted frame because its header size might differ.
Frame::Header origHeader(origData, headerVersion);
frameDataPosition += origHeader.frameSize() + origHeader.size();
}
addFrame(frame);
}

View File

@@ -25,11 +25,14 @@
#include "mpegfile.h"
#include "taglib_config.h"
#include "id3v2framefactory.h"
#include "tdebug.h"
#include "tpropertymap.h"
#ifdef TAGLIB_WITH_APE
#include "apefooter.h"
#include "apetag.h"
#endif
#include "id3v1tag.h"
#include "id3v2tag.h"
#include "tagunion.h"
@@ -277,6 +280,7 @@ bool MPEG::File::save(int tags, StripTags strip, ID3v2::Version version, Duplica
}
}
#ifdef TAGLIB_WITH_APE
if(APE & tags) {
if(APETag() && !APETag()->isEmpty()) {
@@ -305,6 +309,7 @@ bool MPEG::File::save(int tags, StripTags strip, ID3v2::Version version, Duplica
File::strip(APE, false);
}
}
#endif
return true;
}
@@ -321,7 +326,11 @@ ID3v1::Tag *MPEG::File::ID3v1Tag(bool create)
APE::Tag *MPEG::File::APETag(bool create)
{
#ifdef TAGLIB_WITH_APE
return d->tag.access<APE::Tag>(APEIndex, create);
#else
return nullptr;
#endif
}
bool MPEG::File::strip(int tags, bool freeMemory)
@@ -480,6 +489,7 @@ void MPEG::File::read(bool readProperties, Properties::ReadStyle readStyle)
if(d->ID3v1Location >= 0)
d->tag.set(ID3v1Index, new ID3v1::Tag(this, d->ID3v1Location));
#ifdef TAGLIB_WITH_APE
// Look for an APE tag
d->APELocation = Utils::findAPE(this, d->ID3v1Location);
@@ -489,6 +499,7 @@ void MPEG::File::read(bool readProperties, Properties::ReadStyle readStyle)
d->APEOriginalSize = APETag()->footer()->completeTagSize();
d->APELocation = d->APELocation + APE::Footer::size() - d->APEOriginalSize;
}
#endif
if(readProperties)
d->properties = std::make_unique<Properties>(this, readStyle);

View File

@@ -25,10 +25,13 @@
#include "mpegproperties.h"
#include "taglib_config.h"
#include "tdebug.h"
#include "mpegfile.h"
#include "xingheader.h"
#ifdef TAGLIB_WITH_APE
#include "apetag.h"
#endif
using namespace TagLib;
@@ -237,7 +240,7 @@ void MPEG::Properties::read(File *file, ReadStyle readStyle)
const Header lastHeader(file, lastFrameOffset, false);
if(const offset_t streamLength = lastFrameOffset - firstFrameOffset + lastHeader.frameLength();
streamLength > 0)
d->length = static_cast<int>(streamLength * 8.0 / d->bitrate + 0.5);
d->length = static_cast<int>(static_cast<double>(streamLength) * 8.0 / d->bitrate + 0.5);
}
}
}

View File

@@ -113,6 +113,17 @@ bool Ogg::FLAC::File::save()
// Put the size in the first 32 bit (I assume no more than 24 bit are used)
ByteVector v = ByteVector::fromUInt(d->xiphCommentData.size());
if(v[0] != 0) {
// Block size uses more than 24 bits, try again with pictures removed.
d->comment->removeAllPictures();
d->xiphCommentData = d->comment->render(false);
v = ByteVector::fromUInt(d->xiphCommentData.size());
if(v[0] != 0) {
debug("Ogg::FLAC::File::save() -- Invalid, metadata block is too large.");
return false;
}
debug("Ogg::FLAC::File::save() -- Metadata block is too large, pictures removed.");
}
// Set the type of the metadata-block to be a Xiph / Vorbis comment

View File

@@ -147,7 +147,7 @@ void Opus::Properties::read(File *file)
fileLengthWithoutOverhead -= file->packet(i).size();
}
d->length = static_cast<int>(length + 0.5);
d->bitrate = static_cast<int>(fileLengthWithoutOverhead * 8.0 / length + 0.5);
d->bitrate = static_cast<int>(static_cast<double>(fileLengthWithoutOverhead) * 8.0 / length + 0.5);
}
}
else {

View File

@@ -163,7 +163,7 @@ void Speex::Properties::read(File *file)
fileLengthWithoutOverhead -= file->packet(i).size();
}
d->length = static_cast<int>(length + 0.5);
d->bitrate = static_cast<int>(fileLengthWithoutOverhead * 8.0 / length + 0.5);
d->bitrate = static_cast<int>(static_cast<double>(fileLengthWithoutOverhead) * 8.0 / length + 0.5);
}
}
else {

View File

@@ -166,7 +166,7 @@ void Vorbis::Properties::read(File *file)
fileLengthWithoutOverhead -= file->packet(i).size();
}
d->length = static_cast<int>(length + 0.5);
d->bitrate = static_cast<int>(fileLengthWithoutOverhead * 8.0 / length + 0.5);
d->bitrate = static_cast<int>(static_cast<double>(fileLengthWithoutOverhead) * 8.0 / length + 0.5);
}
}
else {

View File

@@ -0,0 +1,542 @@
/***************************************************************************
copyright : (C) 2020-2024 Stephen F. Booth
email : me@sbooth.org
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include "shortenfile.h"
#include <cmath>
#include "shortenutils.h"
#include "tdebug.h"
#include "tutils.h"
#include "tagutils.h"
#include "tpropertymap.h"
using namespace TagLib;
namespace {
// MARK: Constants
constexpr int minSupportedVersion = 1;
constexpr int maxSupportedVersion = 3;
// Possible values of k
constexpr int32_t channelCountCodeSize = 0;
constexpr int32_t functionCodeSize = 2;
constexpr int32_t verbatimChunkSizeCodeSize = 5;
constexpr int32_t verbatimByteCodeSize = 8;
constexpr int32_t uInt32CodeSize = 2;
constexpr int32_t skipBytesCodeSize = 1;
constexpr int32_t lpcqCodeSize = 2;
constexpr int32_t extraByteCodeSize = 7;
constexpr int32_t fileTypeCodeSize = 4;
constexpr int32_t functionVerbatim = 9;
constexpr int32_t canonicalHeaderSize = 44;
constexpr int32_t verbatimChunkMaxSize = 256;
constexpr uint32_t maxChannelCount = 8;
constexpr uint32_t defaultBlockSize = 256;
constexpr uint32_t maxBlockSize = 65535;
constexpr int waveFormatPCMTag = 0x0001;
// MARK: Variable-Length Input
//! Variable-length input using Golomb-Rice coding.
class VariableLengthInput {
public:
//! Creates a new \c VariableLengthInput object.
VariableLengthInput(File *file) : file(file) {}
~VariableLengthInput() = default;
VariableLengthInput() = delete;
VariableLengthInput(const VariableLengthInput &) = delete;
VariableLengthInput(VariableLengthInput &&) = delete;
VariableLengthInput &operator=(const VariableLengthInput &) = delete;
VariableLengthInput &operator=(VariableLengthInput &&) = delete;
bool getRiceGolombCode(int32_t &i32, int k);
bool getUInt(uint32_t &ui32, int version, int32_t k);
private:
//! Refills \c bitBuffer with a single \c uint32_t from \c buffer,
//! refilling \c buffer if necessary.
bool refillBitBuffer();
//! Input stream
File *file { nullptr };
//! Byte buffer
ByteVector buffer;
//! Current position in buffer
unsigned int bufferPosition { 0 };
//! Bit buffer
uint32_t bitBuffer { 0 };
//! Bits available in \c bitBuffer, 0..32
int bitsAvailable { 0 };
};
bool VariableLengthInput::getRiceGolombCode(int32_t &i32, int32_t k)
{
static constexpr uint32_t sMaskTable[] = {
0x0,
0x1, 0x3, 0x7, 0xf,
0x1f, 0x3f, 0x7f, 0xff,
0x1ff, 0x3ff, 0x7ff, 0xfff,
0x1fff, 0x3fff, 0x7fff, 0xffff,
0x1ffff, 0x3ffff, 0x7ffff, 0xfffff,
0x1fffff, 0x3fffff, 0x7fffff, 0xffffff,
0x1ffffff, 0x3ffffff, 0x7ffffff, 0xfffffff,
0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff
};
if(bitsAvailable == 0 && !refillBitBuffer())
return false;
int32_t result;
for(result = 0; !(bitBuffer & (1L << --bitsAvailable)); ++result) {
if(bitsAvailable == 0 && !refillBitBuffer())
return false;
}
while(k != 0) {
if(bitsAvailable >= k) {
result = (result << k) | static_cast<int32_t>(
(bitBuffer >> (bitsAvailable - k)) & sMaskTable[k]);
bitsAvailable -= k;
k = 0;
}
else {
result = (result << bitsAvailable) | static_cast<int32_t>(
bitBuffer & sMaskTable[bitsAvailable]);
k -= bitsAvailable;
if(!refillBitBuffer())
return false;
}
}
i32 = result;
return true;
}
bool VariableLengthInput::getUInt(uint32_t &ui32, int version, int32_t k)
{
if(version > 0 && !getRiceGolombCode(k, uInt32CodeSize))
return false;
int32_t i32;
if(!getRiceGolombCode(i32, k))
return false;
ui32 = static_cast<uint32_t>(i32);
return true;
}
bool VariableLengthInput::refillBitBuffer()
{
if(buffer.size() - bufferPosition < 4) {
static constexpr size_t bufferSize = 512;
auto block = file->readBlock(bufferSize);
if(block.size() < 4)
return false;
buffer = block;
bufferPosition = 0;
}
bitBuffer = buffer.toUInt(bufferPosition, true);
bufferPosition += 4;
bitsAvailable = 32;
return true;
}
} // namespace
class Shorten::File::FilePrivate
{
public:
FilePrivate() = default;
~FilePrivate() = default;
FilePrivate(const FilePrivate &) = delete;
FilePrivate &operator=(const FilePrivate &) = delete;
std::unique_ptr<Properties> properties;
std::unique_ptr<Tag> tag;
};
bool Shorten::File::isSupported(IOStream *stream)
{
// A Shorten file has to start with "ajkg"
const ByteVector id = Utils::readHeader(stream, 4, false);
return id.startsWith("ajkg");
}
Shorten::File::File(FileName file, bool,
AudioProperties::ReadStyle propertiesStyle) :
TagLib::File(file),
d(std::make_unique<FilePrivate>())
{
if(isOpen())
read(propertiesStyle);
}
Shorten::File::File(IOStream *stream, bool,
AudioProperties::ReadStyle propertiesStyle) :
TagLib::File(stream),
d(std::make_unique<FilePrivate>())
{
if(isOpen())
read(propertiesStyle);
}
Shorten::File::~File() = default;
Shorten::Tag *Shorten::File::tag() const
{
return d->tag.get();
}
PropertyMap Shorten::File::properties() const
{
return d->tag->properties();
}
PropertyMap Shorten::File::setProperties(const PropertyMap &properties)
{
return d->tag->setProperties(properties);
}
Shorten::Properties *Shorten::File::audioProperties() const
{
return d->properties.get();
}
bool Shorten::File::save()
{
if(readOnly()) {
debug("Shorten::File::save() - Cannot save to a read only file.");
return false;
}
debug("Shorten::File::save() - Saving not supported.");
return false;
}
void Shorten::File::read(AudioProperties::ReadStyle propertiesStyle)
{
if(!isOpen())
return;
// Read magic number
auto magic = readBlock(4);
if(magic != "ajkg") {
debug("Shorten::File::read() -- Not a Shorten file.");
setValid(false);
return;
}
PropertyValues props{};
// Read file version
int version = readBlock(1).toUInt();
if(version < minSupportedVersion || version > maxSupportedVersion) {
debug("Shorten::File::read() -- Unsupported version.");
setValid(false);
return;
}
props.version = version;
// Set up variable length input
VariableLengthInput input(this);
// Read file type
uint32_t fileType;
if(!input.getUInt(fileType, version, fileTypeCodeSize)) {
debug("Shorten::File::read() -- Unable to read file type.");
setValid(false);
return;
}
props.fileType = static_cast<int>(fileType);
// Read number of channels
uint32_t channelCount = 0;
if(!input.getUInt(channelCount, version, channelCountCodeSize) ||
channelCount == 0 || channelCount > maxChannelCount) {
debug("Shorten::File::read() -- Invalid or unsupported channel count.");
setValid(false);
return;
}
props.channelCount = static_cast<int>(channelCount);
// Read block size if version > 0
if(version > 0) {
uint32_t blockSize = 0;
if(!input.getUInt(blockSize, version,
static_cast<int32_t>(std::log2(defaultBlockSize))) ||
blockSize == 0 || blockSize > maxBlockSize) {
debug("Shorten::File::read() -- Invalid or unsupported block size.");
setValid(false);
return;
}
uint32_t maxnlpc = 0;
if(!input.getUInt(maxnlpc, version, lpcqCodeSize) /*|| maxnlpc > 1024*/) {
debug("Shorten::File::read() -- Invalid maximum nlpc.");
setValid(false);
return;
}
uint32_t nmean = 0;
if(!input.getUInt(nmean, version, 0) /*|| nmean > 32768*/) {
debug("Shorten::File::read() -- Invalid nmean.");
setValid(false);
return;
}
uint32_t skipCount;
if(!input.getUInt(skipCount, version, skipBytesCodeSize)) {
setValid(false);
return;
}
for(uint32_t i = 0; i < skipCount; ++i) {
uint32_t dummy;
if(!input.getUInt(dummy, version, extraByteCodeSize)) {
setValid(false);
return;
}
}
}
// Parse the WAVE or AIFF header in the verbatim section
int32_t function;
if(!input.getRiceGolombCode(function, functionCodeSize) ||
function != functionVerbatim) {
debug("Shorten::File::read() -- Missing initial verbatim section.");
setValid(false);
return;
}
int32_t header_size;
if(!input.getRiceGolombCode(header_size, verbatimChunkSizeCodeSize) ||
header_size < canonicalHeaderSize || header_size > verbatimChunkMaxSize) {
debug("Shorten::File::read() -- Incorrect header size.");
setValid(false);
return;
}
ByteVector header(header_size, 0);
auto it = header.begin();
for(int32_t i = 0; i < header_size; ++i) {
int32_t byte;
if(!input.getRiceGolombCode(byte, verbatimByteCodeSize)) {
debug("Shorten::File::read() -- Unable to read header.");
setValid(false);
return;
}
*it++ = static_cast<uint8_t>(byte);
}
// header is at least canonicalHeaderSize (44) bytes in size
auto chunkID = header.toUInt(0, true);
// auto chunkSize = header.toUInt(4, true);
const auto chunkData = ByteVector(header, 8, header.size() - 8);
// WAVE
if(chunkID == 0x52494646 /*'RIFF'*/) {
unsigned int offset = 0;
chunkID = chunkData.toUInt(offset, true);
offset += 4;
if(chunkID != 0x57415645 /*'WAVE'*/) {
debug("Shorten::File::read() -- Missing 'WAVE' in 'RIFF' chunk.");
setValid(false);
return;
}
auto sawFormatChunk = false;
uint32_t dataChunkSize = 0;
uint16_t blockAlign = 0;
while(offset < chunkData.size()) {
chunkID = chunkData.toUInt(offset, true);
offset += 4;
auto chunkSize = chunkData.toUInt(offset, false);
offset += 4;
switch(chunkID) {
case 0x666d7420 /*'fmt '*/:
{
if(chunkSize < 16) {
debug("Shorten::File::read() -- 'fmt ' chunk is too small.");
setValid(false);
return;
}
int formatTag = chunkData.toUShort(offset, false);
offset += 2;
if(formatTag != waveFormatPCMTag) {
debug("Shorten::File::read() -- Unsupported WAVE format tag.");
setValid(false);
return;
}
int fmtChannelCount = chunkData.toUShort(offset, false);
offset += 2;
if(props.channelCount != fmtChannelCount)
debug("Shorten::File::read() -- Channel count mismatch between Shorten and 'fmt ' chunk.");
props.sampleRate = static_cast<int>(chunkData.toUInt(offset, false));
offset += 4;
// Skip average bytes per second
offset += 4;
blockAlign = chunkData.toUShort(offset, false);
offset += 2;
props.bitsPerSample = static_cast<int>(chunkData.toUShort(offset, false));
offset += 2;
sawFormatChunk = true;
break;
}
case 0x64617461 /*'data'*/:
dataChunkSize = chunkSize;
break;
}
}
if(!sawFormatChunk) {
debug("Shorten::File::read() -- Missing 'fmt ' chunk.");
setValid(false);
return;
}
if(dataChunkSize && blockAlign)
props.sampleFrames = static_cast<unsigned long>(dataChunkSize / blockAlign);
}
// AIFF
else if(chunkID == 0x464f524d /*'FORM'*/) {
unsigned int offset = 0;
chunkID = chunkData.toUInt(offset, true);
offset += 4;
if(chunkID != 0x41494646 /*'AIFF'*/ && chunkID != 0x41494643 /*'AIFC'*/) {
debug("Shorten::File::read() -- Missing 'AIFF' or 'AIFC' in 'FORM' chunk.");
setValid(false);
return;
}
// if(chunkID == 0x41494643 /*'AIFC'*/)
// props.big_endian = true;
auto sawCommonChunk = false;
while(offset < chunkData.size()) {
chunkID = chunkData.toUInt(offset, true);
offset += 4;
auto chunkSize = chunkData.toUInt(offset, true);
offset += 4;
// All chunks must have an even length but the pad byte is not included in chunkSize
chunkSize += (chunkSize & 1);
switch(chunkID) {
case 0x434f4d4d /*'COMM'*/:
{
if(chunkSize < 18) {
debug("Shorten::File::read() -- 'COMM' chunk is too small.");
setValid(false);
return;
}
int commChannelCount = chunkData.toUShort(offset, true);
offset += 2;
if(props.channelCount != commChannelCount)
debug("Shorten::File::read() -- Channel count mismatch between Shorten and 'COMM' chunk.");
props.sampleFrames = static_cast<unsigned long>(chunkData.toUInt(offset, true));
offset += 4;
props.bitsPerSample = static_cast<int>(chunkData.toUShort(offset, true));
offset += 2;
// sample rate is IEEE 754 80-bit extended float
// (16-bit exponent, 1-bit integer part, 63-bit fraction)
auto exp = static_cast<int16_t>(chunkData.toUShort(offset, true)) - 16383 - 63;
offset += 2;
if(exp < -63 || exp > 63) {
debug("Shorten::File::read() -- exp out of range.");
setValid(false);
return;
}
auto frac = chunkData.toULongLong(offset, true);
offset += 8;
if(exp >= 0)
props.sampleRate = static_cast<int>(frac << exp);
else
props.sampleRate = static_cast<int>(
(frac + (static_cast<uint64_t>(1) << (-exp - 1))) >> -exp);
sawCommonChunk = true;
break;
}
// Skip all other chunks
default:
offset += chunkSize;
break;
}
}
if(!sawCommonChunk) {
debug("Shorten::File::read() -- Missing 'COMM' chunk");
setValid(false);
return;
}
}
else {
debug("Shorten::File::read() -- Unsupported data format.");
setValid(false);
return;
}
d->tag = std::make_unique<Tag>();
d->properties = std::make_unique<Properties>(&props, propertiesStyle);
}

View File

@@ -0,0 +1,140 @@
/***************************************************************************
copyright : (C) 2020-2024 Stephen F. Booth
email : me@sbooth.org
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifndef TAGLIB_SHORTENFILE_H
#define TAGLIB_SHORTENFILE_H
#include <memory>
#include "taglib_export.h"
#include "tfile.h"
#include "shortenproperties.h"
#include "shortentag.h"
namespace TagLib {
//! An implementation of Shorten metadata
/*!
* This is an implementation of Shorten metadata.
*/
namespace Shorten {
//! An implementation of \c TagLib::File with Shorten specific methods
/*!
* This implements and provides an interface for Shorten files to the
* \c TagLib::Tag and \c TagLib::AudioProperties interfaces by way of implementing
* the abstract \c TagLib::File API as well as providing some additional
* information specific to Shorten files.
*/
class TAGLIB_EXPORT File : public TagLib::File {
public:
/*!
* Constructs a Shorten 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 Shorten 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.
*/
~File() override;
File(const File &) = delete;
File &operator=(const File &) = delete;
/*!
* Returns the \c Shorten::Tag for this file.
*
* \note While the returned \c Tag instance is non-null Shorten tags are not supported.
*/
Tag *tag() const override;
/*!
* Implements the unified property interface -- export function.
*/
PropertyMap properties() const override;
/*!
* Implements the unified property interface -- import function.
*/
PropertyMap setProperties(const PropertyMap &) override;
/*!
* Returns the \c Shorten::Properties for this file. If no audio properties
* were read then this will return a null pointer.
*/
Properties *audioProperties() const override;
/*!
* Save the file.
*
* \note Saving Shorten tags is not supported.
*/
bool save() override;
/*!
* Returns whether or not the given \a stream can be opened as a Shorten
* file.
*
* \note This method is designed to do a quick check. The result may
* not necessarily be correct.
*/
static bool isSupported(IOStream *stream);
private:
void read(AudioProperties::ReadStyle propertiesStyle);
class FilePrivate;
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
std::unique_ptr<FilePrivate> d;
};
} // namespace Shorten
} // namespace TagLib
#endif

View File

@@ -0,0 +1,112 @@
/***************************************************************************
copyright : (C) 2020-2024 Stephen F. Booth
email : me@sbooth.org
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include "shortenproperties.h"
#include "shortenutils.h"
using namespace TagLib;
class Shorten::Properties::PropertiesPrivate
{
public:
PropertiesPrivate() = default;
~PropertiesPrivate() = default;
PropertiesPrivate(const PropertiesPrivate &) = delete;
PropertiesPrivate &operator=(const PropertiesPrivate &) = delete;
int version { 0 };
int fileType { 0 };
int channelCount { 0 };
int sampleRate { 0 };
int bitsPerSample { 0 };
unsigned long sampleFrames { 0 };
// Computed
int bitrate { 0 };
int length { 0 };
};
Shorten::Properties::Properties(const PropertyValues *values, ReadStyle style) :
AudioProperties(style),
d(std::make_unique<PropertiesPrivate>())
{
if(values) {
d->version = values->version;
d->fileType = values->fileType;
d->channelCount = values->channelCount;
d->sampleRate = values->sampleRate;
d->bitsPerSample = values->bitsPerSample;
d->sampleFrames = values->sampleFrames;
d->bitrate = static_cast<int>(d->sampleRate * d->bitsPerSample * d->channelCount / 1000.0 + 0.5);
if(d->sampleRate > 0)
d->length = static_cast<int>(static_cast<double>(d->sampleFrames) * 1000.0 / d->sampleRate + 0.5);
}
}
Shorten::Properties::~Properties() = default;
int Shorten::Properties::lengthInMilliseconds() const
{
return d->length;
}
int Shorten::Properties::bitrate() const
{
return d->bitrate;
}
int Shorten::Properties::sampleRate() const
{
return d->sampleRate;
}
int Shorten::Properties::channels() const
{
return d->channelCount;
}
int Shorten::Properties::shortenVersion() const
{
return d->version;
}
int Shorten::Properties::fileType() const
{
return d->fileType;
}
int Shorten::Properties::bitsPerSample() const
{
return d->bitsPerSample;
}
unsigned long Shorten::Properties::sampleFrames() const
{
return d->sampleFrames;
}

View File

@@ -0,0 +1,74 @@
/***************************************************************************
copyright : (C) 2020-2024 Stephen F. Booth
email : me@sbooth.org
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifndef TAGLIB_SHORTENPROPERTIES_H
#define TAGLIB_SHORTENPROPERTIES_H
#include <memory>
#include "taglib_export.h"
#include "audioproperties.h"
namespace TagLib {
namespace Shorten {
struct PropertyValues;
//! An implementation of audio properties for Shorten
class TAGLIB_EXPORT Properties : public AudioProperties {
public:
Properties(const PropertyValues *values, ReadStyle style = Average);
~Properties() override;
Properties(const Properties &) = delete;
Properties &operator=(const Properties &) = delete;
int lengthInMilliseconds() const override;
int bitrate() const override;
int sampleRate() const override;
int channels() const override;
//! Returns the Shorten file version (1-3).
int shortenVersion() const;
//! Returns the file type (0-9).
//! 0 = 8-bit µ-law,
//! 1 = signed 8-bit PCM, 2 = unsigned 8-bit PCM,
//! 3 = signed big-endian 16-bit PCM, 4 = unsigned big-endian 16-bit PCM,
//! 5 = signed little-endian 16-bit PCM, 6 = unsigned little-endian 16-bit PCM,
//! 7 = 8-bit ITU-T G.711 µ-law, 8 = 8-bit µ-law,
//! 9 = 8-bit A-law, 10 = 8-bit ITU-T G.711 A-law
int fileType() const;
int bitsPerSample() const;
unsigned long sampleFrames() const;
private:
class PropertiesPrivate;
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
std::unique_ptr<PropertiesPrivate> d;
};
} // namespace Shorten
} // namespace TagLib
#endif

View File

@@ -0,0 +1,114 @@
/***************************************************************************
copyright : (C) 2020-2024 Stephen F. Booth
email : me@sbooth.org
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include "shortentag.h"
#include "tpropertymap.h"
using namespace TagLib;
class Shorten::Tag::TagPrivate
{
};
Shorten::Tag::Tag() :
d(std::make_unique<TagPrivate>())
{
}
Shorten::Tag::~Tag() = default;
String Shorten::Tag::title() const
{
return String();
}
String Shorten::Tag::artist() const
{
return String();
}
String Shorten::Tag::album() const
{
return String();
}
String Shorten::Tag::comment() const
{
return String();
}
String Shorten::Tag::genre() const
{
return String();
}
unsigned int Shorten::Tag::year() const
{
return 0;
}
unsigned int Shorten::Tag::track() const
{
return 0;
}
void Shorten::Tag::setTitle(const String &)
{
}
void Shorten::Tag::setArtist(const String &)
{
}
void Shorten::Tag::setAlbum(const String &)
{
}
void Shorten::Tag::setComment(const String &)
{
}
void Shorten::Tag::setGenre(const String &)
{
}
void Shorten::Tag::setYear(unsigned int)
{
}
void Shorten::Tag::setTrack(unsigned int)
{
}
PropertyMap Shorten::Tag::properties() const
{
return PropertyMap{};
}
PropertyMap Shorten::Tag::setProperties(const PropertyMap &origProps)
{
return PropertyMap{origProps};
}

139
taglib/shorten/shortentag.h Normal file
View File

@@ -0,0 +1,139 @@
/***************************************************************************
copyright : (C) 2020-2024 Stephen F. Booth
email : me@sbooth.org
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifndef TAGLIB_SHORTENTAG_H
#define TAGLIB_SHORTENTAG_H
#include "tag.h"
namespace TagLib {
namespace Shorten {
//! A Shorten file tag implementation
/*!
* Tags for Shorten files.
*
* This is a stub class; Shorten files do not support tags.
*/
class TAGLIB_EXPORT Tag : public TagLib::Tag
{
public:
Tag();
~Tag() override;
Tag(const Tag &) = delete;
Tag &operator=(const Tag &) = delete;
/*!
* Not supported by Shorten files. Therefore always returns an empty string.
*/
String title() const override;
/*!
* Not supported by Shorten files. Therefore always returns an empty string.
*/
String artist() const override;
/*!
* Not supported by Shorten files. Therefore always returns an empty string.
*/
String album() const override;
/*!
* Not supported by Shorten files. Therefore always returns an empty string.
*/
String comment() const override;
/*!
* Not supported by Shorten files. Therefore always returns an empty string.
*/
String genre() const override;
/*!
* Not supported by Shorten files. Therefore always returns 0.
*/
unsigned int year() const override;
/*!
* Not supported by Shorten files. Therefore always returns 0.
*/
unsigned int track() const override;
/*!
* Not supported by Shorten files and therefore ignored.
*/
void setTitle(const String &title) override;
/*!
* Not supported by Shorten files and therefore ignored.
*/
void setArtist(const String &artist) override;
/*!
* Not supported by Shorten files and therefore ignored.
*/
void setAlbum(const String &album) override;
/*!
* Not supported by Shorten files and therefore ignored.
*/
void setComment(const String &comment) override;
/*!
* Not supported by Shorten files and therefore ignored.
*/
void setGenre(const String &genre) override;
/*!
* Not supported by Shorten files and therefore ignored.
*/
void setYear(unsigned int year) override;
/*!
* Not supported by Shorten files and therefore ignored.
*/
void setTrack(unsigned int track) override;
/*!
* Implements the unified property interface -- export function.
*/
PropertyMap properties() const override;
/*!
* Implements the unified property interface -- import function.
*/
PropertyMap setProperties(const PropertyMap &) override;
private:
class TagPrivate;
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
std::unique_ptr<TagPrivate> d;
};
} // namespace Shorten
} // namespace TagLib
#endif

View File

@@ -0,0 +1,51 @@
/***************************************************************************
copyright : (C) 2020-2024 Stephen F. Booth
email : me@sbooth.org
***************************************************************************/
/***************************************************************************
* This library is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License version *
* 2.1 as published by the Free Software Foundation. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
* 02110-1301 USA *
* *
* Alternatively, this file is available under the Mozilla Public *
* License Version 1.1. You may obtain a copy of the License at *
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#ifndef TAGLIB_SHORTENUTILS_H
#define TAGLIB_SHORTENUTILS_H
// THIS FILE IS NOT A PART OF THE TAGLIB API
#ifndef DO_NOT_DOCUMENT // tell Doxygen not to document this header
namespace TagLib {
namespace Shorten {
/// Values shared with \c Shorten::Properties by \c Shorten::File
struct PropertyValues
{
int version { 0 };
int fileType { 0 };
int channelCount { 0 };
int sampleRate { 0 };
int bitsPerSample { 0 };
unsigned long sampleFrames { 0 };
};
} // namespace Shorten
} // namespace TagLib
#endif
#endif

View File

@@ -0,0 +1,16 @@
/* taglib_config.h. Generated by cmake from taglib_config.h.cmake */
#ifndef TAGLIB_TAGLIB_CONFIG_H
#define TAGLIB_TAGLIB_CONFIG_H
#cmakedefine TAGLIB_WITH_APE 1
#cmakedefine TAGLIB_WITH_ASF 1
#cmakedefine TAGLIB_WITH_DSF 1
#cmakedefine TAGLIB_WITH_MOD 1
#cmakedefine TAGLIB_WITH_MP4 1
#cmakedefine TAGLIB_WITH_RIFF 1
#cmakedefine TAGLIB_WITH_SHORTEN 1
#cmakedefine TAGLIB_WITH_TRUEAUDIO 1
#cmakedefine TAGLIB_WITH_VORBIS 1
#endif

View File

@@ -25,11 +25,14 @@
#include "tagutils.h"
#include "taglib_config.h"
#include "tfile.h"
#include "id3v1tag.h"
#include "id3v2header.h"
#ifdef TAGLIB_WITH_APE
#include "apetag.h"
#endif
using namespace TagLib;
@@ -45,7 +48,13 @@ offset_t Utils::findID3v1(File *file)
const offset_t p = file->tell() + 3;
if(const TagLib::ByteVector data = file->readBlock(8);
data.containsAt(ID3v1::Tag::fileIdentifier(), 3) && data != APE::Tag::fileIdentifier())
data.containsAt(ID3v1::Tag::fileIdentifier(), 3) &&
#ifdef TAGLIB_WITH_APE
data != APE::Tag::fileIdentifier()
#else
data != ByteVector::fromCString("APETAGEX")
#endif
)
return p;
} else {
file->seek(-128, File::End);
@@ -83,7 +92,13 @@ offset_t Utils::findAPE(File *file, offset_t id3v1Location)
const offset_t p = file->tell();
if(file->readBlock(8) == APE::Tag::fileIdentifier())
if(file->readBlock(8) ==
#ifdef TAGLIB_WITH_APE
APE::Tag::fileIdentifier()
#else
ByteVector::fromCString("APETAGEX")
#endif
)
return p;
return -1;

View File

@@ -27,7 +27,7 @@
#define TAGLIB_H
#define TAGLIB_MAJOR_VERSION 2
#define TAGLIB_MINOR_VERSION 0
#define TAGLIB_MINOR_VERSION 1
#define TAGLIB_PATCH_VERSION 1
#if (defined(_MSC_VER) && _MSC_VER >= 1600)

View File

@@ -120,7 +120,8 @@ T toNumber(const ByteVector &v, size_t offset, size_t length, bool mostSignifica
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<unsigned char>(v[static_cast<int>(offset + i)])) << shift;
sum |= static_cast<T>(
static_cast<T>(static_cast<unsigned char>(v[static_cast<int>(offset + i)])) << shift);
}
return sum;
@@ -158,7 +159,7 @@ ByteVector fromNumber(T value, bool mostSignificantByteFirst)
template <typename TFloat, typename TInt, Utils::ByteOrder ENDIAN>
TFloat toFloat(const ByteVector &v, size_t offset)
{
if(offset > v.size() - sizeof(TInt)) {
if(offset + sizeof(TInt) > v.size()) {
debug("toFloat() - offset is out of range. Returning 0.");
return 0.0;
}
@@ -195,7 +196,7 @@ long double toFloat80(const ByteVector &v, size_t offset)
{
using std::swap;
if(offset > v.size() - 10) {
if(offset + 10 > v.size()) {
debug("toFloat80() - offset is out of range. Returning 0.");
return 0.0;
}
@@ -236,7 +237,7 @@ long double toFloat80(const ByteVector &v, size_t offset)
debug("toFloat80() - can't handle the infinity or NaN. Returning 0.");
return 0.0;
}
val = ::ldexp(static_cast<long double>(fraction), exponent - 16383 - 63);
val = ::ldexpl(static_cast<long double>(fraction), exponent - 16383 - 63);
}
if(negative)
@@ -282,47 +283,47 @@ ByteVector ByteVector::fromCString(const char *s, unsigned int length)
ByteVector ByteVector::fromUInt(unsigned int value, bool mostSignificantByteFirst)
{
return fromNumber<unsigned int>(value, mostSignificantByteFirst);
return fromNumber<uint32_t>(value, mostSignificantByteFirst);
}
ByteVector ByteVector::fromShort(short value, bool mostSignificantByteFirst)
{
return fromNumber<unsigned short>(value, mostSignificantByteFirst);
return fromNumber<uint16_t>(value, mostSignificantByteFirst);
}
ByteVector ByteVector::fromUShort(unsigned short value, bool mostSignificantByteFirst)
{
return fromNumber<unsigned short>(value, mostSignificantByteFirst);
return fromNumber<uint16_t>(value, mostSignificantByteFirst);
}
ByteVector ByteVector::fromLongLong(long long value, bool mostSignificantByteFirst)
{
return fromNumber<unsigned long long>(value, mostSignificantByteFirst);
return fromNumber<uint64_t>(value, mostSignificantByteFirst);
}
ByteVector ByteVector::fromULongLong(unsigned long long value, bool mostSignificantByteFirst)
{
return fromNumber<unsigned long long>(value, mostSignificantByteFirst);
return fromNumber<uint64_t>(value, mostSignificantByteFirst);
}
ByteVector ByteVector::fromFloat32LE(float value)
{
return fromFloat<float, unsigned int, Utils::LittleEndian>(value);
return fromFloat<float, uint32_t, Utils::LittleEndian>(value);
}
ByteVector ByteVector::fromFloat32BE(float value)
{
return fromFloat<float, unsigned int, Utils::BigEndian>(value);
return fromFloat<float, uint32_t, Utils::BigEndian>(value);
}
ByteVector ByteVector::fromFloat64LE(double value)
{
return fromFloat<double, unsigned long long, Utils::LittleEndian>(value);
return fromFloat<double, uint64_t, Utils::LittleEndian>(value);
}
ByteVector ByteVector::fromFloat64BE(double value)
{
return fromFloat<double, unsigned long long, Utils::BigEndian>(value);
return fromFloat<double, uint64_t, Utils::BigEndian>(value);
}
////////////////////////////////////////////////////////////////////////////////
@@ -360,7 +361,7 @@ ByteVector::ByteVector(const char *data, unsigned int length) :
}
ByteVector::ByteVector(const char *data) :
d(std::make_unique<ByteVectorPrivate>(data, static_cast<unsigned int>(::strlen(data))))
d(std::make_unique<ByteVectorPrivate>(data, data ? static_cast<unsigned int>(::strlen(data)) : 0))
{
}
@@ -656,79 +657,86 @@ bool ByteVector::isEmpty() const
return d->length == 0;
}
// Sanity checks
static_assert(sizeof(unsigned short) == sizeof(uint16_t), "unsigned short and uint16_t are different sizes");
static_assert(sizeof(unsigned int) == sizeof(uint32_t), "unsigned int and uint32_t are different sizes");
static_assert(sizeof(unsigned long long) == sizeof(uint64_t), "unsigned long long and uint64_t are different sizes");
static_assert(sizeof(float) == sizeof(uint32_t), "float and uint32_t are different sizes");
static_assert(sizeof(double) == sizeof(uint64_t), "double and uint64_t are different sizes");
unsigned int ByteVector::toUInt(bool mostSignificantByteFirst) const
{
return toNumber<unsigned int>(*this, 0, mostSignificantByteFirst);
return toNumber<uint32_t>(*this, 0, mostSignificantByteFirst);
}
unsigned int ByteVector::toUInt(unsigned int offset, bool mostSignificantByteFirst) const
{
return toNumber<unsigned int>(*this, offset, mostSignificantByteFirst);
return toNumber<uint32_t>(*this, offset, mostSignificantByteFirst);
}
unsigned int ByteVector::toUInt(unsigned int offset, unsigned int length, bool mostSignificantByteFirst) const
{
return toNumber<unsigned int>(*this, offset, length, mostSignificantByteFirst);
return toNumber<uint32_t>(*this, offset, length, mostSignificantByteFirst);
}
short ByteVector::toShort(bool mostSignificantByteFirst) const
{
return toNumber<unsigned short>(*this, 0, mostSignificantByteFirst);
return toNumber<uint16_t>(*this, 0, mostSignificantByteFirst);
}
short ByteVector::toShort(unsigned int offset, bool mostSignificantByteFirst) const
{
return toNumber<unsigned short>(*this, offset, mostSignificantByteFirst);
return toNumber<uint16_t>(*this, offset, mostSignificantByteFirst);
}
unsigned short ByteVector::toUShort(bool mostSignificantByteFirst) const
{
return toNumber<unsigned short>(*this, 0, mostSignificantByteFirst);
return toNumber<uint16_t>(*this, 0, mostSignificantByteFirst);
}
unsigned short ByteVector::toUShort(unsigned int offset, bool mostSignificantByteFirst) const
{
return toNumber<unsigned short>(*this, offset, mostSignificantByteFirst);
return toNumber<uint16_t>(*this, offset, mostSignificantByteFirst);
}
long long ByteVector::toLongLong(bool mostSignificantByteFirst) const
{
return toNumber<unsigned long long>(*this, 0, mostSignificantByteFirst);
return toNumber<uint64_t>(*this, 0, mostSignificantByteFirst);
}
long long ByteVector::toLongLong(unsigned int offset, bool mostSignificantByteFirst) const
{
return toNumber<unsigned long long>(*this, offset, mostSignificantByteFirst);
return toNumber<uint64_t>(*this, offset, mostSignificantByteFirst);
}
unsigned long long ByteVector::toULongLong(bool mostSignificantByteFirst) const
{
return toNumber<unsigned long long>(*this, 0, mostSignificantByteFirst);
return toNumber<uint64_t>(*this, 0, mostSignificantByteFirst);
}
unsigned long long ByteVector::toULongLong(unsigned int offset, bool mostSignificantByteFirst) const
{
return toNumber<unsigned long long>(*this, offset, mostSignificantByteFirst);
return toNumber<uint64_t>(*this, offset, mostSignificantByteFirst);
}
float ByteVector::toFloat32LE(size_t offset) const
{
return toFloat<float, unsigned int, Utils::LittleEndian>(*this, offset);
return toFloat<float, uint32_t, Utils::LittleEndian>(*this, offset);
}
float ByteVector::toFloat32BE(size_t offset) const
{
return toFloat<float, unsigned int, Utils::BigEndian>(*this, offset);
return toFloat<float, uint32_t, Utils::BigEndian>(*this, offset);
}
double ByteVector::toFloat64LE(size_t offset) const
{
return toFloat<double, unsigned long long, Utils::LittleEndian>(*this, offset);
return toFloat<double, uint64_t, Utils::LittleEndian>(*this, offset);
}
double ByteVector::toFloat64BE(size_t offset) const
{
return toFloat<double, unsigned long long, Utils::BigEndian>(*this, offset);
return toFloat<double, uint64_t, Utils::BigEndian>(*this, offset);
}
long double ByteVector::toFloat80LE(size_t offset) const
@@ -767,6 +775,9 @@ bool ByteVector::operator!=(const ByteVector &v) const
bool ByteVector::operator==(const char *s) const
{
if(!s)
return isEmpty();
if(size() != ::strlen(s))
return false;

View File

@@ -195,23 +195,27 @@ String::String(const wchar_t *s) :
String::String(const wchar_t *s, Type t) :
d(std::make_shared<StringPrivate>())
{
if(t == UTF16 || t == UTF16BE || t == UTF16LE) {
copyFromUTF16(d->data, s, ::wcslen(s), t);
}
else {
debug("String::String() -- const wchar_t * should not contain Latin1 or UTF-8.");
if(s) {
if(t == UTF16 || t == UTF16BE || t == UTF16LE) {
copyFromUTF16(d->data, s, ::wcslen(s), t);
}
else {
debug("String::String() -- const wchar_t * should not contain Latin1 or UTF-8.");
}
}
}
String::String(const char *s, Type t) :
d(std::make_shared<StringPrivate>())
{
if(t == Latin1)
copyFromLatin1(d->data, s, ::strlen(s));
else if(t == String::UTF8)
copyFromUTF8(d->data, s, ::strlen(s));
else {
debug("String::String() -- const char * should not contain UTF16.");
if(s) {
if(t == Latin1)
copyFromLatin1(d->data, s, ::strlen(s));
else if(t == String::UTF8)
copyFromUTF8(d->data, s, ::strlen(s));
else {
debug("String::String() -- const char * should not contain UTF16.");
}
}
}
@@ -546,6 +550,10 @@ bool String::operator!=(const String &s) const
bool String::operator==(const char *s) const
{
if(!s) {
return isEmpty();
}
const wchar_t *p = toCWString();
while(*p != L'\0' || *s != '\0') {
@@ -562,6 +570,10 @@ bool String::operator!=(const char *s) const
bool String::operator==(const wchar_t *s) const
{
if(!s) {
return isEmpty();
}
return d->data == s;
}
@@ -580,18 +592,22 @@ String &String::operator+=(const String &s)
String &String::operator+=(const wchar_t *s)
{
detach();
if(s) {
detach();
d->data += s;
d->data += s;
}
return *this;
}
String &String::operator+=(const char *s)
{
detach();
if(s) {
detach();
for(int i = 0; s[i] != 0; i++)
d->data += static_cast<unsigned char>(s[i]);
for(int i = 0; s[i] != 0; i++)
d->data += static_cast<unsigned char>(s[i]);
}
return *this;
}

View File

@@ -30,6 +30,7 @@
#ifndef DO_NOT_DOCUMENT // tell Doxygen not to document this header
#include <cstdint>
#include <cstdio>
#include <cstdarg>
#include <cstring>
@@ -60,7 +61,7 @@ namespace TagLib
/*!
* Reverses the order of bytes in a 16-bit integer.
*/
inline unsigned short byteSwap(unsigned short x)
inline uint16_t byteSwap(uint16_t x)
{
#if defined(HAVE_GCC_BYTESWAP)
@@ -92,7 +93,7 @@ namespace TagLib
/*!
* Reverses the order of bytes in a 32-bit integer.
*/
inline unsigned int byteSwap(unsigned int x)
inline uint32_t byteSwap(uint32_t x)
{
#if defined(HAVE_GCC_BYTESWAP)
@@ -127,7 +128,7 @@ namespace TagLib
/*!
* Reverses the order of bytes in a 64-bit integer.
*/
inline unsigned long long byteSwap(unsigned long long x)
inline uint64_t byteSwap(uint64_t x)
{
#if defined(HAVE_GCC_BYTESWAP)

View File

@@ -145,7 +145,7 @@ void TrueAudio::Properties::read(const ByteVector &data, offset_t streamLength)
if(d->sampleFrames > 0 && d->sampleRate > 0) {
const auto length = static_cast<double>(d->sampleFrames) * 1000.0 / d->sampleRate;
d->length = static_cast<int>(length + 0.5);
d->bitrate = static_cast<int>(streamLength * 8.0 / length + 0.5);
d->bitrate = static_cast<int>(static_cast<double>(streamLength) * 8.0 / length + 0.5);
}
}
}

View File

@@ -288,7 +288,7 @@ void WavPack::Properties::read(File *file, offset_t streamLength)
if(d->version < MIN_STREAM_VERS || d->version > MAX_STREAM_VERS)
break;
d->bitsPerSample = ((flags & BYTES_STORED) + 1) * 8 - ((flags & SHIFT_MASK) >> SHIFT_LSB);
d->bitsPerSample = static_cast<int>(((flags & BYTES_STORED) + 1) * 8 - ((flags & SHIFT_MASK) >> SHIFT_LSB));
d->sampleRate = static_cast<int>(smplRate);
d->lossless = !(flags & HYBRID_FLAG);
d->sampleFrames = smplFrames;
@@ -308,7 +308,7 @@ void WavPack::Properties::read(File *file, offset_t streamLength)
if(d->sampleFrames > 0 && d->sampleRate > 0) {
const auto length = static_cast<double>(d->sampleFrames) * 1000.0 / d->sampleRate;
d->length = static_cast<int>(length + 0.5);
d->bitrate = static_cast<int>(streamLength * 8.0 / length + 0.5);
d->bitrate = static_cast<int>(static_cast<double>(streamLength) * 8.0 / length + 0.5);
}
}

View File

@@ -1,33 +1,71 @@
INCLUDE_DIRECTORIES(
SET(test_HDR_DIRS
${CMAKE_CURRENT_SOURCE_DIR}/../taglib
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/toolkit
${CMAKE_CURRENT_SOURCE_DIR}/../bindings/c
${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
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/dsf
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/dsdiff
)
IF(WITH_APE)
SET(test_HDR_DIRS ${test_HDR_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/ape
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mpc
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/wavpack
)
ENDIF()
IF(WITH_ASF)
SET(test_HDR_DIRS ${test_HDR_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/asf
)
ENDIF()
IF(WITH_MP4)
SET(test_HDR_DIRS ${test_HDR_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mp4
)
ENDIF()
IF(WITH_RIFF)
SET(test_HDR_DIRS ${test_HDR_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/riff
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/riff/aiff
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/riff/wav
)
ENDIF()
IF(WITH_TRUEAUDIO)
SET(test_HDR_DIRS ${test_HDR_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/trueaudio
)
ENDIF()
IF(WITH_VORBIS)
SET(test_HDR_DIRS ${test_HDR_DIRS}
${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
)
ENDIF()
IF(WITH_MOD)
SET(test_HDR_DIRS ${test_HDR_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mod
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/s3m
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/it
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/xm
)
ENDIF()
IF(WITH_DSF)
SET(test_HDR_DIRS ${test_HDR_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/dsf
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/dsdiff
)
ENDIF()
IF(WITH_SHORTEN)
SET(test_HDR_DIRS ${test_HDR_DIRS}
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/shorten
)
ENDIF()
INCLUDE_DIRECTORIES(${test_HDR_DIRS})
SET(test_runner_SRCS
main.cpp
@@ -35,7 +73,6 @@ SET(test_runner_SRCS
test_map.cpp
test_mpeg.cpp
test_synchdata.cpp
test_trueaudio.cpp
test_bytevector.cpp
test_bytevectorlist.cpp
test_bytevectorstream.cpp
@@ -48,35 +85,73 @@ SET(test_runner_SRCS
test_id3v1.cpp
test_id3v2.cpp
test_id3v2framefactory.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
test_speex.cpp
test_dsf.cpp
test_dsdiff.cpp
test_sizes.cpp
test_versionnumber.cpp
)
IF(WITH_TRUEAUDIO)
SET(test_runner_SRCS ${test_runner_SRCS}
test_trueaudio.cpp
)
ENDIF()
IF(WITH_VORBIS)
SET(test_runner_SRCS ${test_runner_SRCS}
test_xiphcomment.cpp
test_ogg.cpp
test_oggflac.cpp
test_flac.cpp
test_flacpicture.cpp
test_flacunknownmetadatablock.cpp
test_opus.cpp
test_speex.cpp
)
ENDIF()
IF(WITH_RIFF)
SET(test_runner_SRCS ${test_runner_SRCS}
test_aiff.cpp
test_riff.cpp
test_wav.cpp
test_info.cpp
)
ENDIF()
if(WITH_APE)
SET(test_runner_SRCS ${test_runner_SRCS}
test_ape.cpp
test_apetag.cpp
test_wavpack.cpp
test_mpc.cpp
)
ENDIF()
IF(WITH_MP4)
SET(test_runner_SRCS ${test_runner_SRCS}
test_mp4.cpp
test_mp4item.cpp
test_mp4coverart.cpp
)
ENDIF()
IF(WITH_ASF)
SET(test_runner_SRCS ${test_runner_SRCS}
test_asf.cpp
)
ENDIF()
IF(WITH_MOD)
SET(test_runner_SRCS ${test_runner_SRCS}
test_mod.cpp
test_s3m.cpp
test_it.cpp
test_xm.cpp
)
ENDIF()
IF(WITH_DSF)
SET(test_runner_SRCS ${test_runner_SRCS}
test_dsf.cpp
test_dsdiff.cpp
)
ENDIF()
IF(WITH_SHORTEN)
SET(test_runner_SRCS ${test_runner_SRCS}
test_shorten.cpp
)
ENDIF()
IF(BUILD_BINDINGS)
SET(test_runner_SRCS ${test_runner_SRCS}
test_tag_c.cpp

File diff suppressed because one or more lines are too long

BIN
tests/data/itunes10.mp3 Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -23,6 +23,7 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <cstring>
#define _USE_MATH_DEFINES
#include <cmath>
@@ -53,6 +54,7 @@ class TestByteVector : public CppUnit::TestFixture
CPPUNIT_TEST(testAppend1);
CPPUNIT_TEST(testAppend2);
CPPUNIT_TEST(testBase64);
CPPUNIT_TEST(testEmpty);
CPPUNIT_TEST_SUITE_END();
public:
@@ -558,7 +560,7 @@ public:
// reverse
{
for(int i = 0; i < 256; i++){
all[i]=static_cast<unsigned char>(255)-i;
all[i]=static_cast<unsigned char>(255 - i);
}
ByteVector b64 = all.toBase64();
ByteVector original = ByteVector::fromBase64(b64);
@@ -612,6 +614,94 @@ public:
}
void testEmpty()
{
const ByteVector empty;
const ByteVector notEmpty("A");
ByteVector mutEmpty;
CPPUNIT_ASSERT_EQUAL(empty, ByteVector(""));
CPPUNIT_ASSERT_EQUAL(empty, ByteVector("", 0));
CPPUNIT_ASSERT_EQUAL(empty, ByteVector(0U));
CPPUNIT_ASSERT_EQUAL(empty, ByteVector(empty, 0, 0));
CPPUNIT_ASSERT_EQUAL(empty, ByteVector(notEmpty, 1, 0));
CPPUNIT_ASSERT_EQUAL(empty, ByteVector(static_cast<const char *>(nullptr)));
CPPUNIT_ASSERT_EQUAL(empty, ByteVector(static_cast<const char *>(nullptr), 0));
CPPUNIT_ASSERT_EQUAL(mutEmpty.setData("", 0), empty);
CPPUNIT_ASSERT_EQUAL(mutEmpty.setData(""), empty);
CPPUNIT_ASSERT_EQUAL(mutEmpty.setData(nullptr, 0), empty);
CPPUNIT_ASSERT_EQUAL(mutEmpty.setData(nullptr), empty);
CPPUNIT_ASSERT(!empty.data());
CPPUNIT_ASSERT(!mutEmpty.data());
CPPUNIT_ASSERT_EQUAL(empty.mid(0), empty);
CPPUNIT_ASSERT_EQUAL(empty.at(0), '\0');
// Note that the behavior of ByteVector::find() with an empty pattern is
// not consistent with String::find() and std::string::find().
CPPUNIT_ASSERT_EQUAL(empty.find(mutEmpty), -1);
CPPUNIT_ASSERT_EQUAL(empty.find(notEmpty), -1);
CPPUNIT_ASSERT_EQUAL(notEmpty.find(empty), -1);
CPPUNIT_ASSERT_EQUAL(empty.find('\0'), -1);
CPPUNIT_ASSERT_EQUAL(empty.rfind(mutEmpty), -1);
CPPUNIT_ASSERT_EQUAL(empty.rfind(notEmpty), -1);
CPPUNIT_ASSERT_EQUAL(notEmpty.rfind(empty), -1);
CPPUNIT_ASSERT_EQUAL(empty.containsAt(mutEmpty, 0), false);
CPPUNIT_ASSERT_EQUAL(empty.startsWith(mutEmpty), false);
CPPUNIT_ASSERT_EQUAL(empty.startsWith(notEmpty), false);
CPPUNIT_ASSERT_EQUAL(notEmpty.startsWith(empty), false);
CPPUNIT_ASSERT_EQUAL(empty.endsWith(mutEmpty), false);
CPPUNIT_ASSERT_EQUAL(empty.endsWithPartialMatch(mutEmpty), -1);
CPPUNIT_ASSERT_EQUAL(mutEmpty.replace('a', 'b'), empty);
CPPUNIT_ASSERT_EQUAL(mutEmpty.replace("abc", ""), empty);
CPPUNIT_ASSERT_EQUAL(mutEmpty.append(empty), empty);
CPPUNIT_ASSERT_EQUAL(mutEmpty.append(notEmpty), notEmpty);
mutEmpty.clear();
CPPUNIT_ASSERT_EQUAL(mutEmpty, empty);
CPPUNIT_ASSERT_EQUAL(ByteVector(notEmpty).append(empty), notEmpty);
CPPUNIT_ASSERT_EQUAL(mutEmpty.append('A'), notEmpty);
CPPUNIT_ASSERT_EQUAL(mutEmpty.resize(0), empty);
CPPUNIT_ASSERT_EQUAL(empty.size(), 0U);
CPPUNIT_ASSERT(empty.begin() == empty.end());
CPPUNIT_ASSERT(empty.cbegin() == empty.cend());
CPPUNIT_ASSERT(empty.rbegin() == empty.rend());
CPPUNIT_ASSERT(mutEmpty.begin() == mutEmpty.end());
CPPUNIT_ASSERT(mutEmpty.rbegin() == mutEmpty.rend());
CPPUNIT_ASSERT(empty.isEmpty());
CPPUNIT_ASSERT_EQUAL(empty.toUInt(), 0U);
CPPUNIT_ASSERT_EQUAL(empty.toUInt(0, true), 0U);
CPPUNIT_ASSERT_EQUAL(empty.toUInt(0, 0, true), 0U);
CPPUNIT_ASSERT_EQUAL(empty.toShort(), static_cast<short>(0));
CPPUNIT_ASSERT_EQUAL(empty.toShort(0, true), static_cast<short>(0));
CPPUNIT_ASSERT_EQUAL(empty.toUShort(), static_cast<unsigned short>(0));
CPPUNIT_ASSERT_EQUAL(empty.toUShort(0, true), static_cast<unsigned short>(0));
CPPUNIT_ASSERT_EQUAL(empty.toLongLong(), 0LL);
CPPUNIT_ASSERT_EQUAL(empty.toLongLong(0, true), 0LL);
CPPUNIT_ASSERT_EQUAL(empty.toULongLong(), 0ULL);
CPPUNIT_ASSERT_EQUAL(empty.toULongLong(0, true), 0ULL);
CPPUNIT_ASSERT_EQUAL(empty.toFloat32LE(0), 0.f);
CPPUNIT_ASSERT_EQUAL(empty.toFloat32BE(0), 0.f);
CPPUNIT_ASSERT_EQUAL(empty.toFloat64LE(0), 0.);
CPPUNIT_ASSERT_EQUAL(empty.toFloat64BE(0), 0.);
CPPUNIT_ASSERT_EQUAL(empty.toFloat80LE(0), 0.l);
CPPUNIT_ASSERT_EQUAL(empty.toFloat80BE(0), 0.l);
CPPUNIT_ASSERT(empty == mutEmpty);
CPPUNIT_ASSERT(empty != notEmpty);
CPPUNIT_ASSERT(empty == "");
CPPUNIT_ASSERT(empty != " ");
CPPUNIT_ASSERT(empty == static_cast<const char *>(nullptr));
CPPUNIT_ASSERT(!(empty != static_cast<const char *>(nullptr)));
CPPUNIT_ASSERT(empty < notEmpty);
CPPUNIT_ASSERT(!(empty > notEmpty));
CPPUNIT_ASSERT_EQUAL(empty + mutEmpty, empty);
CPPUNIT_ASSERT_EQUAL(empty + notEmpty, notEmpty);
CPPUNIT_ASSERT_EQUAL(mutEmpty = static_cast<const char *>(nullptr), empty);
CPPUNIT_ASSERT_EQUAL(mutEmpty = notEmpty, notEmpty);
ByteVector tmp;
mutEmpty.swap(tmp);
CPPUNIT_ASSERT_EQUAL(mutEmpty, empty);
CPPUNIT_ASSERT_EQUAL(empty.toHex(), empty);
CPPUNIT_ASSERT_EQUAL(empty.toBase64(), empty);
}
};
CPPUNIT_TEST_SUITE_REGISTRATION(TestByteVector);

View File

@@ -23,21 +23,30 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include "asfpicture.h"
#include "flacpicture.h"
#include "flacfile.h"
#include "taglib_config.h"
#include "tbytevector.h"
#include "tvariant.h"
#include "tzlib.h"
#include "fileref.h"
#include "apetag.h"
#include "asftag.h"
#include "mp4tag.h"
#include "xiphcomment.h"
#include "id3v1tag.h"
#include "id3v2tag.h"
#include "attachedpictureframe.h"
#include "generalencapsulatedobjectframe.h"
#ifdef TAGLIB_WITH_ASF
#include "asfpicture.h"
#include "asftag.h"
#endif
#ifdef TAGLIB_WITH_VORBIS
#include "flacpicture.h"
#include "flacfile.h"
#include "xiphcomment.h"
#endif
#ifdef TAGLIB_WITH_APE
#include "apetag.h"
#endif
#ifdef TAGLIB_WITH_MP4
#include "mp4tag.h"
#endif
#include <cppunit/extensions/HelperMacros.h>
#include "utils.h"
@@ -69,17 +78,25 @@ class TestComplexProperties : public CppUnit::TestFixture
{
CPPUNIT_TEST_SUITE(TestComplexProperties);
CPPUNIT_TEST(testReadMp3Picture);
CPPUNIT_TEST(testSetGetId3Geob);
CPPUNIT_TEST(testSetGetId3Picture);
CPPUNIT_TEST(testNonExistent);
#ifdef TAGLIB_WITH_MP4
CPPUNIT_TEST(testReadM4aPicture);
CPPUNIT_TEST(testSetGetMp4Picture);
#endif
#ifdef TAGLIB_WITH_VORBIS
CPPUNIT_TEST(testReadOggPicture);
CPPUNIT_TEST(testReadWriteFlacPicture);
CPPUNIT_TEST(testReadWriteMultipleProperties);
CPPUNIT_TEST(testSetGetId3Geob);
CPPUNIT_TEST(testSetGetId3Picture);
CPPUNIT_TEST(testSetGetApePicture);
CPPUNIT_TEST(testSetGetAsfPicture);
CPPUNIT_TEST(testSetGetMp4Picture);
CPPUNIT_TEST(testSetGetXiphPicture);
CPPUNIT_TEST(testNonExistent);
#endif
#ifdef TAGLIB_WITH_APE
CPPUNIT_TEST(testSetGetApePicture);
#endif
#ifdef TAGLIB_WITH_ASF
CPPUNIT_TEST(testSetGetAsfPicture);
#endif
CPPUNIT_TEST_SUITE_END();
public:
@@ -103,6 +120,7 @@ public:
}
}
#ifdef TAGLIB_WITH_MP4
void testReadM4aPicture()
{
const ByteVector expectedData1(
@@ -145,7 +163,9 @@ public:
CPPUNIT_ASSERT_EQUAL(String("image/jpeg"),
picture.value("mimeType").value<String>());
}
#endif
#ifdef TAGLIB_WITH_VORBIS
void testReadOggPicture()
{
FileRef f(TEST_FILE_PATH_C("lowercase-fields.ogg"), false);
@@ -217,6 +237,7 @@ public:
CPPUNIT_ASSERT(f.pictureList().isEmpty());
}
}
#endif
void testReadWriteMultipleProperties()
{
@@ -311,6 +332,7 @@ public:
CPPUNIT_ASSERT_EQUAL(ID3v2::AttachedPictureFrame::FrontCover, frame->type());
}
#ifdef TAGLIB_WITH_APE
void testSetGetApePicture()
{
const String FRONT_COVER("COVER ART (FRONT)");
@@ -326,7 +348,9 @@ public:
.append(picture.value("data").value<ByteVector>()),
item.binaryData());
}
#endif
#ifdef TAGLIB_WITH_ASF
void testSetGetAsfPicture()
{
VariantMap picture(TEST_PICTURE);
@@ -344,7 +368,9 @@ public:
asfPicture.description());
CPPUNIT_ASSERT_EQUAL(ASF::Picture::FrontCover, asfPicture.type());
}
#endif
#ifdef TAGLIB_WITH_MP4
void testSetGetMp4Picture()
{
VariantMap picture(TEST_PICTURE);
@@ -360,7 +386,9 @@ public:
covr.data());
CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::JPEG, covr.format());
}
#endif
#ifdef TAGLIB_WITH_VORBIS
void testSetGetXiphPicture()
{
VariantMap picture(TEST_PICTURE);
@@ -386,6 +414,7 @@ public:
CPPUNIT_ASSERT_EQUAL(1, pic->width());
CPPUNIT_ASSERT_EQUAL(1, pic->height());
}
#endif
void testNonExistent()
{

View File

@@ -26,27 +26,44 @@
#include <string>
#include <cstdio>
#include "taglib_config.h"
#include "tfilestream.h"
#include "tbytevectorstream.h"
#include "tag.h"
#include "fileref.h"
#include "mpegfile.h"
#ifdef TAGLIB_WITH_VORBIS
#include "oggflacfile.h"
#include "vorbisfile.h"
#include "mpegfile.h"
#include "mpcfile.h"
#include "asffile.h"
#include "speexfile.h"
#include "flacfile.h"
#include "trueaudiofile.h"
#include "mp4file.h"
#include "wavfile.h"
#include "apefile.h"
#include "aifffile.h"
#include "wavpackfile.h"
#include "opusfile.h"
#endif
#ifdef TAGLIB_WITH_APE
#include "mpcfile.h"
#include "apefile.h"
#include "wavpackfile.h"
#endif
#ifdef TAGLIB_WITH_ASF
#include "asffile.h"
#endif
#ifdef TAGLIB_WITH_TRUEAUDIO
#include "trueaudiofile.h"
#endif
#ifdef TAGLIB_WITH_MP4
#include "mp4file.h"
#endif
#ifdef TAGLIB_WITH_RIFF
#include "wavfile.h"
#include "aifffile.h"
#endif
#ifdef TAGLIB_WITH_MOD
#include "xmfile.h"
#endif
#ifdef TAGLIB_WITH_DSF
#include "dsffile.h"
#include "dsdifffile.h"
#endif
#include <cppunit/extensions/HelperMacros.h>
#include "utils.h"
@@ -55,6 +72,7 @@ using namespace TagLib;
namespace
{
#ifdef TAGLIB_WITH_VORBIS
class DummyResolver : public FileRef::FileTypeResolver
{
public:
@@ -63,7 +81,9 @@ namespace
return new Ogg::Vorbis::File(fileName);
}
};
#endif
#ifdef TAGLIB_WITH_MP4
class DummyStreamResolver : public FileRef::StreamTypeResolver
{
public:
@@ -77,36 +97,51 @@ namespace
return new MP4::File(s);
}
};
#endif
} // namespace
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(testMP4_4);
CPPUNIT_TEST(testTrueAudio);
CPPUNIT_TEST(testAPE);
CPPUNIT_TEST(testWav);
CPPUNIT_TEST(testAIFF_1);
CPPUNIT_TEST(testAIFF_2);
CPPUNIT_TEST(testWavPack);
CPPUNIT_TEST(testOpus);
CPPUNIT_TEST(testDSF);
CPPUNIT_TEST(testDSDIFF);
CPPUNIT_TEST(testUnsupported);
CPPUNIT_TEST(testAudioProperties);
CPPUNIT_TEST(testDefaultFileExtensions);
CPPUNIT_TEST(testFileResolver);
#ifdef TAGLIB_WITH_ASF
CPPUNIT_TEST(testASF);
#endif
#ifdef TAGLIB_WITH_APE
CPPUNIT_TEST(testMusepack);
CPPUNIT_TEST(testAPE);
CPPUNIT_TEST(testWavPack);
#endif
#ifdef TAGLIB_WITH_VORBIS
CPPUNIT_TEST(testVorbis);
CPPUNIT_TEST(testSpeex);
CPPUNIT_TEST(testFLAC);
CPPUNIT_TEST(testOGA_FLAC);
CPPUNIT_TEST(testOGA_Vorbis);
CPPUNIT_TEST(testOpus);
#endif
#ifdef TAGLIB_WITH_MP4
CPPUNIT_TEST(testMP4_1);
CPPUNIT_TEST(testMP4_2);
CPPUNIT_TEST(testMP4_3);
CPPUNIT_TEST(testMP4_4);
#endif
#ifdef TAGLIB_WITH_TRUEAUDIO
CPPUNIT_TEST(testTrueAudio);
#endif
#ifdef TAGLIB_WITH_RIFF
CPPUNIT_TEST(testWav);
CPPUNIT_TEST(testAIFF_1);
CPPUNIT_TEST(testAIFF_2);
#endif
#ifdef TAGLIB_WITH_DSF
CPPUNIT_TEST(testDSF);
CPPUNIT_TEST(testDSDIFF);
#endif
CPPUNIT_TEST_SUITE_END();
public:
@@ -239,16 +274,21 @@ public:
}
}
#ifdef TAGLIB_WITH_APE
void testMusepack()
{
fileRefSave<MPC::File>("click", ".mpc");
}
#endif
#ifdef TAGLIB_WITH_ASF
void testASF()
{
fileRefSave<ASF::File>("silence-1", ".wma");
}
#endif
#ifdef TAGLIB_WITH_VORBIS
void testVorbis()
{
fileRefSave<Ogg::Vorbis::File>("empty", ".ogg");
@@ -263,17 +303,21 @@ public:
{
fileRefSave<FLAC::File>("no-tags", ".flac");
}
#endif
void testMP3()
{
fileRefSave<MPEG::File>("xing", ".mp3");
}
#ifdef TAGLIB_WITH_TRUEAUDIO
void testTrueAudio()
{
fileRefSave<TrueAudio::File>("empty", ".tta");
}
#endif
#ifdef TAGLIB_WITH_MP4
void testMP4_1()
{
fileRefSave<MP4::File>("has-tags", ".m4a");
@@ -293,12 +337,16 @@ public:
{
fileRefSave<MP4::File>("blank_video", ".m4v");
}
#endif
#ifdef TAGLIB_WITH_RIFF
void testWav()
{
fileRefSave<RIFF::WAV::File>("empty", ".wav");
}
#endif
#ifdef TAGLIB_WITH_VORBIS
void testOGA_FLAC()
{
fileRefSave<Ogg::FLAC::File>("empty_flac", ".oga");
@@ -308,12 +356,16 @@ public:
{
fileRefSave<Ogg::Vorbis::File>("empty_vorbis", ".oga");
}
#endif
#ifdef TAGLIB_WITH_APE
void testAPE()
{
fileRefSave<APE::File>("mac-399", ".ape");
}
#endif
#ifdef TAGLIB_WITH_RIFF
void testAIFF_1()
{
fileRefSave<RIFF::AIFF::File>("empty", ".aiff");
@@ -323,17 +375,23 @@ public:
{
fileRefSave<RIFF::AIFF::File>("alaw", ".aifc");
}
#endif
#ifdef TAGLIB_WITH_APE
void testWavPack()
{
fileRefSave<WavPack::File>("click", ".wv");
}
#endif
#ifdef TAGLIB_WITH_VORBIS
void testOpus()
{
fileRefSave<Ogg::Opus::File>("correctness_gain_silent_output", ".opus");
}
#endif
#ifdef TAGLIB_WITH_DSF
void testDSF()
{
fileRefSave<DSF::File>("empty10ms",".dsf");
@@ -343,6 +401,7 @@ public:
{
fileRefSave<DSDIFF::File>("empty10ms",".dff");
}
#endif
void testUnsupported()
{
@@ -364,27 +423,56 @@ public:
void testDefaultFileExtensions()
{
const StringList extensions = FileRef::defaultFileExtensions();
#ifdef TAGLIB_WITH_APE
CPPUNIT_ASSERT(extensions.contains("mpc"));
#endif
#ifdef TAGLIB_WITH_ASF
CPPUNIT_ASSERT(extensions.contains("wma"));
#endif
#ifdef TAGLIB_WITH_VORBIS
CPPUNIT_ASSERT(extensions.contains("ogg"));
CPPUNIT_ASSERT(extensions.contains("spx"));
CPPUNIT_ASSERT(extensions.contains("flac"));
#endif
CPPUNIT_ASSERT(extensions.contains("mp3"));
#ifdef TAGLIB_WITH_TRUEAUDIO
CPPUNIT_ASSERT(extensions.contains("tta"));
#endif
#ifdef TAGLIB_WITH_MP4
CPPUNIT_ASSERT(extensions.contains("m4a"));
CPPUNIT_ASSERT(extensions.contains("3g2"));
CPPUNIT_ASSERT(extensions.contains("m4v"));
#endif
#ifdef TAGLIB_WITH_RIFF
CPPUNIT_ASSERT(extensions.contains("wav"));
#endif
#ifdef TAGLIB_WITH_VORBIS
CPPUNIT_ASSERT(extensions.contains("oga"));
#endif
#ifdef TAGLIB_WITH_APE
CPPUNIT_ASSERT(extensions.contains("ape"));
#endif
#ifdef TAGLIB_WITH_RIFF
CPPUNIT_ASSERT(extensions.contains("aiff"));
CPPUNIT_ASSERT(extensions.contains("aifc"));
#endif
#ifdef TAGLIB_WITH_APE
CPPUNIT_ASSERT(extensions.contains("wv"));
#endif
#ifdef TAGLIB_WITH_VORBIS
CPPUNIT_ASSERT(extensions.contains("opus"));
#endif
#ifdef TAGLIB_WITH_MOD
CPPUNIT_ASSERT(extensions.contains("xm"));
#endif
#ifdef TAGLIB_WITH_DSF
CPPUNIT_ASSERT(extensions.contains("dsf"));
CPPUNIT_ASSERT(extensions.contains("dff"));
CPPUNIT_ASSERT(extensions.contains("dsdiff"));
#endif
#ifdef TAGLIB_WITH_SHORTEN
CPPUNIT_ASSERT(extensions.contains("shn"));
#endif
}
void testFileResolver()
@@ -394,6 +482,7 @@ public:
CPPUNIT_ASSERT(dynamic_cast<MPEG::File *>(f.file()) != nullptr);
}
#ifdef TAGLIB_WITH_VORBIS
DummyResolver resolver;
FileRef::addFileTypeResolver(&resolver);
@@ -401,7 +490,9 @@ public:
FileRef f(TEST_FILE_PATH_C("xing.mp3"));
CPPUNIT_ASSERT(dynamic_cast<Ogg::Vorbis::File *>(f.file()) != nullptr);
}
#endif
#ifdef TAGLIB_WITH_MP4
DummyStreamResolver streamResolver;
FileRef::addFileTypeResolver(&streamResolver);
@@ -410,6 +501,7 @@ public:
FileRef f(&s);
CPPUNIT_ASSERT(dynamic_cast<MP4::File *>(f.file()) != nullptr);
}
#endif
FileRef::clearFileTypeResolvers();
}

View File

@@ -1035,7 +1035,7 @@ public:
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"));
tf->setText(StringList().append("Producer").append("Artist 3").append("Engineer").append("Artist 4"));
foo.ID3v2Tag()->addFrame(tf);
tf = new ID3v2::TextIdentificationFrame("TCON", String::Latin1);
tf->setText(StringList().append("51").append("Noise").append("Power Noise"));
@@ -1062,15 +1062,18 @@ public:
CPPUNIT_ASSERT_EQUAL(String("2012-04-17T12:01"), tf->fieldList().front());
tf = dynamic_cast<ID3v2::TextIdentificationFrame *>(bar.ID3v2Tag()->frameList("TIPL").front());
CPPUNIT_ASSERT(tf);
CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(8), tf->fieldList().size());
CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(4), tf->fieldList().size());
CPPUNIT_ASSERT_EQUAL(String("Producer"), tf->fieldList()[0]);
CPPUNIT_ASSERT_EQUAL(String("Artist 3"), tf->fieldList()[1]);
CPPUNIT_ASSERT_EQUAL(String("Engineer"), tf->fieldList()[2]);
CPPUNIT_ASSERT_EQUAL(String("Artist 4"), tf->fieldList()[3]);
tf = dynamic_cast<ID3v2::TextIdentificationFrame *>(bar.ID3v2Tag()->frameList("TMCL").front());
CPPUNIT_ASSERT(tf);
CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(4), 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]);
tf = dynamic_cast<ID3v2::TextIdentificationFrame *>(bar.ID3v2Tag()->frameList("TCON").front());
CPPUNIT_ASSERT(tf);
CPPUNIT_ASSERT_EQUAL(3U, tf->fieldList().size());
@@ -1090,7 +1093,7 @@ public:
}
{
const ByteVector expectedId3v23Data(
"ID3" "\x03\x00\x00\x00\x00\x09\x49"
"ID3" "\x03\x00\x00\x00\x00\x09\x48"
"TSOA" "\x00\x00\x00\x01\x00\x00\x00"
"TSOT" "\x00\x00\x00\x01\x00\x00\x00"
"TSOP" "\x00\x00\x00\x01\x00\x00\x00"
@@ -1098,10 +1101,10 @@ public:
"TYER" "\x00\x00\x00\x05\x00\x00\x00" "2012"
"TDAT" "\x00\x00\x00\x05\x00\x00\x00" "1704"
"TIME" "\x00\x00\x00\x05\x00\x00\x00" "1201"
"IPLS" "\x00\x00\x00\x44\x00\x00\x00" "Guitar" "\x00"
"IPLS" "\x00\x00\x00\x43\x00\x00\x00" "Guitar" "\x00"
"Artist 1" "\x00" "Drums" "\x00" "Artist 2" "\x00" "Producer" "\x00"
"Artist 3" "\x00" "Mastering" "\x00" "Artist 4"
"TCON" "\x00\x00\x00\x14\x00\x00\x00" "(51)(39)Power Noise", 211);
"Artist 3" "\x00" "Engineer" "\x00" "Artist 4"
"TCON" "\x00\x00\x00\x14\x00\x00\x00" "(51)(39)Power Noise", 210);
const ByteVector actualId3v23Data =
PlainFile(newname.c_str()).readBlock(expectedId3v23Data.size());
CPPUNIT_ASSERT_EQUAL(expectedId3v23Data, actualId3v23Data);
@@ -1265,6 +1268,38 @@ public:
CPPUNIT_ASSERT_EQUAL(static_cast<ID3v2::UserTextIdentificationFrame *>(nullptr), ID3v2::UserTextIdentificationFrame::find(&tag, "non existing"));
CPPUNIT_ASSERT_EQUAL(frame10, ID3v2::CommentsFrame::findByDescription(&tag, "iTunNORM"));
CPPUNIT_ASSERT_EQUAL(static_cast<ID3v2::CommentsFrame *>(nullptr), ID3v2::CommentsFrame::findByDescription(&tag, "non existing"));
// Check if the allowed TIPL keys are correctly mapped to properties.
// These are the keys used by MusicBrainz: arranger, engineer, producer, DJ-mix, mix.
// See https://picard-docs.musicbrainz.org/downloads/MusicBrainz_Picard_Tag_Map.html.
// MusicBrainz Picard uses lowercase keys whereas TagLib used uppercase keys.
auto frame11 = new ID3v2::TextIdentificationFrame("TIPL");
StringList tiplData;
tiplData.append("arranger");
tiplData.append("an arranger");
tiplData.append("ENGINEER");
tiplData.append("an engineer");
tiplData.append("producer");
tiplData.append("a producer");
tiplData.append("DJ-mix");
tiplData.append("a DJ mixer");
tiplData.append("mix");
tiplData.append("a mixer");
frame11->setText(tiplData);
tag.addFrame(frame11);
properties = tag.properties();
CPPUNIT_ASSERT_EQUAL(0u, properties.unsupportedData().size());
CPPUNIT_ASSERT(properties.contains("ARRANGER"));
CPPUNIT_ASSERT(properties.contains("ENGINEER"));
CPPUNIT_ASSERT(properties.contains("PRODUCER"));
CPPUNIT_ASSERT(properties.contains("DJMIXER"));
CPPUNIT_ASSERT(properties.contains("MIXER"));
CPPUNIT_ASSERT_EQUAL(String("an arranger"), properties["ARRANGER"].front());
CPPUNIT_ASSERT_EQUAL(String("an engineer"), properties["ENGINEER"].front());
CPPUNIT_ASSERT_EQUAL(String("a producer"), properties["PRODUCER"].front());
CPPUNIT_ASSERT_EQUAL(String("a DJ mixer"), properties["DJMIXER"].front());
CPPUNIT_ASSERT_EQUAL(String("a mixer"), properties["MIXER"].front());
}
void testPropertiesMovement()

View File

@@ -26,21 +26,30 @@
#include <functional>
#include <memory>
#include "flacproperties.h"
#include "taglib_config.h"
#include "mpegproperties.h"
#include "tbytevector.h"
#include "tpropertymap.h"
#include "mpegfile.h"
#include "flacfile.h"
#include "trueaudiofile.h"
#include "trueaudioproperties.h"
#include "wavfile.h"
#include "aifffile.h"
#include "dsffile.h"
#include "dsdifffile.h"
#include "id3v2tag.h"
#include "id3v2frame.h"
#include "id3v2framefactory.h"
#ifdef TAGLIB_WITH_VORBIS
#include "flacproperties.h"
#include "flacfile.h"
#endif
#ifdef TAGLIB_WITH_TRUEAUDIO
#include "trueaudiofile.h"
#include "trueaudioproperties.h"
#endif
#ifdef TAGLIB_WITH_RIFF
#include "wavfile.h"
#include "aifffile.h"
#endif
#ifdef TAGLIB_WITH_DSF
#include "dsffile.h"
#include "dsdifffile.h"
#endif
#include <cppunit/extensions/HelperMacros.h>
#include "utils.h"
@@ -118,12 +127,20 @@ class TestId3v2FrameFactory : public CppUnit::TestFixture
{
CPPUNIT_TEST_SUITE(TestId3v2FrameFactory);
CPPUNIT_TEST(testMPEG);
#ifdef TAGLIB_WITH_VORBIS
CPPUNIT_TEST(testFLAC);
#endif
#ifdef TAGLIB_WITH_TRUEAUDIO
CPPUNIT_TEST(testTrueAudio);
#endif
#ifdef TAGLIB_WITH_RIFF
CPPUNIT_TEST(testWAV);
CPPUNIT_TEST(testAIFF);
#endif
#ifdef TAGLIB_WITH_DSF
CPPUNIT_TEST(testDSF);
CPPUNIT_TEST(testDSDIFF);
#endif
CPPUNIT_TEST_SUITE_END();
public:
@@ -236,6 +253,7 @@ public:
);
}
#ifdef TAGLIB_WITH_VORBIS
void testFLAC()
{
ScopedFileCopy copy("no-tags", ".flac");
@@ -260,7 +278,9 @@ public:
}
);
}
#endif
#ifdef TAGLIB_WITH_TRUEAUDIO
void testTrueAudio()
{
ScopedFileCopy copy("empty", ".tta");
@@ -285,7 +305,9 @@ public:
}
);
}
#endif
#ifdef TAGLIB_WITH_RIFF
void testWAV()
{
ScopedFileCopy copy("empty", ".wav");
@@ -335,7 +357,9 @@ public:
}
);
}
#endif
#ifdef TAGLIB_WITH_DSF
void testDSF()
{
ScopedFileCopy copy("empty10ms", ".dsf");
@@ -385,6 +409,7 @@ public:
}
);
}
#endif
};

View File

@@ -101,6 +101,7 @@ class TestMP4 : public CppUnit::TestFixture
CPPUNIT_TEST(testRemoveMetadata);
CPPUNIT_TEST(testNonFullMetaAtom);
CPPUNIT_TEST(testItemFactory);
CPPUNIT_TEST(testNonPrintableAtom);
CPPUNIT_TEST_SUITE_END();
public:
@@ -441,6 +442,7 @@ public:
tags["BPM"] = StringList("123");
tags["ARTIST"] = StringList("Foo Bar");
tags["COMPILATION"] = StringList("1");
tags["REMIXEDBY"] = StringList("Remixed by");
f.setProperties(tags);
tags = f.properties();
@@ -467,6 +469,11 @@ public:
CPPUNIT_ASSERT_EQUAL(true, f.tag()->item("cpil").toBool());
CPPUNIT_ASSERT_EQUAL(StringList("1"), tags["COMPILATION"]);
CPPUNIT_ASSERT(f.tag()->contains("----:com.apple.iTunes:REMIXEDBY"));
CPPUNIT_ASSERT_EQUAL(StringList("Remixed by"),
f.tag()->item("----:com.apple.iTunes:REMIXEDBY").toStringList());
CPPUNIT_ASSERT_EQUAL(StringList("Remixed by"), tags["REMIXEDBY"]);
tags["COMPILATION"] = StringList("0");
f.setProperties(tags);
@@ -847,6 +854,25 @@ public:
CPPUNIT_ASSERT_EQUAL(StringList("456"), properties.value("TESTINTEGER"));
}
}
void testNonPrintableAtom()
{
ScopedFileCopy copy("nonprintable-atom-type", ".m4a");
{
MP4::File f(copy.fileName().c_str());
CPPUNIT_ASSERT(f.isValid());
CPPUNIT_ASSERT_EQUAL(1, f.audioProperties()->channels());
CPPUNIT_ASSERT_EQUAL(32000, f.audioProperties()->sampleRate());
f.tag()->setTitle("TITLE");
f.save();
}
{
MP4::File f(copy.fileName().c_str());
CPPUNIT_ASSERT(f.isValid());
CPPUNIT_ASSERT(f.hasMP4Tag());
CPPUNIT_ASSERT_EQUAL(String("TITLE"), f.tag()->title());
}
}
};
CPPUNIT_TEST_SUITE_REGISTRATION(TestMP4);

View File

@@ -27,12 +27,15 @@
#include <cstdio>
#include <array>
#include "taglib_config.h"
#include "tstring.h"
#include "tpropertymap.h"
#include "mpegfile.h"
#include "id3v2tag.h"
#include "id3v1tag.h"
#ifdef TAGLIB_WITH_APE
#include "apetag.h"
#endif
#include "mpegproperties.h"
#include "xingheader.h"
#include "mpegheader.h"
@@ -67,10 +70,13 @@ class TestMPEG : public CppUnit::TestFixture
CPPUNIT_TEST(testRepeatedSave3);
CPPUNIT_TEST(testEmptyID3v2);
CPPUNIT_TEST(testEmptyID3v1);
#ifdef TAGLIB_WITH_APE
CPPUNIT_TEST(testEmptyAPE);
#endif
CPPUNIT_TEST(testIgnoreGarbage);
CPPUNIT_TEST(testExtendedHeader);
CPPUNIT_TEST(testReadStyleFast);
CPPUNIT_TEST(testID3v22Properties);
CPPUNIT_TEST_SUITE_END();
public:
@@ -303,7 +309,9 @@ public:
{
MPEG::File f(copy.fileName().c_str());
f.ID3v2Tag(true)->setTitle("ID3v2");
#ifdef TAGLIB_WITH_APE
f.APETag(true)->setTitle("APE");
#endif
f.ID3v1Tag(true)->setTitle("ID3v1");
f.save();
}
@@ -311,8 +319,10 @@ public:
MPEG::File f(copy.fileName().c_str());
CPPUNIT_ASSERT_EQUAL(String("ID3v2"), f.properties()["TITLE"].front());
f.strip(MPEG::File::ID3v2);
#ifdef TAGLIB_WITH_APE
CPPUNIT_ASSERT_EQUAL(String("APE"), f.properties()["TITLE"].front());
f.strip(MPEG::File::APE);
#endif
CPPUNIT_ASSERT_EQUAL(String("ID3v1"), f.properties()["TITLE"].front());
f.strip(MPEG::File::ID3v1);
CPPUNIT_ASSERT(f.properties().isEmpty());
@@ -463,17 +473,23 @@ public:
CPPUNIT_ASSERT(!f.hasAPETag());
CPPUNIT_ASSERT(!f.hasID3v1Tag());
#ifdef TAGLIB_WITH_APE
f.APETag(true)->setTitle("01234 56789 ABCDE FGHIJ");
f.save();
f.APETag()->setTitle("0");
f.save();
#endif
f.ID3v1Tag(true)->setTitle("01234 56789 ABCDE FGHIJ");
#ifdef TAGLIB_WITH_APE
f.APETag()->setTitle("01234 56789 ABCDE FGHIJ 01234 56789 ABCDE FGHIJ 01234 56789");
#endif
f.save();
}
{
MPEG::File f(copy.fileName().c_str());
#ifdef TAGLIB_WITH_APE
CPPUNIT_ASSERT(f.hasAPETag());
#endif
CPPUNIT_ASSERT(f.hasID3v1Tag());
}
}
@@ -518,6 +534,7 @@ public:
}
}
#ifdef TAGLIB_WITH_APE
void testEmptyAPE()
{
ScopedFileCopy copy("xing", ".mp3");
@@ -537,6 +554,7 @@ public:
CPPUNIT_ASSERT(!f.hasAPETag());
}
}
#endif
void testIgnoreGarbage()
{
@@ -618,6 +636,56 @@ public:
}
}
void testID3v22Properties()
{
ScopedFileCopy copy("itunes10", ".mp3");
MPEG::File f(copy.fileName().c_str());
PropertyMap expectedProperties(SimplePropertyMap{
{"ALBUM", {"Album"}},
{"ALBUMARTIST", {"Album Artist"}},
{"ALBUMARTISTSORT", {"Sort Album Artist"}},
{"ALBUMSORT", {"Sort Album"}},
{"ARTIST", {"Artist"}},
{"ARTISTSORT", {"Sort Artist"}},
{"BPM", {"180"}},
{"COMMENT", {"Comments"}},
{"COMMENT:ITUNPGAP", {"1"}},
{"COMPILATION", {"1"}},
{"COMPOSER", {"Composer"}},
{"COMPOSERSORT", {"Sort Composer"}},
{"DATE", {"2011"}},
{"DISCNUMBER", {"1/2"}},
{"GENRE", {"Heavy Metal"}},
{"LYRICS", {"Lyrics"}},
{"SUBTITLE", {"Description"}},
{"TITLE", {"iTunes10MP3"}},
{"TITLESORT", {"Sort Name"}},
{"TRACKNUMBER", {"1/10"}},
{"WORK", {"Grouping"}}
});
expectedProperties.addUnsupportedData("APIC");
expectedProperties.addUnsupportedData("UNKNOWN/RVA");
PropertyMap properties = f.properties();
if (expectedProperties != properties) {
CPPUNIT_ASSERT_EQUAL(expectedProperties.toString(), properties.toString());
}
CPPUNIT_ASSERT(expectedProperties == properties);
const String PICTURE_KEY("PICTURE");
CPPUNIT_ASSERT_EQUAL(StringList(PICTURE_KEY), f.complexPropertyKeys());
auto pictures = f.complexProperties(PICTURE_KEY);
CPPUNIT_ASSERT_EQUAL(1U, pictures.size());
auto picture = pictures.front();
CPPUNIT_ASSERT_EQUAL(String("image/png"), picture.value("mimeType").toString());
CPPUNIT_ASSERT(picture.value("description").toString().isEmpty());
CPPUNIT_ASSERT_EQUAL(String("Other"), picture.value("pictureType").toString());
auto data = picture.value("data").toByteVector();
CPPUNIT_ASSERT(data.startsWith("\x89PNG\x0d\x0a\x1a\x0a"));
CPPUNIT_ASSERT_EQUAL(2315U, data.size());
}
};
CPPUNIT_TEST_SUITE_REGISTRATION(TestMPEG);

View File

@@ -23,15 +23,26 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include "taglib_config.h"
#include "tpropertymap.h"
#include "tag.h"
#include "apetag.h"
#include "asftag.h"
#include "id3v1tag.h"
#include "id3v2tag.h"
#ifdef TAGLIB_WITH_APE
#include "apetag.h"
#endif
#ifdef TAGLIB_WITH_ASF
#include "asftag.h"
#endif
#ifdef TAGLIB_WITH_RIFF
#include "infotag.h"
#endif
#ifdef TAGLIB_WITH_MP4
#include "mp4tag.h"
#endif
#ifdef TAGLIB_WITH_VORBIS
#include "xiphcomment.h"
#endif
#include <cppunit/extensions/HelperMacros.h>
#include "utils.h"
@@ -41,14 +52,24 @@ class TestPropertyMap : public CppUnit::TestFixture
{
CPPUNIT_TEST_SUITE(TestPropertyMap);
CPPUNIT_TEST(testInvalidKeys);
CPPUNIT_TEST(testGetSetApe);
CPPUNIT_TEST(testGetSetAsf);
CPPUNIT_TEST(testGetSetId3v1);
CPPUNIT_TEST(testGetSetId3v2);
CPPUNIT_TEST(testGetSetInfo);
CPPUNIT_TEST(testGetSetMp4);
CPPUNIT_TEST(testGetSetXiphComment);
CPPUNIT_TEST(testGetSet);
#ifdef TAGLIB_WITH_APE
CPPUNIT_TEST(testGetSetApe);
#endif
#ifdef TAGLIB_WITH_ASF
CPPUNIT_TEST(testGetSetAsf);
#endif
#ifdef TAGLIB_WITH_RIFF
CPPUNIT_TEST(testGetSetInfo);
#endif
#ifdef TAGLIB_WITH_MP4
CPPUNIT_TEST(testGetSetMp4);
#endif
#ifdef TAGLIB_WITH_VORBIS
CPPUNIT_TEST(testGetSetXiphComment);
#endif
CPPUNIT_TEST_SUITE_END();
public:
@@ -141,30 +162,40 @@ public:
tagGetSet<ID3v2::Tag>();
}
#ifdef TAGLIB_WITH_VORBIS
void testGetSetXiphComment()
{
tagGetSet<Ogg::XiphComment>();
}
#endif
#ifdef TAGLIB_WITH_APE
void testGetSetApe()
{
tagGetSet<APE::Tag>();
}
#endif
#ifdef TAGLIB_WITH_ASF
void testGetSetAsf()
{
tagGetSet<ASF::Tag>();
}
#endif
#ifdef TAGLIB_WITH_MP4
void testGetSetMp4()
{
tagGetSet<MP4::Tag>();
}
#endif
#ifdef TAGLIB_WITH_RIFF
void testGetSetInfo()
{
tagGetSet<RIFF::Info::Tag>();
}
#endif
void testGetSet()
{

44
tests/test_shorten.cpp Normal file
View File

@@ -0,0 +1,44 @@
#include <string>
#include <cstdio>
#include "tbytevectorlist.h"
#include "tpropertymap.h"
#include "tag.h"
#include "shortenfile.h"
#include "plainfile.h"
#include <cppunit/extensions/HelperMacros.h>
#include "utils.h"
using namespace std;
using namespace TagLib;
class TestShorten : public CppUnit::TestFixture
{
CPPUNIT_TEST_SUITE(TestShorten);
CPPUNIT_TEST(testBasic);
CPPUNIT_TEST(testTags);
CPPUNIT_TEST_SUITE_END();
public:
void testBasic()
{
Shorten::File f(TEST_FILE_PATH_C("2sec-silence.shn"));
CPPUNIT_ASSERT(f.audioProperties());
CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->lengthInSeconds());
CPPUNIT_ASSERT_EQUAL(2000, f.audioProperties()->lengthInMilliseconds());
CPPUNIT_ASSERT_EQUAL(1411, f.audioProperties()->bitrate());
CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->channels());
CPPUNIT_ASSERT_EQUAL(44100, f.audioProperties()->sampleRate());
CPPUNIT_ASSERT_EQUAL(2, f.audioProperties()->shortenVersion());
CPPUNIT_ASSERT_EQUAL(5, f.audioProperties()->fileType());
CPPUNIT_ASSERT_EQUAL(16, f.audioProperties()->bitsPerSample());
CPPUNIT_ASSERT_EQUAL(static_cast<unsigned long>(88200), f.audioProperties()->sampleFrames());
}
void testTags()
{
}
};
CPPUNIT_TEST_SUITE_REGISTRATION(TestShorten);

View File

@@ -25,34 +25,25 @@
#include <cstring>
#include "aifffile.h"
#include "aiffproperties.h"
#include "apefile.h"
#include "apefooter.h"
#include "apeitem.h"
#include "apeproperties.h"
#include "apetag.h"
#include "asfattribute.h"
#include "asffile.h"
#include "asfpicture.h"
#include "asfproperties.h"
#include "asftag.h"
#include "attachedpictureframe.h"
#include "audioproperties.h"
#include "chapterframe.h"
#include "commentsframe.h"
#include "dsffile.h"
#include "dsfproperties.h"
#include "dsdifffile.h"
#include "dsdiffproperties.h"
#include "eventtimingcodesframe.h"
#include "taglib_config.h"
#include "tag.h"
#include "tbytevector.h"
#include "tbytevectorlist.h"
#include "tbytevectorstream.h"
#include "tdebuglistener.h"
#include "tfile.h"
#include "tfilestream.h"
#include "tiostream.h"
#include "tlist.h"
#include "tmap.h"
#include "tpropertymap.h"
#include "tstring.h"
#include "tstringlist.h"
#include "fileref.h"
#include "flacfile.h"
#include "flacmetadatablock.h"
#include "flacunknownmetadatablock.h"
#include "flacpicture.h"
#include "flacproperties.h"
#include "generalencapsulatedobjectframe.h"
#include "mpegfile.h"
#include "mpegheader.h"
#include "mpegproperties.h"
#include "xingheader.h"
#include "id3v1tag.h"
#include "id3v2extendedheader.h"
#include "id3v2footer.h"
@@ -60,72 +51,103 @@
#include "id3v2framefactory.h"
#include "id3v2header.h"
#include "id3v2tag.h"
#include "attachedpictureframe.h"
#include "audioproperties.h"
#include "chapterframe.h"
#include "commentsframe.h"
#include "eventtimingcodesframe.h"
#include "generalencapsulatedobjectframe.h"
#include "ownershipframe.h"
#include "podcastframe.h"
#include "popularimeterframe.h"
#include "privateframe.h"
#include "relativevolumeframe.h"
#include "synchronizedlyricsframe.h"
#include "tableofcontentsframe.h"
#include "textidentificationframe.h"
#include "uniquefileidentifierframe.h"
#include "unknownframe.h"
#include "unsynchronizedlyricsframe.h"
#include "urllinkframe.h"
#ifdef TAGLIB_WITH_RIFF
#include "aifffile.h"
#include "aiffproperties.h"
#include "infotag.h"
#include "itfile.h"
#include "itproperties.h"
#include "modfile.h"
#include "modfilebase.h"
#include "modproperties.h"
#include "modtag.h"
#include "mp4coverart.h"
#include "mp4file.h"
#include "mp4item.h"
#include "mp4itemfactory.h"
#include "mp4properties.h"
#include "mp4tag.h"
#include "rifffile.h"
#include "wavfile.h"
#include "wavproperties.h"
#endif
#ifdef TAGLIB_WITH_APE
#include "apefile.h"
#include "apefooter.h"
#include "apeitem.h"
#include "apeproperties.h"
#include "apetag.h"
#include "mpcfile.h"
#include "mpcproperties.h"
#include "mpegfile.h"
#include "mpegheader.h"
#include "mpegproperties.h"
#include "wavpackfile.h"
#include "wavpackproperties.h"
#endif
#ifdef TAGLIB_WITH_ASF
#include "asfattribute.h"
#include "asffile.h"
#include "asfpicture.h"
#include "asfproperties.h"
#include "asftag.h"
#endif
#ifdef TAGLIB_WITH_DSF
#include "dsffile.h"
#include "dsfproperties.h"
#include "dsdifffile.h"
#include "dsdiffproperties.h"
#endif
#ifdef TAGLIB_WITH_VORBIS
#include "flacfile.h"
#include "flacmetadatablock.h"
#include "flacunknownmetadatablock.h"
#include "flacpicture.h"
#include "flacproperties.h"
#include "oggfile.h"
#include "oggflacfile.h"
#include "oggpage.h"
#include "oggpageheader.h"
#include "opusfile.h"
#include "opusproperties.h"
#include "ownershipframe.h"
#include "podcastframe.h"
#include "popularimeterframe.h"
#include "privateframe.h"
#include "relativevolumeframe.h"
#include "rifffile.h"
#include "s3mfile.h"
#include "s3mproperties.h"
#include "speexfile.h"
#include "speexproperties.h"
#include "synchronizedlyricsframe.h"
#include "tableofcontentsframe.h"
#include "tag.h"
#include "tbytevector.h"
#include "tbytevectorlist.h"
#include "tbytevectorstream.h"
#include "tdebuglistener.h"
#include "textidentificationframe.h"
#include "tfile.h"
#include "tfilestream.h"
#include "tiostream.h"
#include "tlist.h"
#include "tmap.h"
#include "tpropertymap.h"
#include "trueaudiofile.h"
#include "trueaudioproperties.h"
#include "tstring.h"
#include "tstringlist.h"
#include "uniquefileidentifierframe.h"
#include "unknownframe.h"
#include "unsynchronizedlyricsframe.h"
#include "urllinkframe.h"
#include "vorbisfile.h"
#include "vorbisproperties.h"
#include "wavfile.h"
#include "wavpackfile.h"
#include "wavpackproperties.h"
#include "wavproperties.h"
#include "xingheader.h"
#include "xiphcomment.h"
#endif
#ifdef TAGLIB_WITH_MOD
#include "itfile.h"
#include "itproperties.h"
#include "modfile.h"
#include "modfilebase.h"
#include "modproperties.h"
#include "modtag.h"
#include "s3mfile.h"
#include "s3mproperties.h"
#include "xmfile.h"
#include "xmproperties.h"
#endif
#ifdef TAGLIB_WITH_MP4
#include "mp4coverart.h"
#include "mp4file.h"
#include "mp4item.h"
#include "mp4itemfactory.h"
#include "mp4properties.h"
#include "mp4tag.h"
#endif
#ifdef TAGLIB_WITH_SHORTEN
#include "shortenfile.h"
#include "shortenproperties.h"
#include "shortentag.h"
#endif
#ifdef TAGLIB_WITH_TRUEAUDIO
#include "trueaudiofile.h"
#include "trueaudioproperties.h"
#endif
#include <cppunit/extensions/HelperMacros.h>
@@ -144,31 +166,11 @@ public:
// Class list was built by generating XML docs with Doxygen, and then running:
// $ grep kind=\"class\" index.xml | sed -E -e 's/(.*<name>|<\/name>.*)//g'
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::APE::File));
CPPUNIT_ASSERT_EQUAL(classSize(0, false), sizeof(TagLib::APE::Footer));
CPPUNIT_ASSERT_EQUAL(classSize(0, false), sizeof(TagLib::APE::Item));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::APE::Properties));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::APE::Tag));
CPPUNIT_ASSERT_EQUAL(classSize(1, false), sizeof(TagLib::ASF::Attribute));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::ASF::File));
CPPUNIT_ASSERT_EQUAL(classSize(1, false), sizeof(TagLib::ASF::Picture));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::ASF::Properties));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::ASF::Tag));
CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::AudioProperties));
CPPUNIT_ASSERT_EQUAL(classSize(0, false), sizeof(TagLib::ByteVector));
CPPUNIT_ASSERT_EQUAL(classSize(2, false), sizeof(TagLib::ByteVectorList));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::ByteVectorStream));
CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::DebugListener));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::DSDIFF::DIIN::Tag));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::DSDIFF::File));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::DSDIFF::Properties));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::FLAC::File));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::DSF::File));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::DSF::Properties));
CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::FLAC::MetadataBlock));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::FLAC::Picture));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::FLAC::Properties));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::FLAC::UnknownMetadataBlock));
CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::File));
CPPUNIT_ASSERT_EQUAL(classSize(1, false), sizeof(TagLib::FileRef));
CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::FileRef::FileTypeResolver));
@@ -204,26 +206,47 @@ public:
CPPUNIT_ASSERT_EQUAL(classSize(2, true), sizeof(TagLib::ID3v2::UserTextIdentificationFrame));
CPPUNIT_ASSERT_EQUAL(classSize(2, true), sizeof(TagLib::ID3v2::UserUrlLinkFrame));
CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::IOStream));
CPPUNIT_ASSERT_EQUAL(classSize(2, true), sizeof(TagLib::IT::File));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::IT::Properties));
CPPUNIT_ASSERT_EQUAL(classSize(1, false), sizeof(TagLib::List<int>));
CPPUNIT_ASSERT_EQUAL(classSize(1, false), sizeof(TagLib::MP4::CoverArt));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::MP4::File));
CPPUNIT_ASSERT_EQUAL(classSize(1, false), sizeof(TagLib::MP4::Item));
CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::MP4::ItemFactory));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::MP4::Properties));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::MP4::Tag));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::MPC::File));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::MPC::Properties));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::MPEG::File));
CPPUNIT_ASSERT_EQUAL(classSize(1, false), sizeof(TagLib::MPEG::Header));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::MPEG::Properties));
CPPUNIT_ASSERT_EQUAL(classSize(0, false), sizeof(TagLib::MPEG::XingHeader));
CPPUNIT_ASSERT_EQUAL(classSize(1, false), sizeof(TagLib::Map<int, int>));
CPPUNIT_ASSERT_EQUAL(classSize(2, true), sizeof(TagLib::Mod::File));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::Mod::FileBase));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::Mod::Properties));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::Mod::Tag));
CPPUNIT_ASSERT_EQUAL(classSize(2, false), sizeof(TagLib::PropertyMap));
CPPUNIT_ASSERT_EQUAL(classSize(1, false), sizeof(TagLib::String));
CPPUNIT_ASSERT_EQUAL(classSize(2, false), sizeof(TagLib::StringList));
CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::Tag));
#ifdef TAGLIB_WITH_APE
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::APE::File));
CPPUNIT_ASSERT_EQUAL(classSize(0, false), sizeof(TagLib::APE::Footer));
CPPUNIT_ASSERT_EQUAL(classSize(0, false), sizeof(TagLib::APE::Item));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::APE::Properties));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::APE::Tag));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::MPC::File));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::MPC::Properties));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::WavPack::File));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::WavPack::Properties));
#endif
#ifdef TAGLIB_WITH_ASF
CPPUNIT_ASSERT_EQUAL(classSize(1, false), sizeof(TagLib::ASF::Attribute));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::ASF::File));
CPPUNIT_ASSERT_EQUAL(classSize(1, false), sizeof(TagLib::ASF::Picture));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::ASF::Properties));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::ASF::Tag));
#endif
#ifdef TAGLIB_WITH_DSF
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::DSDIFF::DIIN::Tag));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::DSDIFF::File));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::DSDIFF::Properties));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::DSF::File));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::DSF::Properties));
#endif
#ifdef TAGLIB_WITH_VORBIS
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::FLAC::File));
CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::FLAC::MetadataBlock));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::FLAC::Picture));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::FLAC::Properties));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::FLAC::UnknownMetadataBlock));
CPPUNIT_ASSERT_EQUAL(classSize(2, true), sizeof(TagLib::Ogg::FLAC::File));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::Ogg::File));
CPPUNIT_ASSERT_EQUAL(classSize(2, true), sizeof(TagLib::Ogg::Opus::File));
@@ -235,7 +258,29 @@ public:
CPPUNIT_ASSERT_EQUAL(classSize(2, true), sizeof(TagLib::Ogg::Vorbis::File));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::Ogg::Vorbis::Properties));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::Ogg::XiphComment));
CPPUNIT_ASSERT_EQUAL(classSize(2, false), sizeof(TagLib::PropertyMap));
#endif
#ifdef TAGLIB_WITH_MOD
CPPUNIT_ASSERT_EQUAL(classSize(2, true), sizeof(TagLib::IT::File));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::IT::Properties));
CPPUNIT_ASSERT_EQUAL(classSize(2, true), sizeof(TagLib::Mod::File));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::Mod::FileBase));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::Mod::Properties));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::Mod::Tag));
CPPUNIT_ASSERT_EQUAL(classSize(2, true), sizeof(TagLib::S3M::File));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::S3M::Properties));
CPPUNIT_ASSERT_EQUAL(classSize(2, true), sizeof(TagLib::XM::File));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::XM::Properties));
CPPUNIT_ASSERT_EQUAL(classSize(1, false), sizeof(TagLib::Variant));
#endif
#ifdef TAGLIB_WITH_MP4
CPPUNIT_ASSERT_EQUAL(classSize(1, false), sizeof(TagLib::MP4::CoverArt));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::MP4::File));
CPPUNIT_ASSERT_EQUAL(classSize(1, false), sizeof(TagLib::MP4::Item));
CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::MP4::ItemFactory));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::MP4::Properties));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::MP4::Tag));
#endif
#ifdef TAGLIB_WITH_RIFF
CPPUNIT_ASSERT_EQUAL(classSize(2, true), sizeof(TagLib::RIFF::AIFF::File));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::RIFF::AIFF::Properties));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::RIFF::File));
@@ -243,18 +288,16 @@ public:
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::RIFF::Info::Tag));
CPPUNIT_ASSERT_EQUAL(classSize(2, true), sizeof(TagLib::RIFF::WAV::File));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::RIFF::WAV::Properties));
CPPUNIT_ASSERT_EQUAL(classSize(2, true), sizeof(TagLib::S3M::File));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::S3M::Properties));
CPPUNIT_ASSERT_EQUAL(classSize(1, false), sizeof(TagLib::String));
CPPUNIT_ASSERT_EQUAL(classSize(2, false), sizeof(TagLib::StringList));
CPPUNIT_ASSERT_EQUAL(classSize(0, true), sizeof(TagLib::Tag));
#endif
#ifdef TAGLIB_WITH_SHORTEN
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::Shorten::File));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::Shorten::Properties));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::Shorten::Tag));
#endif
#ifdef TAGLIB_WITH_TRUEAUDIO
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::TrueAudio::File));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::TrueAudio::Properties));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::WavPack::File));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::WavPack::Properties));
CPPUNIT_ASSERT_EQUAL(classSize(2, true), sizeof(TagLib::XM::File));
CPPUNIT_ASSERT_EQUAL(classSize(1, true), sizeof(TagLib::XM::Properties));
CPPUNIT_ASSERT_EQUAL(classSize(1, false), sizeof(TagLib::Variant));
#endif
}
private:

View File

@@ -23,9 +23,12 @@
* http://www.mozilla.org/MPL/ *
***************************************************************************/
#include <string>
#include <cstring>
#include "tstring.h"
#include "tstringlist.h"
#include "tbytevector.h"
#include "tutils.h"
#include <cppunit/extensions/HelperMacros.h>
@@ -54,6 +57,7 @@ class TestString : public CppUnit::TestFixture
CPPUNIT_TEST(testEncodeNonBMP);
CPPUNIT_TEST(testIterator);
CPPUNIT_TEST(testInvalidUTF8);
CPPUNIT_TEST(testEmpty);
CPPUNIT_TEST_SUITE_END();
public:
@@ -370,6 +374,80 @@ public:
CPPUNIT_ASSERT(String(ByteVector("\xED\xB0\x80\xED\xA0\x80"), String::UTF8).isEmpty());
}
void testEmpty()
{
const String empty;
const String notEmpty("A");
String mutEmpty;
CPPUNIT_ASSERT_EQUAL(empty, String(""));
CPPUNIT_ASSERT_EQUAL(empty, String(std::wstring()));
CPPUNIT_ASSERT_EQUAL(empty, String(static_cast<const wchar_t *>(nullptr)));
CPPUNIT_ASSERT(empty != String('\0'));
CPPUNIT_ASSERT_EQUAL(empty, String(L'\0'));
CPPUNIT_ASSERT_EQUAL(empty, String(static_cast<const char *>(nullptr)));
CPPUNIT_ASSERT_EQUAL(empty, String(ByteVector()));
CPPUNIT_ASSERT_EQUAL(empty.to8Bit(), std::string());
CPPUNIT_ASSERT_EQUAL(empty.toWString(), std::wstring());
CPPUNIT_ASSERT_EQUAL(::strlen(empty.toCString()), (size_t)0);
CPPUNIT_ASSERT_EQUAL(::wcslen(empty.toCWString()), (size_t)0);
CPPUNIT_ASSERT(empty.begin() == empty.end());
CPPUNIT_ASSERT(empty.cbegin() == empty.cend());
CPPUNIT_ASSERT(mutEmpty.begin() == mutEmpty.end());
CPPUNIT_ASSERT_EQUAL(empty.find(mutEmpty), 0);
CPPUNIT_ASSERT_EQUAL(empty.find(notEmpty), -1);
CPPUNIT_ASSERT_EQUAL(notEmpty.find(empty), 0);
CPPUNIT_ASSERT_EQUAL(empty.rfind(mutEmpty), 0);
CPPUNIT_ASSERT_EQUAL(empty.rfind(notEmpty), -1);
CPPUNIT_ASSERT_EQUAL(notEmpty.rfind(empty), 1);
CPPUNIT_ASSERT_EQUAL(empty.split(), StringList(empty));
CPPUNIT_ASSERT_EQUAL(empty.startsWith(mutEmpty), true);
CPPUNIT_ASSERT_EQUAL(empty.startsWith(notEmpty), false);
CPPUNIT_ASSERT_EQUAL(notEmpty.startsWith(empty), true);
CPPUNIT_ASSERT_EQUAL(empty.substr(0), empty);
CPPUNIT_ASSERT_EQUAL(mutEmpty.append(empty), empty);
CPPUNIT_ASSERT_EQUAL(mutEmpty.append(notEmpty), notEmpty);
mutEmpty.clear();
CPPUNIT_ASSERT_EQUAL(mutEmpty, empty);
CPPUNIT_ASSERT_EQUAL(String(notEmpty).append(empty), notEmpty);
CPPUNIT_ASSERT_EQUAL(empty.upper(), empty);
CPPUNIT_ASSERT_EQUAL(empty.size(), 0U);
CPPUNIT_ASSERT_EQUAL(empty.length(), 0U);
CPPUNIT_ASSERT_EQUAL(empty.isEmpty(), true);
CPPUNIT_ASSERT_EQUAL(empty.data(String::Latin1), ByteVector());
CPPUNIT_ASSERT_EQUAL(empty.data(String::UTF16LE), ByteVector());
bool ok;
empty.toInt(&ok);
CPPUNIT_ASSERT(!ok);
CPPUNIT_ASSERT_EQUAL(empty.stripWhiteSpace(), empty);
CPPUNIT_ASSERT_EQUAL(empty.isLatin1(), true);
CPPUNIT_ASSERT_EQUAL(empty.isAscii(), true);
CPPUNIT_ASSERT(empty == mutEmpty);
CPPUNIT_ASSERT(empty != notEmpty);
CPPUNIT_ASSERT(empty == "");
CPPUNIT_ASSERT(empty != " ");
CPPUNIT_ASSERT(empty == L"");
CPPUNIT_ASSERT(empty != L" ");
CPPUNIT_ASSERT(empty == static_cast<const char *>(nullptr));
CPPUNIT_ASSERT(!(empty != static_cast<const char *>(nullptr)));
CPPUNIT_ASSERT(empty == static_cast<const wchar_t *>(nullptr));
CPPUNIT_ASSERT(!(empty != static_cast<const wchar_t *>(nullptr)));
CPPUNIT_ASSERT_EQUAL(mutEmpty += empty, empty);
CPPUNIT_ASSERT_EQUAL(mutEmpty += notEmpty, notEmpty);
mutEmpty.clear();
CPPUNIT_ASSERT_EQUAL(mutEmpty += static_cast<const char *>(nullptr), empty);
CPPUNIT_ASSERT_EQUAL(mutEmpty += static_cast<const wchar_t *>(nullptr), empty);
CPPUNIT_ASSERT_EQUAL(mutEmpty = static_cast<const char *>(nullptr), empty);
CPPUNIT_ASSERT_EQUAL(mutEmpty = static_cast<const wchar_t *>(nullptr), empty);
String tmp;
mutEmpty.swap(tmp);
CPPUNIT_ASSERT_EQUAL(mutEmpty, empty);
CPPUNIT_ASSERT_EQUAL(empty < notEmpty, true);
CPPUNIT_ASSERT_EQUAL(empty + mutEmpty, empty);
CPPUNIT_ASSERT_EQUAL(empty + notEmpty, notEmpty);
CPPUNIT_ASSERT_EQUAL(empty + static_cast<const char *>(nullptr), empty);
}
};
CPPUNIT_TEST_SUITE_REGISTRATION(TestString);

View File

@@ -27,6 +27,7 @@
#include <unordered_map>
#include <list>
#include "taglib_config.h"
#include "tag_c.h"
#include "tbytevector.h"
#include "tstring.h"
@@ -77,7 +78,9 @@ class TestTagC : public CppUnit::TestFixture
{
CPPUNIT_TEST_SUITE(TestTagC);
CPPUNIT_TEST(testMp3);
#ifdef TAGLIB_WITH_VORBIS
CPPUNIT_TEST(testStream);
#endif
CPPUNIT_TEST_SUITE_END();
public:
@@ -165,6 +168,7 @@ public:
taglib_tag_free_strings();
}
#ifdef TAGLIB_WITH_VORBIS
void testStream()
{
// Only fetch the beginning of a FLAC file
@@ -233,6 +237,7 @@ public:
taglib_tag_free_strings();
}
#endif
};
CPPUNIT_TEST_SUITE_REGISTRATION(TestTagC);

View File

@@ -54,12 +54,14 @@ inline string copyFile(const string &filename, const string &ext)
{
char testFileName[1024];
#ifdef _WIN32
#ifdef TESTS_TMPDIR
snprintf(testFileName, sizeof(testFileName), "%s/taglib-test%s", TESTS_TMPDIR, ext.c_str());
#elif defined _WIN32
char tempDir[MAX_PATH + 1];
GetTempPathA(sizeof(tempDir), tempDir);
wsprintfA(testFileName, "%s\\taglib-test%s", tempDir, ext.c_str());
#else
snprintf(testFileName, sizeof(testFileName), "/%s/taglib-test%s", P_tmpdir, ext.c_str());
snprintf(testFileName, sizeof(testFileName), "%s/taglib-test%s", P_tmpdir, ext.c_str());
#endif
string sourceFileName = testFilePath(filename) + ext;