12 Commits
v2.0 ... v2.0.1

Author SHA1 Message Date
Urs Fleisch
ebf4c5bbb1 Version 2.0.1 2024-04-09 19:55:08 +02:00
Urs Fleisch
20cec27ac0 C bindings: Support UTF-8 for property values 2024-04-01 08:45:52 +02:00
Urs Fleisch
99bc87ccff Fix WASM build by inverting wchar_t size check
When building WASM with emscripten

cmake -DCMAKE_TOOLCHAIN_FILE=/path/to/Emscripten.cmake ...

all SIZEOF_ variables which should be defined in ConfigureChecks.cmake
are empty and the wchar_t check fails with "LESS" "2", the other
checks seem to pass since they start with NOT. Instead of explicitly
skipping the check for "if(NOT EMSCRIPTEN)" as is done in vcpkg's
disable-wchar-t-check-emscripten.patch, the check is inverted to
start with NOT, so the build still has a chance to run for compilers
which behave like emscripten.
2024-03-25 20:14:19 +01:00
Urs Fleisch
7951f572b5 Avoid offset_t conflict on Illumos
Taken from NetBSD patch-taglib_toolkit_taglib.h.
2024-03-25 20:14:19 +01:00
Urs Fleisch
59ff35772e Fix building with -DBUILD_TESTING=ON -DBUILD_BINDINGS=OFF 2024-03-25 20:14:19 +01:00
Urs Fleisch
3784628155 Provide equal operator for MP4::Item
This is needed to generate MP4::ItemMap bindings with SWIG.
2024-03-25 20:13:55 +01:00
Urs Fleisch
e60df53152 Add virtual to abstract overridden destructor
This is redundant, but required by SWIG.
2024-03-25 20:13:55 +01:00
Urs Fleisch
1ae8e18db5 Windows: Suppress yet another MSVC C4251 warning 2024-03-25 20:13:55 +01:00
Urs Fleisch
0896fb9092 Detect utf8cpp by header if cmake config is not found (#1217) 2024-02-03 06:28:40 +01:00
Jonas Kvinge
920d97606b FileStream: Fix opening long paths on Windows (#1216)
To make sure paths longer than MAX_PATH (260) can be opened, prefix local
paths with `\\?\`, and UNC paths with `\\?\UNC\`.

I've tested on Windows 10 22H2 (Build 19045.3930), even when setting
LongPathsEnabled to 1 in the registry, it still won't open files with long
paths without prefixing them.

For more information see:
https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=registry
2024-01-28 16:22:14 +01:00
Urs Fleisch
0d2c31b102 Clarify 2.0 source compatibility, remove obsolete URL (#1214) 2024-01-28 07:17:05 +01:00
Urs Fleisch
c8c4e5faec Fix 'get() != pointer()' assertion copying ByteVectorList/StringList (#1211)
This reverts dfef09f13 but keeps the assignments as a comment so these
functions do not look like they can be defaulted even though they cannot.
2024-01-27 10:56:31 +01:00
17 changed files with 299 additions and 34 deletions

View File

@@ -1,8 +1,21 @@
TagLib 2.0.1 (Apr 9, 2024)
==========================
* Fix aborting when _GLIBCXX_ASSERTIONS are enabled.
* Fall back to utf8cpp header detection in the case that its CMake
configuration is removed.
* Improve compatibility with the SWIG interface compiler.
* Build system fixes for testing without bindings, Emscripten and Illumos.
* C bindings: Fix setting UTF-8 encoded property values.
* Windows: Fix opening long paths.
TagLib 2.0 (Jan 24, 2024)
=========================
* New major version, binary incompatible, but source-compatible with the
latest 1.x release if no deprecated features are used.
* New major version, binary incompatible, but mostly source-compatible
with the latest 1.x release if no deprecated features are used.
Simple applications should build without changes, more complex
applications (e.g. extending classes of TagLib) will have to be adapted.
* Requires a C++17 compiler and uses features of C++17.
* Major code cleanup, fixed warnings issued by compilers and static analyzers.
* Made methods virtual which should have been virtual but could not be

View File

@@ -93,7 +93,7 @@ endif()
# Patch version: increase it for bug fix releases.
set(TAGLIB_SOVERSION_MAJOR 2)
set(TAGLIB_SOVERSION_MINOR 0)
set(TAGLIB_SOVERSION_PATCH 0)
set(TAGLIB_SOVERSION_PATCH 1)
include(ConfigureChecks.cmake)
@@ -149,18 +149,33 @@ if(TRACE_IN_RELEASE)
endif()
find_package(utf8cpp QUIET)
if(NOT utf8cpp_FOUND)
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/utfcpp/CMakeLists.txt)
add_subdirectory("3rdparty/utfcpp")
message(STATUS "Using utfcpp from ${utf8cpp_SOURCE_DIR}")
else()
message(FATAL_ERROR
"utfcpp not found. Either install package (probably utfcpp, utf8cpp, or libutfcpp-dev) "
"or fetch the git submodule using\n"
"git submodule update --init")
endif()
else()
if(utf8cpp_FOUND)
message(STATUS "Using utfcpp ${utf8cpp_VERSION} from ${utf8cpp_CONFIG}")
else()
find_path(utf8cpp_INCLUDE_DIR NAMES utf8.h PATH_SUFFIXES utf8cpp
DOC "utf8cpp include directory")
mark_as_advanced(utf8cpp_INCLUDE_DIR)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(utf8cpp REQUIRED_VARS utf8cpp_INCLUDE_DIR)
if(utf8cpp_FOUND)
set(utf8cpp_INCLUDE_DIRS "${utf8cpp_INCLUDE_DIR}")
if(NOT TARGET utf8::cpp)
add_library(utf8::cpp INTERFACE IMPORTED)
set_target_properties(utf8::cpp PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${utf8cpp_INCLUDE_DIR}")
endif()
message(STATUS "Using utfcpp from ${utf8cpp_INCLUDE_DIR}")
else()
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/utfcpp/CMakeLists.txt)
add_subdirectory("3rdparty/utfcpp")
message(STATUS "Using utfcpp from ${utf8cpp_SOURCE_DIR}")
else()
message(FATAL_ERROR
"utfcpp not found. Either install package (probably utfcpp, utf8cpp, or libutfcpp-dev) "
"or fetch the git submodule using\n"
"git submodule update --init")
endif()
endif()
endif()
add_subdirectory(taglib)

View File

@@ -20,7 +20,7 @@ if(NOT ${SIZEOF_LONGLONG} EQUAL 8)
endif()
check_type_size("wchar_t" SIZEOF_WCHAR_T)
if(${SIZEOF_WCHAR_T} LESS 2)
if(NOT ${SIZEOF_WCHAR_T} GREATER 1)
message(FATAL_ERROR "TagLib requires that wchar_t is sufficient to store a UTF-16 char.")
endif()

View File

@@ -7,10 +7,10 @@
https://taglib.org/
TagLib is a library for reading and editing the metadata of several
popular audio formats. Currently, it supports both ID3v1 and [ID3v2][]
popular audio formats. Currently, it supports both ID3v1 and ID3v2
for MP3 files, [Ogg Vorbis][] comments and ID3 tags
in [FLAC][], MPC, Speex, WavPack, TrueAudio, WAV, AIFF, MP4, APE,
and ASF files.
in [FLAC][], MPC, Speex, WavPack, TrueAudio, WAV, AIFF, MP4, APE, ASF,
DSF, DFF and AAC files.
TagLib is distributed under the [GNU Lesser General Public License][]
(LGPL) and [Mozilla Public License][] (MPL). Essentially that means that
@@ -18,7 +18,6 @@ it may be used in proprietary applications, but if changes are made to
TagLib they must be contributed back to the project. Please review the
licenses if you are considering using TagLib in your project.
[ID3v2]: https://id3.org/
[Ogg Vorbis]: https://xiph.org/vorbis/
[FLAC]: https://xiph.org/flac/
[GNU Lesser General Public License]: https://www.gnu.org/licenses/lgpl.html

View File

@@ -410,14 +410,14 @@ void _taglib_property_set(TagLib_File *file, const char* prop, const char* value
if(value) {
auto property = map.find(prop);
if(property == map.end()) {
map.insert(prop, StringList(value));
map.insert(prop, StringList(charArrayToString(value)));
}
else {
if(append) {
property->second.append(value);
property->second.append(charArrayToString(value));
}
else {
property->second = StringList(value);
property->second = StringList(charArrayToString(value));
}
}
}
@@ -542,14 +542,14 @@ bool _taglib_complex_property_set(
map.insert(attrKey, attr->value.value.doubleValue);
break;
case TagLib_Variant_String:
map.insert(attrKey, attr->value.value.stringValue);
map.insert(attrKey, charArrayToString(attr->value.value.stringValue));
break;
case TagLib_Variant_StringList: {
StringList strs;
if(attr->value.value.stringListValue) {
char **s = attr->value.value.stringListValue;;
while(*s) {
strs.append(*s++);
strs.append(charArrayToString(*s++));
}
}
map.insert(attrKey, strs);

View File

@@ -143,7 +143,7 @@ namespace TagLib {
/*!
* Destroys this StreamTypeResolver instance.
*/
~StreamTypeResolver() override = 0;
virtual ~StreamTypeResolver() override = 0; // virtual is needed by SWIG
StreamTypeResolver(const StreamTypeResolver &) = delete;
StreamTypeResolver &operator=(const StreamTypeResolver &) = delete;

View File

@@ -69,3 +69,13 @@ MP4::CoverArt::data() const
{
return d->data;
}
bool MP4::CoverArt::operator==(const CoverArt &other) const
{
return format() == other.format() && data() == other.data();
}
bool MP4::CoverArt::operator!=(const CoverArt &other) const
{
return !(*this == other);
}

View File

@@ -69,6 +69,17 @@ namespace TagLib {
//! The image data
ByteVector data() const;
/*!
* Returns \c true if the CoverArt and \a other are of the same format and
* contain the same data.
*/
bool operator==(const CoverArt &other) const;
/*!
* Returns \c true if the CoverArt and \a other differ in format or data.
*/
bool operator!=(const CoverArt &other) const;
private:
class CoverArtPrivate;
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE

View File

@@ -30,6 +30,7 @@ using namespace TagLib;
class MP4::Item::ItemPrivate
{
public:
Type type;
bool valid { true };
AtomDataType atomDataType { TypeUndefined };
union {
@@ -48,6 +49,7 @@ public:
MP4::Item::Item() :
d(std::make_shared<ItemPrivate>())
{
d->type = Type::Void;
d->valid = false;
}
@@ -67,36 +69,42 @@ MP4::Item::~Item() = default;
MP4::Item::Item(bool value) :
d(std::make_shared<ItemPrivate>())
{
d->type = Type::Bool;
d->m_bool = value;
}
MP4::Item::Item(int value) :
d(std::make_shared<ItemPrivate>())
{
d->type = Type::Int;
d->m_int = value;
}
MP4::Item::Item(unsigned char value) :
d(std::make_shared<ItemPrivate>())
{
d->type = Type::Byte;
d->m_byte = value;
}
MP4::Item::Item(unsigned int value) :
d(std::make_shared<ItemPrivate>())
{
d->type = Type::UInt;
d->m_uint = value;
}
MP4::Item::Item(long long value) :
d(std::make_shared<ItemPrivate>())
{
d->type = Type::LongLong;
d->m_longlong = value;
}
MP4::Item::Item(int value1, int value2) :
d(std::make_shared<ItemPrivate>())
{
d->type = Type::IntPair;
d->m_intPair.first = value1;
d->m_intPair.second = value2;
}
@@ -104,18 +112,21 @@ MP4::Item::Item(int value1, int value2) :
MP4::Item::Item(const ByteVectorList &value) :
d(std::make_shared<ItemPrivate>())
{
d->type = Type::ByteVectorList;
d->m_byteVectorList = value;
}
MP4::Item::Item(const StringList &value) :
d(std::make_shared<ItemPrivate>())
{
d->type = Type::StringList;
d->m_stringList = value;
}
MP4::Item::Item(const MP4::CoverArtList &value) :
d(std::make_shared<ItemPrivate>())
{
d->type = Type::CoverArtList;
d->m_coverArtList = value;
}
@@ -188,3 +199,47 @@ MP4::Item::isValid() const
{
return d->valid;
}
MP4::Item::Type MP4::Item::type() const
{
return d->type;
}
bool MP4::Item::operator==(const Item &other) const
{
if(isValid() && other.isValid() &&
type() == other.type() &&
atomDataType() == other.atomDataType()) {
switch(type()) {
case Type::Void:
return true;
case Type::Bool:
return toBool() == other.toBool();
case Type::Int:
return toInt() == other.toInt();
case Type::IntPair: {
const auto lhs = toIntPair();
const auto rhs = other.toIntPair();
return lhs.first == rhs.first && lhs.second == rhs.second;
}
case Type::Byte:
return toByte() == other.toByte();
case Type::UInt:
return toUInt() == other.toUInt();
case Type::LongLong:
return toLongLong() == other.toLongLong();
case Type::StringList:
return toStringList() == other.toStringList();
case Type::ByteVectorList:
return toByteVectorList() == other.toByteVectorList();
case Type::CoverArtList:
return toCoverArtList() == other.toCoverArtList();
}
}
return false;
}
bool MP4::Item::operator!=(const Item &other) const
{
return !(*this == other);
}

View File

@@ -36,6 +36,22 @@ namespace TagLib {
class TAGLIB_EXPORT Item
{
public:
/*!
* The data type stored in the item.
*/
enum class Type : unsigned char {
Void,
Bool,
Int,
IntPair,
Byte,
UInt,
LongLong,
StringList,
ByteVectorList,
CoverArtList
};
struct IntPair {
int first, second;
};
@@ -80,6 +96,19 @@ namespace TagLib {
bool isValid() const;
Type type() const;
/*!
* Returns \c true if the Item and \a other are of the same type and
* contain the same value.
*/
bool operator==(const Item &other) const;
/*!
* Returns \c true if the Item and \a other differ in type or value.
*/
bool operator!=(const Item &other) const;
private:
class ItemPrivate;
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE

View File

@@ -28,7 +28,7 @@
#define TAGLIB_MAJOR_VERSION 2
#define TAGLIB_MINOR_VERSION 0
#define TAGLIB_PATCH_VERSION 0
#define TAGLIB_PATCH_VERSION 1
#if (defined(_MSC_VER) && _MSC_VER >= 1600)
#define TAGLIB_CONSTRUCT_BITSET(x) static_cast<unsigned long long>(x)
@@ -60,7 +60,7 @@ namespace TagLib {
// In Win32, always 64bit. Otherwise, equivalent to off_t.
#ifdef _WIN32
using offset_t = long long;
#else
#elif !defined(__illumos__)
using offset_t = off_t;
#endif

View File

@@ -70,7 +70,8 @@ ByteVectorList::~ByteVectorList() = default;
ByteVectorList::ByteVectorList(const ByteVectorList &l) :
List<ByteVector>(l)
{
*d = *l.d;
// Uncomment if d is used, d.get() is nullptr and *d behavior undefined
// *d = *l.d;
}
ByteVectorList::ByteVectorList(std::initializer_list<ByteVector> init) :
@@ -84,7 +85,8 @@ ByteVectorList &ByteVectorList::operator=(const ByteVectorList &l)
return *this;
List<ByteVector>::operator=(l);
*d = *l.d;
// Uncomment if d is used, d.get() is nullptr and *d behavior undefined
// *d = *l.d;
return *this;
}

View File

@@ -56,7 +56,21 @@ namespace
#if defined (PLATFORM_WINRT)
return CreateFile2(path.wstr().c_str(), access, FILE_SHARE_READ, OPEN_EXISTING, nullptr);
#else
return CreateFileW(path.wstr().c_str(), access, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
constexpr wchar_t LongLocalPathPrefix[] = L"\\\\?\\";
constexpr wchar_t UNCPathPrefix[] = L"\\\\";
constexpr wchar_t LongUNCPathPrefix[] = L"\\\\?\\UNC\\";
std::wstring pathWStr = path.wstr();
if(pathWStr.length() > MAX_PATH &&
pathWStr.compare(0, std::size(LongLocalPathPrefix) - 1, LongLocalPathPrefix) != 0 &&
pathWStr.compare(0, std::size(LongUNCPathPrefix) - 1, LongUNCPathPrefix) != 0) {
if(pathWStr.compare(0, std::size(UNCPathPrefix) - 1, UNCPathPrefix) == 0) {
pathWStr = LongUNCPathPrefix + pathWStr.substr(2);
}
else {
pathWStr = LongLocalPathPrefix + pathWStr;
}
}
return CreateFileW(pathWStr.c_str(), access, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
#endif
}

View File

@@ -31,6 +31,7 @@
#ifdef _MSC_VER
// Explained at end of tpropertymap.cpp
TAGLIB_MSVC_SUPPRESS_WARNING_NEEDS_TO_HAVE_DLL_INTERFACE
extern template class TagLib::Map<TagLib::String, TagLib::StringList>;
#endif

View File

@@ -59,7 +59,8 @@ StringList::StringList() = default;
StringList::StringList(const StringList &l) :
List<String>(l)
{
*d = *l.d;
// Uncomment if d is used, d.get() is nullptr and *d behavior undefined
// *d = *l.d;
}
StringList::StringList(std::initializer_list<String> init) :
@@ -73,7 +74,8 @@ StringList &StringList::operator=(const StringList &l)
return *this;
List<String>::operator=(l);
*d = *l.d;
// Uncomment if d is used, d.get() is nullptr and *d behavior undefined
// *d = *l.d;
return *this;
}

View File

@@ -76,13 +76,20 @@ SET(test_runner_SRCS
test_dsdiff.cpp
test_sizes.cpp
test_versionnumber.cpp
test_tag_c.cpp
)
IF(BUILD_BINDINGS)
SET(test_runner_SRCS ${test_runner_SRCS}
test_tag_c.cpp
)
ENDIF()
INCLUDE_DIRECTORIES(${CPPUNIT_INCLUDE_DIR})
ADD_EXECUTABLE(test_runner ${test_runner_SRCS})
TARGET_LINK_LIBRARIES(test_runner tag tag_c ${CPPUNIT_LIBRARIES})
TARGET_LINK_LIBRARIES(test_runner tag ${CPPUNIT_LIBRARIES})
IF(BUILD_BINDINGS)
TARGET_LINK_LIBRARIES(test_runner tag_c)
ENDIF()
ADD_TEST(test_runner test_runner)
ADD_CUSTOM_TARGET(check COMMAND ${CMAKE_CTEST_COMMAND} -V

View File

@@ -39,6 +39,7 @@ class TestMP4Item : public CppUnit::TestFixture
{
CPPUNIT_TEST_SUITE(TestMP4Item);
CPPUNIT_TEST(testCoverArtList);
CPPUNIT_TEST(testItemOperations);
CPPUNIT_TEST_SUITE_END();
public:
@@ -58,6 +59,112 @@ public:
CPPUNIT_ASSERT_EQUAL(ByteVector("bar"), l[1].data());
}
void testItemOperations()
{
MP4::Item e;
MP4::Item i1(1);
MP4::Item i2(1);
MP4::Item i3(-1);
MP4::Item c1(static_cast<unsigned char>('A'));
MP4::Item c2(static_cast<unsigned char>('A'));
MP4::Item c3(static_cast<unsigned char>('Z'));
MP4::Item u1(2U);
MP4::Item u2(2U);
MP4::Item u3(0U);
MP4::Item l1(3LL);
MP4::Item l2(3LL);
MP4::Item l3(-7LL);
MP4::Item b1(true);
MP4::Item b2(true);
MP4::Item b3(false);
MP4::Item p1(4, 5);
MP4::Item p2(4, 5);
MP4::Item p3(-4, -5);
MP4::Item s1(StringList{"abc", "de"});
MP4::Item s2(StringList{"abc", "de"});
MP4::Item s3(StringList{"abc"});
MP4::Item v1(ByteVectorList{"f", "gh"});
MP4::Item v2(ByteVectorList{"f", "gh"});
MP4::Item v3(ByteVectorList{});
MP4::Item a1(MP4::CoverArtList{
MP4::CoverArt(MP4::CoverArt::PNG, "foo"),
MP4::CoverArt(MP4::CoverArt::JPEG, "bar")
});
MP4::Item a2(MP4::CoverArtList{
MP4::CoverArt(MP4::CoverArt::PNG, "foo"),
MP4::CoverArt(MP4::CoverArt::JPEG, "bar")
});
MP4::Item a3(MP4::CoverArtList{
MP4::CoverArt(MP4::CoverArt::JPEG, "bar")
});
CPPUNIT_ASSERT(i1 == i2);
CPPUNIT_ASSERT(i2 != i3);
CPPUNIT_ASSERT(i3 != c1);
CPPUNIT_ASSERT(c1 == c1);
CPPUNIT_ASSERT(c1 == c2);
CPPUNIT_ASSERT(c2 != c3);
CPPUNIT_ASSERT(c3 != u1);
CPPUNIT_ASSERT(u1 == u2);
CPPUNIT_ASSERT(u2 != u3);
CPPUNIT_ASSERT(u3 != l1);
CPPUNIT_ASSERT(l1 == l2);
CPPUNIT_ASSERT(l2 != l3);
CPPUNIT_ASSERT(l3 != b1);
CPPUNIT_ASSERT(b1 == b2);
CPPUNIT_ASSERT(b2 != b3);
CPPUNIT_ASSERT(b3 != p1);
CPPUNIT_ASSERT(p1 == p2);
CPPUNIT_ASSERT(p2 != p3);
CPPUNIT_ASSERT(p3 != s1);
CPPUNIT_ASSERT(s1 == s2);
CPPUNIT_ASSERT(s2 != s3);
CPPUNIT_ASSERT(s3 != v1);
CPPUNIT_ASSERT(v1 == v2);
CPPUNIT_ASSERT(v2 != v3);
CPPUNIT_ASSERT(v3 != a1);
CPPUNIT_ASSERT(a1 == a2);
CPPUNIT_ASSERT(a2 != a3);
CPPUNIT_ASSERT(a3 != e);
CPPUNIT_ASSERT(!e.isValid());
CPPUNIT_ASSERT(i1.isValid());
CPPUNIT_ASSERT_EQUAL(MP4::Item::Type::Void, e.type());
CPPUNIT_ASSERT_EQUAL(MP4::Item::Type::Int, i1.type());
CPPUNIT_ASSERT_EQUAL(MP4::Item::Type::Byte, c1.type());
CPPUNIT_ASSERT_EQUAL(MP4::Item::Type::UInt, u1.type());
CPPUNIT_ASSERT_EQUAL(MP4::Item::Type::LongLong, l1.type());
CPPUNIT_ASSERT_EQUAL(MP4::Item::Type::Bool, b1.type());
CPPUNIT_ASSERT_EQUAL(MP4::Item::Type::IntPair, p1.type());
CPPUNIT_ASSERT_EQUAL(MP4::Item::Type::StringList, s1.type());
CPPUNIT_ASSERT_EQUAL(MP4::Item::Type::ByteVectorList, v1.type());
CPPUNIT_ASSERT_EQUAL(MP4::Item::Type::CoverArtList, a1.type());
CPPUNIT_ASSERT_EQUAL(1, i1.toInt());
CPPUNIT_ASSERT_EQUAL(static_cast<unsigned char>('A'), c1.toByte());
CPPUNIT_ASSERT_EQUAL(2U, u1.toUInt());
CPPUNIT_ASSERT_EQUAL(3LL, l1.toLongLong());
CPPUNIT_ASSERT_EQUAL(true, b1.toBool());
CPPUNIT_ASSERT_EQUAL(4, p1.toIntPair().first);
CPPUNIT_ASSERT_EQUAL((StringList{"abc", "de"}), s1.toStringList());
CPPUNIT_ASSERT_EQUAL((ByteVectorList{"f", "gh"}), v1.toByteVectorList());
CPPUNIT_ASSERT_EQUAL(MP4::CoverArt::PNG, a1.toCoverArtList().front().format());
s3.swap(s1);
CPPUNIT_ASSERT_EQUAL((StringList{"abc"}), s1.toStringList());
CPPUNIT_ASSERT_EQUAL((StringList{"abc", "de"}), s3.toStringList());
CPPUNIT_ASSERT_EQUAL(MP4::AtomDataType::TypeUndefined, s1.atomDataType());
s1.setAtomDataType(MP4::AtomDataType::TypeUTF8);
CPPUNIT_ASSERT_EQUAL(MP4::AtomDataType::TypeUTF8, s1.atomDataType());
s1 = s3;
CPPUNIT_ASSERT_EQUAL((StringList{"abc", "de"}), s1.toStringList());
MP4::ItemMap m1{{"key1", i1}, {"key2", p1}};
MP4::ItemMap m2{{"key1", i2}, {"key2", p2}};
MP4::ItemMap m3{{"key1", i2}, {"key2", p3}};
CPPUNIT_ASSERT(m1 == m2);
CPPUNIT_ASSERT(m1 != m3);
}
};
CPPUNIT_TEST_SUITE_REGISTRATION(TestMP4Item);