TagLib: Replace bundled copy with upstream 2.0.2
Include a Framework build, unmodified, RelWithDbgInfo. Signed-off-by: Christopher Snowhill <kode54@gmail.com>
This commit is contained in:
parent
a873441484
commit
b0414f4399
429 changed files with 5320 additions and 57679 deletions
File diff suppressed because it is too large
Load diff
|
@ -1,76 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1500"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "8DC2EF4F0486A6940098B216"
|
||||
BuildableName = "TagLib.framework"
|
||||
BlueprintName = "TagLib Framework"
|
||||
ReferencedContainer = "container:TagLib.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "8DC2EF4F0486A6940098B216"
|
||||
BuildableName = "TagLib.framework"
|
||||
BlueprintName = "TagLib Framework"
|
||||
ReferencedContainer = "container:TagLib.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "8DC2EF4F0486A6940098B216"
|
||||
BuildableName = "TagLib.framework"
|
||||
BlueprintName = "TagLib Framework"
|
||||
ReferencedContainer = "container:TagLib.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -1,3 +0,0 @@
|
|||
/* Localized versions of Info.plist keys */
|
||||
|
||||
NSHumanReadableCopyright = "© __MyCompanyName__, 2006";
|
|
@ -1,3 +0,0 @@
|
|||
/* Localized versions of Info.plist keys */
|
||||
|
||||
NSHumanReadableCopyright = "© __MyCompanyName__, 2006";
|
|
@ -1,3 +0,0 @@
|
|||
/* Localized versions of Info.plist keys */
|
||||
|
||||
NSHumanReadableCopyright = "© __MyCompanyName__, 2006";
|
327
Frameworks/TagLib/taglib/3rdparty/utf8-cpp/checked.h
vendored
327
Frameworks/TagLib/taglib/3rdparty/utf8-cpp/checked.h
vendored
|
@ -1,327 +0,0 @@
|
|||
// Copyright 2006-2016 Nemanja Trifunovic
|
||||
|
||||
/*
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
#define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
|
||||
#include "core.h"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace utf8
|
||||
{
|
||||
// Base for the exceptions that may be thrown from the library
|
||||
class exception : public ::std::exception {
|
||||
};
|
||||
|
||||
// Exceptions that may be thrown from the library functions.
|
||||
class invalid_code_point : public exception {
|
||||
uint32_t cp;
|
||||
public:
|
||||
invalid_code_point(uint32_t codepoint) : cp(codepoint) {}
|
||||
virtual const char* what() const throw() { return "Invalid code point"; }
|
||||
uint32_t code_point() const {return cp;}
|
||||
};
|
||||
|
||||
class invalid_utf8 : public exception {
|
||||
uint8_t u8;
|
||||
public:
|
||||
invalid_utf8 (uint8_t u) : u8(u) {}
|
||||
virtual const char* what() const throw() { return "Invalid UTF-8"; }
|
||||
uint8_t utf8_octet() const {return u8;}
|
||||
};
|
||||
|
||||
class invalid_utf16 : public exception {
|
||||
uint16_t u16;
|
||||
public:
|
||||
invalid_utf16 (uint16_t u) : u16(u) {}
|
||||
virtual const char* what() const throw() { return "Invalid UTF-16"; }
|
||||
uint16_t utf16_word() const {return u16;}
|
||||
};
|
||||
|
||||
class not_enough_room : public exception {
|
||||
public:
|
||||
virtual const char* what() const throw() { return "Not enough space"; }
|
||||
};
|
||||
|
||||
/// The library API - functions intended to be called by the users
|
||||
|
||||
template <typename octet_iterator>
|
||||
octet_iterator append(uint32_t cp, octet_iterator result)
|
||||
{
|
||||
if (!utf8::internal::is_code_point_valid(cp))
|
||||
throw invalid_code_point(cp);
|
||||
|
||||
if (cp < 0x80) // one octet
|
||||
*(result++) = static_cast<uint8_t>(cp);
|
||||
else if (cp < 0x800) { // two octets
|
||||
*(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
|
||||
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||
}
|
||||
else if (cp < 0x10000) { // three octets
|
||||
*(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
|
||||
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
|
||||
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||
}
|
||||
else { // four octets
|
||||
*(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
|
||||
*(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f) | 0x80);
|
||||
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
|
||||
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename output_iterator>
|
||||
output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement)
|
||||
{
|
||||
while (start != end) {
|
||||
octet_iterator sequence_start = start;
|
||||
internal::utf_error err_code = utf8::internal::validate_next(start, end);
|
||||
switch (err_code) {
|
||||
case internal::UTF8_OK :
|
||||
for (octet_iterator it = sequence_start; it != start; ++it)
|
||||
*out++ = *it;
|
||||
break;
|
||||
case internal::NOT_ENOUGH_ROOM:
|
||||
throw not_enough_room();
|
||||
case internal::INVALID_LEAD:
|
||||
out = utf8::append (replacement, out);
|
||||
++start;
|
||||
break;
|
||||
case internal::INCOMPLETE_SEQUENCE:
|
||||
case internal::OVERLONG_SEQUENCE:
|
||||
case internal::INVALID_CODE_POINT:
|
||||
out = utf8::append (replacement, out);
|
||||
++start;
|
||||
// just one replacement mark for the sequence
|
||||
while (start != end && utf8::internal::is_trail(*start))
|
||||
++start;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename output_iterator>
|
||||
inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out)
|
||||
{
|
||||
static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd);
|
||||
return utf8::replace_invalid(start, end, out, replacement_marker);
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
uint32_t next(octet_iterator& it, octet_iterator end)
|
||||
{
|
||||
uint32_t cp = 0;
|
||||
internal::utf_error err_code = utf8::internal::validate_next(it, end, cp);
|
||||
switch (err_code) {
|
||||
case internal::UTF8_OK :
|
||||
break;
|
||||
case internal::NOT_ENOUGH_ROOM :
|
||||
throw not_enough_room();
|
||||
case internal::INVALID_LEAD :
|
||||
case internal::INCOMPLETE_SEQUENCE :
|
||||
case internal::OVERLONG_SEQUENCE :
|
||||
throw invalid_utf8(*it);
|
||||
case internal::INVALID_CODE_POINT :
|
||||
throw invalid_code_point(cp);
|
||||
}
|
||||
return cp;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
uint32_t peek_next(octet_iterator it, octet_iterator end)
|
||||
{
|
||||
return utf8::next(it, end);
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
uint32_t prior(octet_iterator& it, octet_iterator start)
|
||||
{
|
||||
// can't do much if it == start
|
||||
if (it == start)
|
||||
throw not_enough_room();
|
||||
|
||||
octet_iterator end = it;
|
||||
// Go back until we hit either a lead octet or start
|
||||
while (utf8::internal::is_trail(*(--it)))
|
||||
if (it == start)
|
||||
throw invalid_utf8(*it); // error - no lead byte in the sequence
|
||||
return utf8::peek_next(it, end);
|
||||
}
|
||||
|
||||
/// Deprecated in versions that include "prior"
|
||||
template <typename octet_iterator>
|
||||
uint32_t previous(octet_iterator& it, octet_iterator pass_start)
|
||||
{
|
||||
octet_iterator end = it;
|
||||
while (utf8::internal::is_trail(*(--it)))
|
||||
if (it == pass_start)
|
||||
throw invalid_utf8(*it); // error - no lead byte in the sequence
|
||||
octet_iterator temp = it;
|
||||
return utf8::next(temp, end);
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename distance_type>
|
||||
void advance (octet_iterator& it, distance_type n, octet_iterator end)
|
||||
{
|
||||
for (distance_type i = 0; i < n; ++i)
|
||||
utf8::next(it, end);
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
typename std::iterator_traits<octet_iterator>::difference_type
|
||||
distance (octet_iterator first, octet_iterator last)
|
||||
{
|
||||
typename std::iterator_traits<octet_iterator>::difference_type dist;
|
||||
for (dist = 0; first < last; ++dist)
|
||||
utf8::next(first, last);
|
||||
return dist;
|
||||
}
|
||||
|
||||
template <typename u16bit_iterator, typename octet_iterator>
|
||||
octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
|
||||
{
|
||||
while (start != end) {
|
||||
uint32_t cp = utf8::internal::mask16(*start++);
|
||||
// Take care of surrogate pairs first
|
||||
if (utf8::internal::is_lead_surrogate(cp)) {
|
||||
if (start != end) {
|
||||
uint32_t trail_surrogate = utf8::internal::mask16(*start++);
|
||||
if (utf8::internal::is_trail_surrogate(trail_surrogate))
|
||||
cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
|
||||
else
|
||||
throw invalid_utf16(static_cast<uint16_t>(trail_surrogate));
|
||||
}
|
||||
else
|
||||
throw invalid_utf16(static_cast<uint16_t>(cp));
|
||||
|
||||
}
|
||||
// Lone trail surrogate
|
||||
else if (utf8::internal::is_trail_surrogate(cp))
|
||||
throw invalid_utf16(static_cast<uint16_t>(cp));
|
||||
|
||||
result = utf8::append(cp, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename u16bit_iterator, typename octet_iterator>
|
||||
u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
|
||||
{
|
||||
while (start < end) {
|
||||
uint32_t cp = utf8::next(start, end);
|
||||
if (cp > 0xffff) { //make a surrogate pair
|
||||
*result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
|
||||
*result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
|
||||
}
|
||||
else
|
||||
*result++ = static_cast<uint16_t>(cp);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename u32bit_iterator>
|
||||
octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
|
||||
{
|
||||
while (start != end)
|
||||
result = utf8::append(*(start++), result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator, typename u32bit_iterator>
|
||||
u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
|
||||
{
|
||||
while (start < end)
|
||||
(*result++) = utf8::next(start, end);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// The iterator class
|
||||
template <typename octet_iterator>
|
||||
class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> {
|
||||
octet_iterator it;
|
||||
octet_iterator range_start;
|
||||
octet_iterator range_end;
|
||||
public:
|
||||
iterator () {}
|
||||
explicit iterator (const octet_iterator& octet_it,
|
||||
const octet_iterator& rangestart,
|
||||
const octet_iterator& rangeend) :
|
||||
it(octet_it), range_start(rangestart), range_end(rangeend)
|
||||
{
|
||||
if (it < range_start || it > range_end)
|
||||
throw std::out_of_range("Invalid utf-8 iterator position");
|
||||
}
|
||||
// the default "big three" are OK
|
||||
octet_iterator base () const { return it; }
|
||||
uint32_t operator * () const
|
||||
{
|
||||
octet_iterator temp = it;
|
||||
return utf8::next(temp, range_end);
|
||||
}
|
||||
bool operator == (const iterator& rhs) const
|
||||
{
|
||||
if (range_start != rhs.range_start || range_end != rhs.range_end)
|
||||
throw std::logic_error("Comparing utf-8 iterators defined with different ranges");
|
||||
return (it == rhs.it);
|
||||
}
|
||||
bool operator != (const iterator& rhs) const
|
||||
{
|
||||
return !(operator == (rhs));
|
||||
}
|
||||
iterator& operator ++ ()
|
||||
{
|
||||
utf8::next(it, range_end);
|
||||
return *this;
|
||||
}
|
||||
iterator operator ++ (int)
|
||||
{
|
||||
iterator temp = *this;
|
||||
utf8::next(it, range_end);
|
||||
return temp;
|
||||
}
|
||||
iterator& operator -- ()
|
||||
{
|
||||
utf8::prior(it, range_start);
|
||||
return *this;
|
||||
}
|
||||
iterator operator -- (int)
|
||||
{
|
||||
iterator temp = *this;
|
||||
utf8::prior(it, range_start);
|
||||
return temp;
|
||||
}
|
||||
}; // class iterator
|
||||
|
||||
} // namespace utf8
|
||||
|
||||
#endif //header guard
|
||||
|
||||
|
332
Frameworks/TagLib/taglib/3rdparty/utf8-cpp/core.h
vendored
332
Frameworks/TagLib/taglib/3rdparty/utf8-cpp/core.h
vendored
|
@ -1,332 +0,0 @@
|
|||
// Copyright 2006 Nemanja Trifunovic
|
||||
|
||||
/*
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
#define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
|
||||
|
||||
#include <iterator>
|
||||
|
||||
namespace utf8
|
||||
{
|
||||
// The typedefs for 8-bit, 16-bit and 32-bit unsigned integers
|
||||
// You may need to change them to match your system.
|
||||
// These typedefs have the same names as ones from cstdint, or boost/cstdint
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
|
||||
// Helper code - not intended to be directly called by the library users. May be changed at any time
|
||||
namespace internal
|
||||
{
|
||||
// Unicode constants
|
||||
// Leading (high) surrogates: 0xd800 - 0xdbff
|
||||
// Trailing (low) surrogates: 0xdc00 - 0xdfff
|
||||
const uint16_t LEAD_SURROGATE_MIN = 0xd800u;
|
||||
const uint16_t LEAD_SURROGATE_MAX = 0xdbffu;
|
||||
const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u;
|
||||
const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu;
|
||||
const uint16_t LEAD_OFFSET = LEAD_SURROGATE_MIN - (0x10000 >> 10);
|
||||
const uint32_t SURROGATE_OFFSET = 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN;
|
||||
|
||||
// Maximum valid value for a Unicode code point
|
||||
const uint32_t CODE_POINT_MAX = 0x0010ffffu;
|
||||
|
||||
template<typename octet_type>
|
||||
inline uint8_t mask8(octet_type oc)
|
||||
{
|
||||
return static_cast<uint8_t>(0xff & oc);
|
||||
}
|
||||
template<typename u16_type>
|
||||
inline uint16_t mask16(u16_type oc)
|
||||
{
|
||||
return static_cast<uint16_t>(0xffff & oc);
|
||||
}
|
||||
template<typename octet_type>
|
||||
inline bool is_trail(octet_type oc)
|
||||
{
|
||||
return ((utf8::internal::mask8(oc) >> 6) == 0x2);
|
||||
}
|
||||
|
||||
template <typename u16>
|
||||
inline bool is_lead_surrogate(u16 cp)
|
||||
{
|
||||
return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX);
|
||||
}
|
||||
|
||||
template <typename u16>
|
||||
inline bool is_trail_surrogate(u16 cp)
|
||||
{
|
||||
return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
|
||||
}
|
||||
|
||||
template <typename u16>
|
||||
inline bool is_surrogate(u16 cp)
|
||||
{
|
||||
return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
|
||||
}
|
||||
|
||||
template <typename u32>
|
||||
inline bool is_code_point_valid(u32 cp)
|
||||
{
|
||||
return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp));
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
inline typename std::iterator_traits<octet_iterator>::difference_type
|
||||
sequence_length(octet_iterator lead_it)
|
||||
{
|
||||
uint8_t lead = utf8::internal::mask8(*lead_it);
|
||||
if (lead < 0x80)
|
||||
return 1;
|
||||
else if ((lead >> 5) == 0x6)
|
||||
return 2;
|
||||
else if ((lead >> 4) == 0xe)
|
||||
return 3;
|
||||
else if ((lead >> 3) == 0x1e)
|
||||
return 4;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename octet_difference_type>
|
||||
inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length)
|
||||
{
|
||||
if (cp < 0x80) {
|
||||
if (length != 1)
|
||||
return true;
|
||||
}
|
||||
else if (cp < 0x800) {
|
||||
if (length != 2)
|
||||
return true;
|
||||
}
|
||||
else if (cp < 0x10000) {
|
||||
if (length != 3)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT};
|
||||
|
||||
/// Helper for get_sequence_x
|
||||
template <typename octet_iterator>
|
||||
utf_error increase_safely(octet_iterator& it, octet_iterator end)
|
||||
{
|
||||
if (++it == end)
|
||||
return NOT_ENOUGH_ROOM;
|
||||
|
||||
if (!utf8::internal::is_trail(*it))
|
||||
return INCOMPLETE_SEQUENCE;
|
||||
|
||||
return UTF8_OK;
|
||||
}
|
||||
|
||||
#define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;}
|
||||
|
||||
/// get_sequence_x functions decode utf-8 sequences of the length x
|
||||
template <typename octet_iterator>
|
||||
utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t& code_point)
|
||||
{
|
||||
if (it == end)
|
||||
return NOT_ENOUGH_ROOM;
|
||||
|
||||
code_point = utf8::internal::mask8(*it);
|
||||
|
||||
return UTF8_OK;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t& code_point)
|
||||
{
|
||||
if (it == end)
|
||||
return NOT_ENOUGH_ROOM;
|
||||
|
||||
code_point = utf8::internal::mask8(*it);
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f);
|
||||
|
||||
return UTF8_OK;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t& code_point)
|
||||
{
|
||||
if (it == end)
|
||||
return NOT_ENOUGH_ROOM;
|
||||
|
||||
code_point = utf8::internal::mask8(*it);
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point += (*it) & 0x3f;
|
||||
|
||||
return UTF8_OK;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t& code_point)
|
||||
{
|
||||
if (it == end)
|
||||
return NOT_ENOUGH_ROOM;
|
||||
|
||||
code_point = utf8::internal::mask8(*it);
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point += (utf8::internal::mask8(*it) << 6) & 0xfff;
|
||||
|
||||
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
|
||||
|
||||
code_point += (*it) & 0x3f;
|
||||
|
||||
return UTF8_OK;
|
||||
}
|
||||
|
||||
#undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR
|
||||
|
||||
template <typename octet_iterator>
|
||||
utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t& code_point)
|
||||
{
|
||||
if (it == end)
|
||||
return NOT_ENOUGH_ROOM;
|
||||
|
||||
// Save the original value of it so we can go back in case of failure
|
||||
// Of course, it does not make much sense with i.e. stream iterators
|
||||
octet_iterator original_it = it;
|
||||
|
||||
uint32_t cp = 0;
|
||||
// Determine the sequence length based on the lead octet
|
||||
typedef typename std::iterator_traits<octet_iterator>::difference_type octet_difference_type;
|
||||
const octet_difference_type length = utf8::internal::sequence_length(it);
|
||||
|
||||
// Get trail octets and calculate the code point
|
||||
utf_error err = UTF8_OK;
|
||||
switch (length) {
|
||||
case 0:
|
||||
return INVALID_LEAD;
|
||||
case 1:
|
||||
err = utf8::internal::get_sequence_1(it, end, cp);
|
||||
break;
|
||||
case 2:
|
||||
err = utf8::internal::get_sequence_2(it, end, cp);
|
||||
break;
|
||||
case 3:
|
||||
err = utf8::internal::get_sequence_3(it, end, cp);
|
||||
break;
|
||||
case 4:
|
||||
err = utf8::internal::get_sequence_4(it, end, cp);
|
||||
break;
|
||||
}
|
||||
|
||||
if (err == UTF8_OK) {
|
||||
// Decoding succeeded. Now, security checks...
|
||||
if (utf8::internal::is_code_point_valid(cp)) {
|
||||
if (!utf8::internal::is_overlong_sequence(cp, length)){
|
||||
// Passed! Return here.
|
||||
code_point = cp;
|
||||
++it;
|
||||
return UTF8_OK;
|
||||
}
|
||||
else
|
||||
err = OVERLONG_SEQUENCE;
|
||||
}
|
||||
else
|
||||
err = INVALID_CODE_POINT;
|
||||
}
|
||||
|
||||
// Failure branch - restore the original value of the iterator
|
||||
it = original_it;
|
||||
return err;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
inline utf_error validate_next(octet_iterator& it, octet_iterator end) {
|
||||
uint32_t ignored;
|
||||
return utf8::internal::validate_next(it, end, ignored);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/// The library API - functions intended to be called by the users
|
||||
|
||||
// Byte order mark
|
||||
const uint8_t bom[] = {0xef, 0xbb, 0xbf};
|
||||
|
||||
template <typename octet_iterator>
|
||||
octet_iterator find_invalid(octet_iterator start, octet_iterator end)
|
||||
{
|
||||
octet_iterator result = start;
|
||||
while (result != end) {
|
||||
utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end);
|
||||
if (err_code != internal::UTF8_OK)
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
inline bool is_valid(octet_iterator start, octet_iterator end)
|
||||
{
|
||||
return (utf8::find_invalid(start, end) == end);
|
||||
}
|
||||
|
||||
template <typename octet_iterator>
|
||||
inline bool starts_with_bom (octet_iterator it, octet_iterator end)
|
||||
{
|
||||
return (
|
||||
((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) &&
|
||||
((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) &&
|
||||
((it != end) && (utf8::internal::mask8(*it)) == bom[2])
|
||||
);
|
||||
}
|
||||
|
||||
//Deprecated in release 2.3
|
||||
template <typename octet_iterator>
|
||||
inline bool is_bom (octet_iterator it)
|
||||
{
|
||||
return (
|
||||
(utf8::internal::mask8(*it++)) == bom[0] &&
|
||||
(utf8::internal::mask8(*it++)) == bom[1] &&
|
||||
(utf8::internal::mask8(*it)) == bom[2]
|
||||
);
|
||||
}
|
||||
} // namespace utf8
|
||||
|
||||
#endif // header guard
|
||||
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
Scott Wheeler <wheeler@kde.org>
|
||||
Author, maintainer
|
||||
Lukas Lalinsky <lalinsky@gmail.com>
|
||||
Implementation of multiple new file formats, many bug fixes, maintainer
|
||||
Tsuda Kageyu <tsuda.kageyu@gmail.com>
|
||||
A lot of bug fixes and performance improvements, maintainer.
|
||||
Stephen F. Booth <me@sbooth.org>
|
||||
DSF metadata implementation, bug fixes, maintainer.
|
||||
Ismael Orenstein <orenstein@kde.org>
|
||||
Xing header implementation
|
||||
Allan Sandfeld Jensen <kde@carewolf.org>
|
||||
FLAC metadata implementation
|
||||
Teemu Tervo <teemu.tervo@gmx.net>
|
||||
Numerous bug reports and fixes
|
||||
Mathias Panzenböck <grosser.meister.morti@gmx.net>
|
||||
Mod, S3M, IT and XM metadata implementations
|
||||
Damien Plisson <damien78@audirvana.com>
|
||||
DSDIFF metadata implementation
|
||||
|
||||
Please send all patches and questions to taglib-devel@kde.org rather than to
|
||||
individual developers!
|
|
@ -1,168 +0,0 @@
|
|||
cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR)
|
||||
|
||||
project(taglib)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
|
||||
|
||||
if(DEFINED ENABLE_STATIC)
|
||||
message(FATAL_ERROR "This option is no longer available, use BUILD_SHARED_LIBS instead")
|
||||
endif()
|
||||
|
||||
option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
|
||||
if(APPLE)
|
||||
option(BUILD_FRAMEWORK "Build an OS X framework" OFF)
|
||||
if(BUILD_FRAMEWORK)
|
||||
set(BUILD_SHARED_LIBS ON)
|
||||
#set(CMAKE_MACOSX_RPATH 1)
|
||||
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)
|
||||
if(ENABLE_CCACHE)
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
if(CCACHE_FOUND)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(VISIBILITY_HIDDEN "Build with -fvisibility=hidden" OFF)
|
||||
option(BUILD_TESTS "Build the test suite" OFF)
|
||||
option(BUILD_EXAMPLES "Build the examples" OFF)
|
||||
option(BUILD_BINDINGS "Build the bindings" ON)
|
||||
|
||||
option(NO_ITUNES_HACKS "Disable workarounds for iTunes bugs" OFF)
|
||||
|
||||
option(PLATFORM_WINRT "Enable WinRT support" OFF)
|
||||
if(PLATFORM_WINRT)
|
||||
add_definitions(-DPLATFORM_WINRT)
|
||||
endif()
|
||||
|
||||
add_definitions(-DHAVE_CONFIG_H)
|
||||
set(TESTS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/tests/")
|
||||
|
||||
## the following are directories where stuff will be installed to
|
||||
set(LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)")
|
||||
set(EXEC_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}" CACHE PATH "Base directory for executables and libraries")
|
||||
set(BIN_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/bin" CACHE PATH "The subdirectory to the binaries prefix (default prefix/bin)")
|
||||
set(LIB_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is /lib${LIB_SUFFIX})")
|
||||
set(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "The subdirectory to the header prefix")
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
||||
endif()
|
||||
|
||||
if(MSVC AND ENABLE_STATIC_RUNTIME)
|
||||
foreach(flag_var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
||||
string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
|
||||
endforeach(flag_var)
|
||||
endif()
|
||||
|
||||
# Read version information from file taglib/toolkit/taglib.h into variables
|
||||
# TAGLIB_LIB_MAJOR_VERSION, TAGLIB_LIB_MINOR_VERSION, TAGLIB_LIB_PATCH_VERSION.
|
||||
foreach(version_part MAJOR MINOR PATCH)
|
||||
set(version_var_name "TAGLIB_${version_part}_VERSION")
|
||||
file(STRINGS taglib/toolkit/taglib.h version_line
|
||||
REGEX "^#define +${version_var_name}")
|
||||
if(NOT version_line)
|
||||
message(FATAL_ERROR "${version_var_name} not found in taglib.h")
|
||||
endif()
|
||||
string(REGEX MATCH "${version_var_name} +([^ ]+)" result ${version_line})
|
||||
set(TAGLIB_LIB_${version_part}_VERSION ${CMAKE_MATCH_1})
|
||||
endforeach(version_part)
|
||||
|
||||
# Only used to force cmake rerun when taglib.h changes.
|
||||
configure_file(taglib/toolkit/taglib.h ${CMAKE_CURRENT_BINARY_DIR}/taglib.h.stamp)
|
||||
|
||||
if("${TAGLIB_LIB_PATCH_VERSION}" EQUAL "0")
|
||||
set(TAGLIB_LIB_VERSION_STRING "${TAGLIB_LIB_MAJOR_VERSION}.${TAGLIB_LIB_MINOR_VERSION}")
|
||||
else()
|
||||
set(TAGLIB_LIB_VERSION_STRING "${TAGLIB_LIB_MAJOR_VERSION}.${TAGLIB_LIB_MINOR_VERSION}.${TAGLIB_LIB_PATCH_VERSION}")
|
||||
endif()
|
||||
|
||||
# 1. If the library source code has changed at all since the last update, then increment revision.
|
||||
# 2. If any interfaces have been added, removed, or changed since the last update, increment current, and set revision to 0.
|
||||
# 3. If any interfaces have been added since the last public release, then increment age.
|
||||
# 4. If any interfaces have been removed since the last public release, then set age to 0.
|
||||
set(TAGLIB_SOVERSION_CURRENT 19)
|
||||
set(TAGLIB_SOVERSION_REVISION 0)
|
||||
set(TAGLIB_SOVERSION_AGE 18)
|
||||
|
||||
math(EXPR TAGLIB_SOVERSION_MAJOR "${TAGLIB_SOVERSION_CURRENT} - ${TAGLIB_SOVERSION_AGE}")
|
||||
math(EXPR TAGLIB_SOVERSION_MINOR "${TAGLIB_SOVERSION_AGE}")
|
||||
math(EXPR TAGLIB_SOVERSION_PATCH "${TAGLIB_SOVERSION_REVISION}")
|
||||
|
||||
include(ConfigureChecks.cmake)
|
||||
|
||||
if(${ZLIB_FOUND})
|
||||
set(ZLIB_LIBRARIES_FLAGS -lz)
|
||||
endif()
|
||||
|
||||
if(NOT WIN32)
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/taglib-config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/taglib-config" @ONLY)
|
||||
install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/taglib-config" DESTINATION "${BIN_INSTALL_DIR}")
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/taglib-config.cmd.cmake" "${CMAKE_CURRENT_BINARY_DIR}/taglib-config.cmd")
|
||||
install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/taglib-config.cmd" DESTINATION "${BIN_INSTALL_DIR}")
|
||||
endif()
|
||||
|
||||
if(NOT BUILD_FRAMEWORK)
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/taglib.pc.cmake" "${CMAKE_CURRENT_BINARY_DIR}/taglib.pc" @ONLY)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/taglib.pc" DESTINATION "${LIB_INSTALL_DIR}/pkgconfig")
|
||||
endif()
|
||||
|
||||
if(NOT HAVE_ZLIB AND ZLIB_SOURCE)
|
||||
set(HAVE_ZLIB 1)
|
||||
set(HAVE_ZLIB_SOURCE 1)
|
||||
endif()
|
||||
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
configure_file(config.h.cmake "${CMAKE_CURRENT_BINARY_DIR}/config.h")
|
||||
|
||||
if(WITH_ASF)
|
||||
set(TAGLIB_WITH_ASF TRUE)
|
||||
endif()
|
||||
if(WITH_MP4)
|
||||
set(TAGLIB_WITH_MP4 TRUE)
|
||||
endif()
|
||||
|
||||
option(TRACE_IN_RELEASE "Output debug messages even in release mode" OFF)
|
||||
if(TRACE_IN_RELEASE)
|
||||
set(TRACE_IN_RELEASE TRUE)
|
||||
endif()
|
||||
|
||||
configure_file(taglib/taglib_config.h.cmake "${CMAKE_CURRENT_BINARY_DIR}/taglib_config.h")
|
||||
|
||||
add_subdirectory(taglib)
|
||||
|
||||
if(BUILD_BINDINGS)
|
||||
add_subdirectory(bindings)
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTS AND NOT BUILD_SHARED_LIBS)
|
||||
enable_testing()
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
if(BUILD_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
endif()
|
||||
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.cmake" "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile")
|
||||
file(COPY doc/taglib.png DESTINATION doc)
|
||||
add_custom_target(docs doxygen)
|
||||
|
||||
# uninstall target
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY)
|
||||
|
||||
if(NOT TARGET uninstall)
|
||||
add_custom_target(uninstall COMMAND "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
|
||||
endif()
|
|
@ -1,502 +0,0 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
|
@ -1,470 +0,0 @@
|
|||
MOZILLA PUBLIC LICENSE
|
||||
Version 1.1
|
||||
|
||||
---------------
|
||||
|
||||
1. Definitions.
|
||||
|
||||
1.0.1. "Commercial Use" means distribution or otherwise making the
|
||||
Covered Code available to a third party.
|
||||
|
||||
1.1. "Contributor" means each entity that creates or contributes to
|
||||
the creation of Modifications.
|
||||
|
||||
1.2. "Contributor Version" means the combination of the Original
|
||||
Code, prior Modifications used by a Contributor, and the Modifications
|
||||
made by that particular Contributor.
|
||||
|
||||
1.3. "Covered Code" means the Original Code or Modifications or the
|
||||
combination of the Original Code and Modifications, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.4. "Electronic Distribution Mechanism" means a mechanism generally
|
||||
accepted in the software development community for the electronic
|
||||
transfer of data.
|
||||
|
||||
1.5. "Executable" means Covered Code in any form other than Source
|
||||
Code.
|
||||
|
||||
1.6. "Initial Developer" means the individual or entity identified
|
||||
as the Initial Developer in the Source Code notice required by Exhibit
|
||||
A.
|
||||
|
||||
1.7. "Larger Work" means a work which combines Covered Code or
|
||||
portions thereof with code not governed by the terms of this License.
|
||||
|
||||
1.8. "License" means this document.
|
||||
|
||||
1.8.1. "Licensable" means having the right to grant, to the maximum
|
||||
extent possible, whether at the time of the initial grant or
|
||||
subsequently acquired, any and all of the rights conveyed herein.
|
||||
|
||||
1.9. "Modifications" means any addition to or deletion from the
|
||||
substance or structure of either the Original Code or any previous
|
||||
Modifications. When Covered Code is released as a series of files, a
|
||||
Modification is:
|
||||
A. Any addition to or deletion from the contents of a file
|
||||
containing Original Code or previous Modifications.
|
||||
|
||||
B. Any new file that contains any part of the Original Code or
|
||||
previous Modifications.
|
||||
|
||||
1.10. "Original Code" means Source Code of computer software code
|
||||
which is described in the Source Code notice required by Exhibit A as
|
||||
Original Code, and which, at the time of its release under this
|
||||
License is not already Covered Code governed by this License.
|
||||
|
||||
1.10.1. "Patent Claims" means any patent claim(s), now owned or
|
||||
hereafter acquired, including without limitation, method, process,
|
||||
and apparatus claims, in any patent Licensable by grantor.
|
||||
|
||||
1.11. "Source Code" means the preferred form of the Covered Code for
|
||||
making modifications to it, including all modules it contains, plus
|
||||
any associated interface definition files, scripts used to control
|
||||
compilation and installation of an Executable, or source code
|
||||
differential comparisons against either the Original Code or another
|
||||
well known, available Covered Code of the Contributor's choice. The
|
||||
Source Code can be in a compressed or archival form, provided the
|
||||
appropriate decompression or de-archiving software is widely available
|
||||
for no charge.
|
||||
|
||||
1.12. "You" (or "Your") means an individual or a legal entity
|
||||
exercising rights under, and complying with all of the terms of, this
|
||||
License or a future version of this License issued under Section 6.1.
|
||||
For legal entities, "You" includes any entity which controls, is
|
||||
controlled by, or is under common control with You. For purposes of
|
||||
this definition, "control" means (a) the power, direct or indirect,
|
||||
to cause the direction or management of such entity, whether by
|
||||
contract or otherwise, or (b) ownership of more than fifty percent
|
||||
(50%) of the outstanding shares or beneficial ownership of such
|
||||
entity.
|
||||
|
||||
2. Source Code License.
|
||||
|
||||
2.1. The Initial Developer Grant.
|
||||
The Initial Developer hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license, subject to third party intellectual property
|
||||
claims:
|
||||
(a) under intellectual property rights (other than patent or
|
||||
trademark) Licensable by Initial Developer to use, reproduce,
|
||||
modify, display, perform, sublicense and distribute the Original
|
||||
Code (or portions thereof) with or without Modifications, and/or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patents Claims infringed by the making, using or
|
||||
selling of Original Code, to make, have made, use, practice,
|
||||
sell, and offer for sale, and/or otherwise dispose of the
|
||||
Original Code (or portions thereof).
|
||||
|
||||
(c) the licenses granted in this Section 2.1(a) and (b) are
|
||||
effective on the date Initial Developer first distributes
|
||||
Original Code under the terms of this License.
|
||||
|
||||
(d) Notwithstanding Section 2.1(b) above, no patent license is
|
||||
granted: 1) for code that You delete from the Original Code; 2)
|
||||
separate from the Original Code; or 3) for infringements caused
|
||||
by: i) the modification of the Original Code or ii) the
|
||||
combination of the Original Code with other software or devices.
|
||||
|
||||
2.2. Contributor Grant.
|
||||
Subject to third party intellectual property claims, each Contributor
|
||||
hereby grants You a world-wide, royalty-free, non-exclusive license
|
||||
|
||||
(a) under intellectual property rights (other than patent or
|
||||
trademark) Licensable by Contributor, to use, reproduce, modify,
|
||||
display, perform, sublicense and distribute the Modifications
|
||||
created by such Contributor (or portions thereof) either on an
|
||||
unmodified basis, with other Modifications, as Covered Code
|
||||
and/or as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims infringed by the making, using, or
|
||||
selling of Modifications made by that Contributor either alone
|
||||
and/or in combination with its Contributor Version (or portions
|
||||
of such combination), to make, use, sell, offer for sale, have
|
||||
made, and/or otherwise dispose of: 1) Modifications made by that
|
||||
Contributor (or portions thereof); and 2) the combination of
|
||||
Modifications made by that Contributor with its Contributor
|
||||
Version (or portions of such combination).
|
||||
|
||||
(c) the licenses granted in Sections 2.2(a) and 2.2(b) are
|
||||
effective on the date Contributor first makes Commercial Use of
|
||||
the Covered Code.
|
||||
|
||||
(d) Notwithstanding Section 2.2(b) above, no patent license is
|
||||
granted: 1) for any code that Contributor has deleted from the
|
||||
Contributor Version; 2) separate from the Contributor Version;
|
||||
3) for infringements caused by: i) third party modifications of
|
||||
Contributor Version or ii) the combination of Modifications made
|
||||
by that Contributor with other software (except as part of the
|
||||
Contributor Version) or other devices; or 4) under Patent Claims
|
||||
infringed by Covered Code in the absence of Modifications made by
|
||||
that Contributor.
|
||||
|
||||
3. Distribution Obligations.
|
||||
|
||||
3.1. Application of License.
|
||||
The Modifications which You create or to which You contribute are
|
||||
governed by the terms of this License, including without limitation
|
||||
Section 2.2. The Source Code version of Covered Code may be
|
||||
distributed only under the terms of this License or a future version
|
||||
of this License released under Section 6.1, and You must include a
|
||||
copy of this License with every copy of the Source Code You
|
||||
distribute. You may not offer or impose any terms on any Source Code
|
||||
version that alters or restricts the applicable version of this
|
||||
License or the recipients' rights hereunder. However, You may include
|
||||
an additional document offering the additional rights described in
|
||||
Section 3.5.
|
||||
|
||||
3.2. Availability of Source Code.
|
||||
Any Modification which You create or to which You contribute must be
|
||||
made available in Source Code form under the terms of this License
|
||||
either on the same media as an Executable version or via an accepted
|
||||
Electronic Distribution Mechanism to anyone to whom you made an
|
||||
Executable version available; and if made available via Electronic
|
||||
Distribution Mechanism, must remain available for at least twelve (12)
|
||||
months after the date it initially became available, or at least six
|
||||
(6) months after a subsequent version of that particular Modification
|
||||
has been made available to such recipients. You are responsible for
|
||||
ensuring that the Source Code version remains available even if the
|
||||
Electronic Distribution Mechanism is maintained by a third party.
|
||||
|
||||
3.3. Description of Modifications.
|
||||
You must cause all Covered Code to which You contribute to contain a
|
||||
file documenting the changes You made to create that Covered Code and
|
||||
the date of any change. You must include a prominent statement that
|
||||
the Modification is derived, directly or indirectly, from Original
|
||||
Code provided by the Initial Developer and including the name of the
|
||||
Initial Developer in (a) the Source Code, and (b) in any notice in an
|
||||
Executable version or related documentation in which You describe the
|
||||
origin or ownership of the Covered Code.
|
||||
|
||||
3.4. Intellectual Property Matters
|
||||
(a) Third Party Claims.
|
||||
If Contributor has knowledge that a license under a third party's
|
||||
intellectual property rights is required to exercise the rights
|
||||
granted by such Contributor under Sections 2.1 or 2.2,
|
||||
Contributor must include a text file with the Source Code
|
||||
distribution titled "LEGAL" which describes the claim and the
|
||||
party making the claim in sufficient detail that a recipient will
|
||||
know whom to contact. If Contributor obtains such knowledge after
|
||||
the Modification is made available as described in Section 3.2,
|
||||
Contributor shall promptly modify the LEGAL file in all copies
|
||||
Contributor makes available thereafter and shall take other steps
|
||||
(such as notifying appropriate mailing lists or newsgroups)
|
||||
reasonably calculated to inform those who received the Covered
|
||||
Code that new knowledge has been obtained.
|
||||
|
||||
(b) Contributor APIs.
|
||||
If Contributor's Modifications include an application programming
|
||||
interface and Contributor has knowledge of patent licenses which
|
||||
are reasonably necessary to implement that API, Contributor must
|
||||
also include this information in the LEGAL file.
|
||||
|
||||
(c) Representations.
|
||||
Contributor represents that, except as disclosed pursuant to
|
||||
Section 3.4(a) above, Contributor believes that Contributor's
|
||||
Modifications are Contributor's original creation(s) and/or
|
||||
Contributor has sufficient rights to grant the rights conveyed by
|
||||
this License.
|
||||
|
||||
3.5. Required Notices.
|
||||
You must duplicate the notice in Exhibit A in each file of the Source
|
||||
Code. If it is not possible to put such notice in a particular Source
|
||||
Code file due to its structure, then You must include such notice in a
|
||||
location (such as a relevant directory) where a user would be likely
|
||||
to look for such a notice. If You created one or more Modification(s)
|
||||
You may add your name as a Contributor to the notice described in
|
||||
Exhibit A. You must also duplicate this License in any documentation
|
||||
for the Source Code where You describe recipients' rights or ownership
|
||||
rights relating to Covered Code. You may choose to offer, and to
|
||||
charge a fee for, warranty, support, indemnity or liability
|
||||
obligations to one or more recipients of Covered Code. However, You
|
||||
may do so only on Your own behalf, and not on behalf of the Initial
|
||||
Developer or any Contributor. You must make it absolutely clear than
|
||||
any such warranty, support, indemnity or liability obligation is
|
||||
offered by You alone, and You hereby agree to indemnify the Initial
|
||||
Developer and every Contributor for any liability incurred by the
|
||||
Initial Developer or such Contributor as a result of warranty,
|
||||
support, indemnity or liability terms You offer.
|
||||
|
||||
3.6. Distribution of Executable Versions.
|
||||
You may distribute Covered Code in Executable form only if the
|
||||
requirements of Section 3.1-3.5 have been met for that Covered Code,
|
||||
and if You include a notice stating that the Source Code version of
|
||||
the Covered Code is available under the terms of this License,
|
||||
including a description of how and where You have fulfilled the
|
||||
obligations of Section 3.2. The notice must be conspicuously included
|
||||
in any notice in an Executable version, related documentation or
|
||||
collateral in which You describe recipients' rights relating to the
|
||||
Covered Code. You may distribute the Executable version of Covered
|
||||
Code or ownership rights under a license of Your choice, which may
|
||||
contain terms different from this License, provided that You are in
|
||||
compliance with the terms of this License and that the license for the
|
||||
Executable version does not attempt to limit or alter the recipient's
|
||||
rights in the Source Code version from the rights set forth in this
|
||||
License. If You distribute the Executable version under a different
|
||||
license You must make it absolutely clear that any terms which differ
|
||||
from this License are offered by You alone, not by the Initial
|
||||
Developer or any Contributor. You hereby agree to indemnify the
|
||||
Initial Developer and every Contributor for any liability incurred by
|
||||
the Initial Developer or such Contributor as a result of any such
|
||||
terms You offer.
|
||||
|
||||
3.7. Larger Works.
|
||||
You may create a Larger Work by combining Covered Code with other code
|
||||
not governed by the terms of this License and distribute the Larger
|
||||
Work as a single product. In such a case, You must make sure the
|
||||
requirements of this License are fulfilled for the Covered Code.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation.
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Code due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description
|
||||
must be included in the LEGAL file described in Section 3.4 and must
|
||||
be included with all distributions of the Source Code. Except to the
|
||||
extent prohibited by statute or regulation, such description must be
|
||||
sufficiently detailed for a recipient of ordinary skill to be able to
|
||||
understand it.
|
||||
|
||||
5. Application of this License.
|
||||
|
||||
This License applies to code to which the Initial Developer has
|
||||
attached the notice in Exhibit A and to related Covered Code.
|
||||
|
||||
6. Versions of the License.
|
||||
|
||||
6.1. New Versions.
|
||||
Netscape Communications Corporation ("Netscape") may publish revised
|
||||
and/or new versions of the License from time to time. Each version
|
||||
will be given a distinguishing version number.
|
||||
|
||||
6.2. Effect of New Versions.
|
||||
Once Covered Code has been published under a particular version of the
|
||||
License, You may always continue to use it under the terms of that
|
||||
version. You may also choose to use such Covered Code under the terms
|
||||
of any subsequent version of the License published by Netscape. No one
|
||||
other than Netscape has the right to modify the terms applicable to
|
||||
Covered Code created under this License.
|
||||
|
||||
6.3. Derivative Works.
|
||||
If You create or use a modified version of this License (which you may
|
||||
only do in order to apply it to code which is not already Covered Code
|
||||
governed by this License), You must (a) rename Your license so that
|
||||
the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
|
||||
"MPL", "NPL" or any confusingly similar phrase do not appear in your
|
||||
license (except to note that your license differs from this License)
|
||||
and (b) otherwise make it clear that Your version of the license
|
||||
contains terms which differ from the Mozilla Public License and
|
||||
Netscape Public License. (Filling in the name of the Initial
|
||||
Developer, Original Code or Contributor in the notice described in
|
||||
Exhibit A shall not of themselves be deemed to be modifications of
|
||||
this License.)
|
||||
|
||||
7. DISCLAIMER OF WARRANTY.
|
||||
|
||||
COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
|
||||
WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
|
||||
WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
|
||||
DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
|
||||
THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
|
||||
IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
|
||||
YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
|
||||
COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
|
||||
OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
|
||||
ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
|
||||
|
||||
8. TERMINATION.
|
||||
|
||||
8.1. This License and the rights granted hereunder will terminate
|
||||
automatically if You fail to comply with terms herein and fail to cure
|
||||
such breach within 30 days of becoming aware of the breach. All
|
||||
sublicenses to the Covered Code which are properly granted shall
|
||||
survive any termination of this License. Provisions which, by their
|
||||
nature, must remain in effect beyond the termination of this License
|
||||
shall survive.
|
||||
|
||||
8.2. If You initiate litigation by asserting a patent infringement
|
||||
claim (excluding declatory judgment actions) against Initial Developer
|
||||
or a Contributor (the Initial Developer or Contributor against whom
|
||||
You file such action is referred to as "Participant") alleging that:
|
||||
|
||||
(a) such Participant's Contributor Version directly or indirectly
|
||||
infringes any patent, then any and all rights granted by such
|
||||
Participant to You under Sections 2.1 and/or 2.2 of this License
|
||||
shall, upon 60 days notice from Participant terminate prospectively,
|
||||
unless if within 60 days after receipt of notice You either: (i)
|
||||
agree in writing to pay Participant a mutually agreeable reasonable
|
||||
royalty for Your past and future use of Modifications made by such
|
||||
Participant, or (ii) withdraw Your litigation claim with respect to
|
||||
the Contributor Version against such Participant. If within 60 days
|
||||
of notice, a reasonable royalty and payment arrangement are not
|
||||
mutually agreed upon in writing by the parties or the litigation claim
|
||||
is not withdrawn, the rights granted by Participant to You under
|
||||
Sections 2.1 and/or 2.2 automatically terminate at the expiration of
|
||||
the 60 day notice period specified above.
|
||||
|
||||
(b) any software, hardware, or device, other than such Participant's
|
||||
Contributor Version, directly or indirectly infringes any patent, then
|
||||
any rights granted to You by such Participant under Sections 2.1(b)
|
||||
and 2.2(b) are revoked effective as of the date You first made, used,
|
||||
sold, distributed, or had made, Modifications made by that
|
||||
Participant.
|
||||
|
||||
8.3. If You assert a patent infringement claim against Participant
|
||||
alleging that such Participant's Contributor Version directly or
|
||||
indirectly infringes any patent where such claim is resolved (such as
|
||||
by license or settlement) prior to the initiation of patent
|
||||
infringement litigation, then the reasonable value of the licenses
|
||||
granted by such Participant under Sections 2.1 or 2.2 shall be taken
|
||||
into account in determining the amount or value of any payment or
|
||||
license.
|
||||
|
||||
8.4. In the event of termination under Sections 8.1 or 8.2 above,
|
||||
all end user license agreements (excluding distributors and resellers)
|
||||
which have been validly granted by You or any distributor hereunder
|
||||
prior to termination shall survive termination.
|
||||
|
||||
9. LIMITATION OF LIABILITY.
|
||||
|
||||
UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
|
||||
(INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
|
||||
DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
|
||||
OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
|
||||
ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
|
||||
CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
|
||||
WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
|
||||
COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
|
||||
INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
|
||||
LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
|
||||
RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
|
||||
PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
|
||||
EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
|
||||
THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
|
||||
|
||||
10. U.S. GOVERNMENT END USERS.
|
||||
|
||||
The Covered Code is a "commercial item," as that term is defined in
|
||||
48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
|
||||
software" and "commercial computer software documentation," as such
|
||||
terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
|
||||
C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
|
||||
all U.S. Government End Users acquire Covered Code with only those
|
||||
rights set forth herein.
|
||||
|
||||
11. MISCELLANEOUS.
|
||||
|
||||
This License represents the complete agreement concerning subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. This License shall be governed by
|
||||
California law provisions (except to the extent applicable law, if
|
||||
any, provides otherwise), excluding its conflict-of-law provisions.
|
||||
With respect to disputes in which at least one party is a citizen of,
|
||||
or an entity chartered or registered to do business in the United
|
||||
States of America, any litigation relating to this License shall be
|
||||
subject to the jurisdiction of the Federal Courts of the Northern
|
||||
District of California, with venue lying in Santa Clara County,
|
||||
California, with the losing party responsible for costs, including
|
||||
without limitation, court costs and reasonable attorneys' fees and
|
||||
expenses. The application of the United Nations Convention on
|
||||
Contracts for the International Sale of Goods is expressly excluded.
|
||||
Any law or regulation which provides that the language of a contract
|
||||
shall be construed against the drafter shall not apply to this
|
||||
License.
|
||||
|
||||
12. RESPONSIBILITY FOR CLAIMS.
|
||||
|
||||
As between Initial Developer and the Contributors, each party is
|
||||
responsible for claims and damages arising, directly or indirectly,
|
||||
out of its utilization of rights under this License and You agree to
|
||||
work with Initial Developer and Contributors to distribute such
|
||||
responsibility on an equitable basis. Nothing herein is intended or
|
||||
shall be deemed to constitute any admission of liability.
|
||||
|
||||
13. MULTIPLE-LICENSED CODE.
|
||||
|
||||
Initial Developer may designate portions of the Covered Code as
|
||||
"Multiple-Licensed". "Multiple-Licensed" means that the Initial
|
||||
Developer permits you to utilize portions of the Covered Code under
|
||||
Your choice of the NPL or the alternative licenses, if any, specified
|
||||
by the Initial Developer in the file described in Exhibit A.
|
||||
|
||||
EXHIBIT A -Mozilla Public License.
|
||||
|
||||
``The contents of this file are subject to the Mozilla Public License
|
||||
Version 1.1 (the "License"); you may not use this file except in
|
||||
compliance with the License. You may obtain a copy of the License at
|
||||
http://www.mozilla.org/MPL/
|
||||
|
||||
Software distributed under the License is distributed on an "AS IS"
|
||||
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing rights and limitations
|
||||
under the License.
|
||||
|
||||
The Original Code is ______________________________________.
|
||||
|
||||
The Initial Developer of the Original Code is ________________________.
|
||||
Portions created by ______________________ are Copyright (C) ______
|
||||
_______________________. All Rights Reserved.
|
||||
|
||||
Contributor(s): ______________________________________.
|
||||
|
||||
Alternatively, the contents of this file may be used under the terms
|
||||
of the _____ license (the "[___] License"), in which case the
|
||||
provisions of [______] License are applicable instead of those
|
||||
above. If you wish to allow use of your version of this file only
|
||||
under the terms of the [____] License and not to allow others to use
|
||||
your version of this file under the MPL, indicate your decision by
|
||||
deleting the provisions above and replace them with the notice and
|
||||
other provisions required by the [___] License. If you do not delete
|
||||
the provisions above, a recipient may use your version of this file
|
||||
under either the MPL or the [___] License."
|
||||
|
||||
[NOTE: The text of this Exhibit A may differ slightly from the text of
|
||||
the notices in the Source Code files of the Original Code. You should
|
||||
use the text of this Exhibit A rather than the text found in the
|
||||
Original Code Source Code for Your Modifications.]
|
||||
|
|
@ -1,203 +0,0 @@
|
|||
include(CheckLibraryExists)
|
||||
include(CheckTypeSize)
|
||||
include(CheckCXXSourceCompiles)
|
||||
|
||||
# Check if the size of numeric types are suitable.
|
||||
|
||||
check_type_size("short" SIZEOF_SHORT)
|
||||
if(NOT ${SIZEOF_SHORT} EQUAL 2)
|
||||
message(FATAL_ERROR "TagLib requires that short is 16-bit wide.")
|
||||
endif()
|
||||
|
||||
check_type_size("int" SIZEOF_INT)
|
||||
if(NOT ${SIZEOF_INT} EQUAL 4)
|
||||
message(FATAL_ERROR "TagLib requires that int is 32-bit wide.")
|
||||
endif()
|
||||
|
||||
check_type_size("long long" SIZEOF_LONGLONG)
|
||||
if(NOT ${SIZEOF_LONGLONG} EQUAL 8)
|
||||
message(FATAL_ERROR "TagLib requires that long long is 64-bit wide.")
|
||||
endif()
|
||||
|
||||
check_type_size("wchar_t" SIZEOF_WCHAR_T)
|
||||
if(${SIZEOF_WCHAR_T} LESS 2)
|
||||
message(FATAL_ERROR "TagLib requires that wchar_t is sufficient to store a UTF-16 char.")
|
||||
endif()
|
||||
|
||||
check_type_size("float" SIZEOF_FLOAT)
|
||||
if(NOT ${SIZEOF_FLOAT} EQUAL 4)
|
||||
message(FATAL_ERROR "TagLib requires that float is 32-bit wide.")
|
||||
endif()
|
||||
|
||||
check_type_size("double" SIZEOF_DOUBLE)
|
||||
if(NOT ${SIZEOF_DOUBLE} EQUAL 8)
|
||||
message(FATAL_ERROR "TagLib requires that double is 64-bit wide.")
|
||||
endif()
|
||||
|
||||
# Determine which kind of atomic operations your compiler supports.
|
||||
|
||||
check_cxx_source_compiles("
|
||||
int main() {
|
||||
volatile int x;
|
||||
__sync_add_and_fetch(&x, 1);
|
||||
int y = __sync_sub_and_fetch(&x, 1);
|
||||
return 0;
|
||||
}
|
||||
" HAVE_GCC_ATOMIC)
|
||||
|
||||
if(NOT HAVE_GCC_ATOMIC)
|
||||
check_cxx_source_compiles("
|
||||
#include <libkern/OSAtomic.h>
|
||||
int main() {
|
||||
volatile int32_t x;
|
||||
OSAtomicIncrement32Barrier(&x);
|
||||
int32_t y = OSAtomicDecrement32Barrier(&x);
|
||||
return 0;
|
||||
}
|
||||
" HAVE_MAC_ATOMIC)
|
||||
|
||||
if(NOT HAVE_MAC_ATOMIC)
|
||||
check_cxx_source_compiles("
|
||||
#include <windows.h>
|
||||
int main() {
|
||||
volatile LONG x;
|
||||
InterlockedIncrement(&x);
|
||||
LONG y = InterlockedDecrement(&x);
|
||||
return 0;
|
||||
}
|
||||
" HAVE_WIN_ATOMIC)
|
||||
|
||||
if(NOT HAVE_WIN_ATOMIC)
|
||||
check_cxx_source_compiles("
|
||||
#include <ia64intrin.h>
|
||||
int main() {
|
||||
volatile int x;
|
||||
__sync_add_and_fetch(&x, 1);
|
||||
int y = __sync_sub_and_fetch(&x, 1);
|
||||
return 0;
|
||||
}
|
||||
" HAVE_IA64_ATOMIC)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Determine which kind of byte swap functions your compiler supports.
|
||||
|
||||
check_cxx_source_compiles("
|
||||
int main() {
|
||||
__builtin_bswap16(0);
|
||||
__builtin_bswap32(0);
|
||||
__builtin_bswap64(0);
|
||||
return 0;
|
||||
}
|
||||
" HAVE_GCC_BYTESWAP)
|
||||
|
||||
if(NOT HAVE_GCC_BYTESWAP)
|
||||
check_cxx_source_compiles("
|
||||
#include <byteswap.h>
|
||||
int main() {
|
||||
__bswap_16(0);
|
||||
__bswap_32(0);
|
||||
__bswap_64(0);
|
||||
return 0;
|
||||
}
|
||||
" HAVE_GLIBC_BYTESWAP)
|
||||
|
||||
if(NOT HAVE_GLIBC_BYTESWAP)
|
||||
check_cxx_source_compiles("
|
||||
#include <stdlib.h>
|
||||
int main() {
|
||||
_byteswap_ushort(0);
|
||||
_byteswap_ulong(0);
|
||||
_byteswap_uint64(0);
|
||||
return 0;
|
||||
}
|
||||
" HAVE_MSC_BYTESWAP)
|
||||
|
||||
if(NOT HAVE_MSC_BYTESWAP)
|
||||
check_cxx_source_compiles("
|
||||
#include <libkern/OSByteOrder.h>
|
||||
int main() {
|
||||
OSSwapInt16(0);
|
||||
OSSwapInt32(0);
|
||||
OSSwapInt64(0);
|
||||
return 0;
|
||||
}
|
||||
" HAVE_MAC_BYTESWAP)
|
||||
|
||||
if(NOT HAVE_MAC_BYTESWAP)
|
||||
check_cxx_source_compiles("
|
||||
#include <sys/endian.h>
|
||||
int main() {
|
||||
swap16(0);
|
||||
swap32(0);
|
||||
swap64(0);
|
||||
return 0;
|
||||
}
|
||||
" HAVE_OPENBSD_BYTESWAP)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Determine whether your compiler supports some safer version of vsprintf.
|
||||
|
||||
check_cxx_source_compiles("
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
int main() {
|
||||
char buf[20];
|
||||
va_list args;
|
||||
vsnprintf(buf, 20, \"%d\", args);
|
||||
return 0;
|
||||
}
|
||||
" HAVE_VSNPRINTF)
|
||||
|
||||
if(NOT HAVE_VSNPRINTF)
|
||||
check_cxx_source_compiles("
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
int main() {
|
||||
char buf[20];
|
||||
va_list args;
|
||||
vsprintf_s(buf, \"%d\", args);
|
||||
return 0;
|
||||
}
|
||||
" HAVE_VSPRINTF_S)
|
||||
endif()
|
||||
|
||||
# Determine whether your compiler supports ISO _strdup.
|
||||
|
||||
check_cxx_source_compiles("
|
||||
#include <cstring>
|
||||
int main() {
|
||||
_strdup(0);
|
||||
return 0;
|
||||
}
|
||||
" HAVE_ISO_STRDUP)
|
||||
|
||||
# Determine whether zlib is installed.
|
||||
|
||||
if(NOT ZLIB_SOURCE)
|
||||
find_package(ZLIB)
|
||||
if(ZLIB_FOUND)
|
||||
set(HAVE_ZLIB 1)
|
||||
else()
|
||||
set(HAVE_ZLIB 0)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Determine whether CppUnit is installed.
|
||||
|
||||
if(BUILD_TESTS AND NOT BUILD_SHARED_LIBS)
|
||||
find_package(CppUnit)
|
||||
if(NOT CppUnit_FOUND)
|
||||
message(STATUS "CppUnit not found, disabling tests.")
|
||||
set(BUILD_TESTS OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Detect WinRT mode
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
|
||||
set(PLATFORM WINRT 1)
|
||||
endif()
|
|
@ -1,210 +0,0 @@
|
|||
# Doxyfile 1.3.4
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Project related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
PROJECT_NAME = TagLib
|
||||
PROJECT_NUMBER = ${TAGLIB_LIB_VERSION_STRING}
|
||||
OUTPUT_DIRECTORY = doc
|
||||
OUTPUT_LANGUAGE = English
|
||||
USE_WINDOWS_ENCODING = NO
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
FULL_PATH_NAMES = NO
|
||||
STRIP_FROM_PATH =
|
||||
SHORT_NAMES = NO
|
||||
JAVADOC_AUTOBRIEF = NO
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
DETAILS_AT_TOP = NO
|
||||
INHERIT_DOCS = YES
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
TAB_SIZE = 4
|
||||
ALIASES =
|
||||
OPTIMIZE_OUTPUT_FOR_C = NO
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
SUBGROUPING = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Build related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
EXTRACT_ALL = YES
|
||||
EXTRACT_PRIVATE = NO
|
||||
EXTRACT_STATIC = NO
|
||||
EXTRACT_LOCAL_CLASSES = NO
|
||||
HIDE_UNDOC_MEMBERS = NO
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
HIDE_FRIEND_COMPOUNDS = NO
|
||||
HIDE_IN_BODY_DOCS = NO
|
||||
INTERNAL_DOCS = YES
|
||||
CASE_SENSE_NAMES = YES
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
INLINE_INFO = YES
|
||||
SORT_MEMBER_DOCS = YES
|
||||
GENERATE_TODOLIST = NO
|
||||
GENERATE_TESTLIST = NO
|
||||
GENERATE_BUGLIST = NO
|
||||
GENERATE_DEPRECATEDLIST= NO
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
SHOW_USED_FILES = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to warning and progress messages
|
||||
#---------------------------------------------------------------------------
|
||||
QUIET = NO
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = NO
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_LOGFILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
INPUT = @CMAKE_SOURCE_DIR@/taglib
|
||||
FILE_PATTERNS = *.h \
|
||||
*.hh \
|
||||
*.H
|
||||
RECURSIVE = YES
|
||||
EXCLUDE =
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS =
|
||||
EXAMPLE_PATH =
|
||||
EXAMPLE_PATTERNS =
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH =
|
||||
INPUT_FILTER =
|
||||
FILTER_SOURCE_FILES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to source browsing
|
||||
#---------------------------------------------------------------------------
|
||||
SOURCE_BROWSER = NO
|
||||
INLINE_SOURCES = NO
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
REFERENCED_BY_RELATION = YES
|
||||
REFERENCES_RELATION = YES
|
||||
VERBATIM_HEADERS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
ALPHABETICAL_INDEX = YES
|
||||
COLS_IN_ALPHA_INDEX = 5
|
||||
IGNORE_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the HTML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = html
|
||||
HTML_FILE_EXTENSION = .html
|
||||
HTML_HEADER = @CMAKE_SOURCE_DIR@/doc/api-header.html
|
||||
HTML_FOOTER = @CMAKE_SOURCE_DIR@/doc/api-footer.html
|
||||
HTML_STYLESHEET = @CMAKE_SOURCE_DIR@/doc/taglib-api.css
|
||||
HTML_ALIGN_MEMBERS = YES
|
||||
GENERATE_HTMLHELP = NO
|
||||
CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
GENERATE_CHI = NO
|
||||
BINARY_TOC = NO
|
||||
TOC_EXPAND = NO
|
||||
DISABLE_INDEX = YES
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
GENERATE_TREEVIEW = NO
|
||||
TREEVIEW_WIDTH = 250
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the LaTeX output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_LATEX = NO
|
||||
LATEX_OUTPUT = latex
|
||||
LATEX_CMD_NAME = latex
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
COMPACT_LATEX = NO
|
||||
PAPER_TYPE = letter
|
||||
EXTRA_PACKAGES =
|
||||
LATEX_HEADER =
|
||||
PDF_HYPERLINKS = YES
|
||||
USE_PDFLATEX = YES
|
||||
LATEX_BATCHMODE = NO
|
||||
LATEX_HIDE_INDICES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the RTF output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_RTF = NO
|
||||
RTF_OUTPUT = rtf
|
||||
COMPACT_RTF = NO
|
||||
RTF_HYPERLINKS = NO
|
||||
RTF_STYLESHEET_FILE =
|
||||
RTF_EXTENSIONS_FILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the man page output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_MAN = NO
|
||||
MAN_OUTPUT = man
|
||||
MAN_EXTENSION = .3
|
||||
MAN_LINKS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the XML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_XML = NO
|
||||
XML_OUTPUT = xml
|
||||
XML_SCHEMA =
|
||||
XML_DTD =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options for the AutoGen Definitions output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the Perl module output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_PERLMOD = NO
|
||||
PERLMOD_LATEX = NO
|
||||
PERLMOD_PRETTY = YES
|
||||
PERLMOD_MAKEVAR_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the preprocessor
|
||||
#---------------------------------------------------------------------------
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = NO
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
SEARCH_INCLUDES = YES
|
||||
INCLUDE_PATH =
|
||||
INCLUDE_FILE_PATTERNS =
|
||||
PREDEFINED = DO_NOT_DOCUMENT \
|
||||
DOXYGEN \
|
||||
WITH_MP4 \
|
||||
WITH_ASF
|
||||
EXPAND_AS_DEFINED =
|
||||
SKIP_FUNCTION_MACROS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::addtions related to external references
|
||||
#---------------------------------------------------------------------------
|
||||
TAGFILES =
|
||||
GENERATE_TAGFILE =
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = YES
|
||||
PERL_PATH = /usr/bin/perl
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
CLASS_DIAGRAMS = YES
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = YES
|
||||
CLASS_GRAPH = YES
|
||||
COLLABORATION_GRAPH = YES
|
||||
UML_LOOK = NO
|
||||
TEMPLATE_RELATIONS = YES
|
||||
INCLUDE_GRAPH = YES
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
CALL_GRAPH = NO
|
||||
GRAPHICAL_HIERARCHY = YES
|
||||
DOT_IMAGE_FORMAT = png
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
MAX_DOT_GRAPH_WIDTH = 1024
|
||||
MAX_DOT_GRAPH_HEIGHT = 1024
|
||||
MAX_DOT_GRAPH_DEPTH = 0
|
||||
GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::addtions related to the search engine
|
||||
#---------------------------------------------------------------------------
|
||||
SEARCHENGINE = NO
|
|
@ -1,175 +0,0 @@
|
|||
TagLib Installation
|
||||
===================
|
||||
|
||||
TagLib uses the CMake build system. As a user, you will most likely want to
|
||||
build TagLib in release mode and install it into a system-wide location.
|
||||
This can be done using the following commands:
|
||||
|
||||
cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DCMAKE_BUILD_TYPE=Release .
|
||||
make
|
||||
sudo make install
|
||||
|
||||
In order to build the included examples, use the `BUILD_EXAMPLES` option:
|
||||
|
||||
cmake -DBUILD_EXAMPLES=ON [...]
|
||||
|
||||
See http://www.cmake.org/cmake/help/runningcmake.html for generic help on
|
||||
running CMake.
|
||||
|
||||
Mac OS X
|
||||
--------
|
||||
|
||||
On Mac OS X, you might want to build a framework that can be easily integrated
|
||||
into your application. If you set the BUILD_FRAMEWORK option on, it will compile
|
||||
TagLib as a framework. For example, the following command can be used to build
|
||||
an Universal Binary framework with Mac OS X 10.4 as the deployment target:
|
||||
|
||||
cmake -DCMAKE_BUILD_TYPE=Release \
|
||||
-DBUILD_FRAMEWORK=ON \
|
||||
-DCMAKE_C_COMPILER=/usr/bin/gcc-4.0 \
|
||||
-DCMAKE_CXX_COMPILER=/usr/bin/c++-4.0 \
|
||||
-DCMAKE_OSX_SYSROOT=/Developer/SDKs/MacOSX10.4u.sdk/ \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.4 \
|
||||
-DCMAKE_OSX_ARCHITECTURES="ppc;i386;x86_64"
|
||||
|
||||
For a 10.6 Snow Leopard static library with both 32-bit and 64-bit code, use:
|
||||
|
||||
cmake -DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.6 \
|
||||
-DCMAKE_OSX_ARCHITECTURES="i386;x86_64" \
|
||||
-DBUILD_SHARED_LIBS=OFF \
|
||||
-DCMAKE_INSTALL_PREFIX="<folder you want to build to>"
|
||||
|
||||
After `make`, and `make install`, add `libtag.` to your XCode project, and add
|
||||
the include folder to the project's User Header Search Paths.
|
||||
|
||||
Windows
|
||||
-------
|
||||
|
||||
It's Windows ... Systems vary!
|
||||
This means you need to adjust things to suit your system, especially paths.
|
||||
|
||||
Tested with:
|
||||
* Microsoft Visual Studio 2010, 2015, 2017
|
||||
* Microsoft C++ Build Tools 2015, 2017 (standalone packages not requiring Visual Studio)
|
||||
* Gcc by mingw-w64.sf.net v4.6.3 (Strawberry Perl 32b)
|
||||
* MinGW32-4.8.0
|
||||
|
||||
Requirements:
|
||||
* Tool chain, build environment, whatever ya want to call it ...
|
||||
Installed and working.
|
||||
* CMake program. (Available at: www.cmake.org)
|
||||
Installed and working.
|
||||
|
||||
Optional:
|
||||
* Zlib library.
|
||||
Available in some tool chains, not all.
|
||||
Search the web, take your choice.
|
||||
|
||||
Useful configuration options used with CMake (GUI and/or command line):
|
||||
Any of the `ZLIB_` variables may be used at the command line, `ZLIB_ROOT` is only
|
||||
available on the command line.
|
||||
|
||||
| option | description |
|
||||
---------------------| ------------|
|
||||
`ZLIB_ROOT=` | Where to find ZLib's root directory. Assumes parent of: `\include` and `\lib.`|
|
||||
`ZLIB_INCLUDE_DIR=` | Where to find ZLib's Include directory.|
|
||||
`ZLIB_LIBRARY=` | Where to find ZLib's Library.
|
||||
`ZLIB_SOURCE=` | Where to find ZLib's Source Code. Alternative to `ZLIB_INCLUDE_DIR` and `ZLIB_LIBRARY`.
|
||||
`CMAKE_INSTALL_PREFIX=` | Where to install Taglib. |
|
||||
`CMAKE_BUILD_TYPE=` | Release, Debug, etc ... (Not available in MSVC) |
|
||||
|
||||
The easiest way is at the command prompt (Visual C++ command prompt for MSVS users – batch file and/or shortcuts are your friends).
|
||||
|
||||
1. **Build the Makefiles:**
|
||||
|
||||
Replace "GENERATOR" with your needs.
|
||||
* For MSVS: `Visual Studio XX YYYY`, e.g. `Visual Studio 14 2015`.
|
||||
|
||||
**Note**: As Visual Studio 2017 supports CMake, you can skip this step and open the taglib
|
||||
folder in VS instead.
|
||||
* For MinGW: `MinGW Makefiles`
|
||||
|
||||
C:\GitRoot\taglib> cmake -G "GENERATOR" -DCMAKE_INSTALL_PREFIX=C:\Libraries\taglib
|
||||
|
||||
Or use the CMake GUI:
|
||||
1. Open CMake GUI.
|
||||
2. Set paths: *Where is the source code* and *Where to build the binaries*.
|
||||
|
||||
In the example, both would be: `C:\GitRoot\taglib`
|
||||
3. Tick: Advanced
|
||||
4. Select: Configure
|
||||
5. Select: Generator
|
||||
6. Tick: Use default native compilers
|
||||
7. Select: Finish
|
||||
Wait until done.
|
||||
8. If using ZLib, Scroll down.
|
||||
(to the bottom of the list of options ... should go over them all)
|
||||
1. Edit: `ZLIB_INCLUDE_DIR`
|
||||
2. Edit: `ZLIB_LIBRARY`
|
||||
9. Select: Generate
|
||||
|
||||
2. **Build the project**
|
||||
* MSVS:
|
||||
|
||||
C:\GitRoot\taglib> msbuild all_build.vcxproj /p:Configuration=Release
|
||||
OR (Depending on MSVS version or personal choice)
|
||||
|
||||
C:\GitRoot\taglib> devenv all_build.vcxproj /build Release
|
||||
OR in the MSVS GUI:
|
||||
1. Open MSVS.
|
||||
2. Open taglib solution.
|
||||
3. Set build type to: Release (look in the tool bars)
|
||||
2. Hit F7 to build the solution. (project)
|
||||
* MinGW:
|
||||
|
||||
C:\GitRoot\taglib> gmake
|
||||
|
||||
OR (Depending on MinGW install)
|
||||
|
||||
C:\GitRoot\taglib> mingw32-make
|
||||
|
||||
|
||||
|
||||
3. **Install the project**
|
||||
|
||||
(Change `install` to `uninstall` to uninstall the project)
|
||||
* MSVS:
|
||||
|
||||
C:\GitRoot\taglib> msbuild install.vcxproj
|
||||
OR (Depending on MSVC version or personal choice)
|
||||
|
||||
C:\GitRoot\taglib> devenv install.vcxproj
|
||||
|
||||
Or in the MSVS GUI:
|
||||
1. Open project.
|
||||
2. Open Solution Explorer.
|
||||
3. Right Click: INSTALL
|
||||
4. Select: Project Only
|
||||
5. Select: Build Only INSTALL
|
||||
* MinGW:
|
||||
|
||||
C:\GitRoot\taglib> gmake install
|
||||
OR (Depending on MinGW install)
|
||||
|
||||
C:\GitRoot\taglib> mingw32-make install
|
||||
|
||||
|
||||
To build a static library, set the following two options with CMake:
|
||||
|
||||
-DBUILD_SHARED_LIBS=OFF -DENABLE_STATIC_RUNTIME=ON
|
||||
|
||||
Including `ENABLE_STATIC_RUNTIME=ON` indicates you want TagLib built using the
|
||||
static runtime library, rather than the DLL form of the runtime.
|
||||
|
||||
Unit Tests
|
||||
----------
|
||||
|
||||
If you want to run the test suite to make sure TagLib works properly on your
|
||||
system, you need to have cppunit installed. To build the tests, include
|
||||
the option `-DBUILD_TESTS=on` when running cmake.
|
||||
|
||||
The test suite has a custom target in the build system, so you can run
|
||||
the tests using make:
|
||||
|
||||
make check
|
|
@ -1,335 +0,0 @@
|
|||
============================
|
||||
|
||||
* Added support for WinRT.
|
||||
* Added support for Linux on POWER.
|
||||
* Added support for classical music tags of iTunes 12.5.
|
||||
* Added support for file descriptor to FileStream.
|
||||
* Added support for 'cmID', 'purl', 'egid' MP4 atoms.
|
||||
* Added support for 'GRP1' ID3v2 frame.
|
||||
* Added support for extensible WAV subformat.
|
||||
* Enabled FileRef to detect file types based on the stream content.
|
||||
* Dropped support for Windows 9x and NT 4.0 or older.
|
||||
* Check for mandatory header objects in ASF files.
|
||||
* More tolerant handling of RIFF padding, WAV files, broken MPEG streams.
|
||||
* Improved calculation of Ogg, Opus, Speex, WAV, MP4 bitrates.
|
||||
* Improved Windows compatibility by storing FLAC picture after comments.
|
||||
* Fixed numerical genres in ID3v2.3.0 'TCON' frames.
|
||||
* Fixed consistency of API removing MP4 items when empty values are set.
|
||||
* Fixed consistency of API preferring COMM frames with no description.
|
||||
* Fixed OOB read on invalid Ogg FLAC files (CVE-2018-11439).
|
||||
* Fixed handling of empty MPEG files.
|
||||
* Fixed parsing MP4 mdhd timescale.
|
||||
* Fixed reading MP4 atoms with zero length.
|
||||
* Fixed reading FLAC files with zero-sized seektables.
|
||||
* Fixed handling of lowercase field names in Vorbis Comments.
|
||||
* Fixed handling of 'rate' atoms in MP4 files.
|
||||
* Fixed handling of invalid UTF-8 sequences.
|
||||
* Fixed possible file corruptions when saving Ogg files.
|
||||
* Fixed handling of non-audio blocks, sampling rates, DSD audio in WavPack files.
|
||||
* TableOfContentsFrame::toString() improved.
|
||||
* UserTextIdentificationFrame::toString() improved.
|
||||
* Marked FileRef::create() deprecated.
|
||||
* Marked MPEG::File::save() with boolean parameters deprecated,
|
||||
provide overloads with enum parameters.
|
||||
* Several smaller bug fixes and performance improvements.
|
||||
|
||||
TagLib 1.11.1 (Oct 24, 2016)
|
||||
============================
|
||||
|
||||
* Fixed binary incompatible change in TagLib::String.
|
||||
* Fixed reading ID3v2 CTOC frames with a lot of entries.
|
||||
* Fixed seeking ByteVectorStream from the end.
|
||||
|
||||
TagLib 1.11 (Apr 29, 2016)
|
||||
==========================
|
||||
|
||||
1.11:
|
||||
|
||||
* Fixed reading APE items with long keys.
|
||||
* Fixed reading ID3v2 SYLT frames when description is empty.
|
||||
|
||||
1.11 BETA 2:
|
||||
|
||||
* Better handling of PCM WAV files with a 'fact' chunk.
|
||||
* Better handling of corrupted APE tags.
|
||||
* Efficient decoding of unsynchronized ID3v2 frames.
|
||||
* Fixed text encoding when saving certain frames in ID3v2.3 tags.
|
||||
* Fixed updating the size of RIFF files when removing chunks.
|
||||
* Several smaller bug fixes and performance improvements.
|
||||
|
||||
1.11 BETA:
|
||||
|
||||
* New API for creating FileRef from IOStream.
|
||||
* Added support for ID3v2 PCST and WFED frames.
|
||||
* Added support for pictures in XiphComment.
|
||||
* Added String::clear().
|
||||
* Added FLAC::File::strip() for removing non-standard tags.
|
||||
* Added alternative functions to XiphComment::removeField().
|
||||
* Added BUILD_BINDINGS build option.
|
||||
* Added ENABLE_CCACHE build option.
|
||||
* Replaced ENABLE_STATIC build option with BUILD_SHARED_LIBS.
|
||||
* Better handling of duplicate ID3v2 tags in all kinds of files.
|
||||
* Better handling of duplicate tag chunks in WAV files.
|
||||
* Better handling of duplicate tag chunks in AIFF files.
|
||||
* Better handling of duplicate Vorbis comment blocks in FLAC files.
|
||||
* Better handling of broken MPEG audio frames.
|
||||
* Fixed crash when calling File::properties() after strip().
|
||||
* Fixed crash when parsing certain MPEG files.
|
||||
* Fixed crash when saving Ogg files.
|
||||
* Fixed possible file corruptions when saving ASF files.
|
||||
* Fixed possible file corruptions when saving FLAC files.
|
||||
* Fixed possible file corruptions when saving MP4 files.
|
||||
* Fixed possible file corruptions when saving MPEG files.
|
||||
* Fixed possible file corruptions when saving APE files.
|
||||
* Fixed possible file corruptions when saving Musepack files.
|
||||
* Fixed possible file corruptions when saving WavPack files.
|
||||
* Fixed updating the comment field of Vorbis comments.
|
||||
* Fixed reading date and time in ID3v2.3 tags.
|
||||
* Marked ByteVector::null and ByteVector::isNull() deprecated.
|
||||
* Marked String::null and String::isNull() deprecated.
|
||||
* Marked XiphComment::removeField() deprecated.
|
||||
* Marked Ogg::Page::getCopyWithNewPageSequenceNumber() deprecated. It returns null.
|
||||
* Marked custom integer types deprecated.
|
||||
* Many smaller bug fixes and performance improvements.
|
||||
|
||||
TagLib 1.10 (Nov 11, 2015)
|
||||
==========================
|
||||
|
||||
1.10:
|
||||
|
||||
* Added new options to the tagwriter example.
|
||||
* Fixed self-assignment operator in some types.
|
||||
* Fixed extraction of MP4 tag keys with an empty list.
|
||||
|
||||
1.10 BETA:
|
||||
|
||||
* New API for the audio length in milliseconds.
|
||||
* Added support for ID3v2 ETCO and SYLT frames.
|
||||
* Added support for album artist in PropertyMap API of MP4 files.
|
||||
* Added support for embedded frames in ID3v2 CHAP and CTOC frames.
|
||||
* Added support for AIFF-C files.
|
||||
* Better handling of duplicate ID3v2 tags in MPEG files.
|
||||
* Allowed generating taglib.pc on Windows.
|
||||
* Added ZLIB_SOURCE build option.
|
||||
* Fixed backwards-incompatible change in TagLib::String when constructing UTF16 strings.
|
||||
* Fixed crash when parsing certain FLAC files.
|
||||
* Fixed crash when encoding empty strings.
|
||||
* Fixed saving of certain XM files on OS X.
|
||||
* Changed Xiph and APE generic getters to return space-concatenated values.
|
||||
* Fixed possible file corruptions when removing tags from WAV files.
|
||||
* Added support for MP4 files with 64-bit atoms in certain 64-bit environments.
|
||||
* Prevented ID3v2 padding from being too large.
|
||||
* Fixed crash when parsing corrupted APE files.
|
||||
* Fixed crash when parsing corrupted WAV files.
|
||||
* Fixed crash when parsing corrupted Ogg FLAC files.
|
||||
* Fixed crash when parsing corrupted MPEG files.
|
||||
* Fixed saving empty tags in WAV files.
|
||||
* Fixed crash when parsing corrupted Musepack files.
|
||||
* Fixed possible memory leaks when parsing AIFF and WAV files.
|
||||
* Fixed crash when parsing corrupted MP4 files.
|
||||
* Stopped writing empty ID3v2 frames.
|
||||
* Fixed possible file corruptions when saving WMA files.
|
||||
* Added TagLib::MP4::Tag::isEmpty().
|
||||
* Added accessors to manipulate MP4 tags.
|
||||
* Fixed crash when parsing corrupted WavPack files.
|
||||
* Fixed seeking MPEG frames.
|
||||
* Fixed reading FLAC files with zero-sized padding blocks.
|
||||
* Added support for reading the encoder information of WMA files.
|
||||
* Added support for reading the codec of WAV files.
|
||||
* Added support for multi channel WavPack files.
|
||||
* Added support for reading the nominal bitrate of Ogg Speex files.
|
||||
* Added support for VBR headers in MPEG files.
|
||||
* Marked FLAC::File::streamInfoData() deprecated. It returns an empty ByteVector.
|
||||
* Marked FLAC::File::streamLength() deprecated. It returns zero.
|
||||
* Fixed possible file corruptions when adding an ID3v1 tag to FLAC files.
|
||||
* Many smaller bug fixes and performance improvements.
|
||||
|
||||
TagLib 1.9.1 (Oct 8, 2013)
|
||||
==========================
|
||||
|
||||
* Fixed binary incompatible change in TagLib::Map and TagLib::List.
|
||||
* Fixed constructing String from ByteVector.
|
||||
* Fixed compilation on MSVC with the /Zc:wchar_t- option.
|
||||
* Fixed detecting of RIFF files with invalid chunk sizes.
|
||||
* Added TagLib::MP4::Properties::codec().
|
||||
|
||||
TagLib 1.9 (Oct 6, 2013)
|
||||
========================
|
||||
|
||||
* Added support for the Ogg Opus file format.
|
||||
* Added support for INFO tags in WAV files.
|
||||
* Changed FileStream to use Windows file API.
|
||||
* Included taglib-config.cmd script for Windows.
|
||||
* New ID3v1::Tag methods for working directly with genre numbers.
|
||||
* New MPEG::File methods for checking which tags are saved in the file.
|
||||
* Added support for the PropertyMap API to ASF and MP4 files.
|
||||
* Added MusicBrainz identifiers to the PropertyMap API.
|
||||
* Allowed reading of MP4 cover art without an explicitly specified format.
|
||||
* Better parsing of corrupted FLAC files.
|
||||
* Fixed saving of PropertyMap comments without description into ID3v2 tags.
|
||||
* Fixed crash when parsing certain XM files.
|
||||
* Fixed compilation of unit test with clang.
|
||||
* Better handling of files that can't be open or have read-only permissions.
|
||||
* Improved atomic reference counting.
|
||||
* New hookable API for debug messages.
|
||||
* More complete Windows install instructions.
|
||||
* Many smaller bug fixes and performance improvements.
|
||||
|
||||
TagLib 1.8 (Sep 6, 2012)
|
||||
========================
|
||||
|
||||
1.8:
|
||||
|
||||
* Added support for OWNE ID3 frames.
|
||||
* Changed key validation in the new PropertyMap API.
|
||||
* ID3v1::Tag::setStringHandler will no londer delete the previous handler,
|
||||
the caller is responsible for this.
|
||||
* File objects will also no longer delete the passed IOStream objects. It
|
||||
should be done in the caller code after the File object is no longer
|
||||
used.
|
||||
* Added ID3v2::Tag::setLatin1StringHandler for custom handling of
|
||||
latin1-encoded text in ID3v2 frames.
|
||||
* Fixed validation of ID3v2 frame IDs (IDs with '0' were ignored).
|
||||
|
||||
1.8 BETA:
|
||||
|
||||
* New API for accessing tags by name.
|
||||
* New abstract I/O stream layer to allow custom I/O handlers.
|
||||
* Support for writing ID3v2.3 tags.
|
||||
* Support for various module file formats (MOD, S3M, IT, XM).
|
||||
* Support for MP4 and ASF is now enabled by default.
|
||||
* Started using atomic int operations for reference counting.
|
||||
* Added methods for checking if WMA and MP4 files are DRM-protected.
|
||||
* Added taglib_free to the C bindings.
|
||||
* New method to allow removing pictures from FLAC files.
|
||||
* Support for reading audio properties from ALAC and Musepack SV8 files.
|
||||
* Added replay-gain information to Musepack audio properties.
|
||||
* Support for APEv2 binary tags.
|
||||
* Many AudioProperties subclasses now provide information about the total number of samples.
|
||||
* Various small bug fixes.
|
||||
|
||||
TagLib 1.7.2 (Apr 20, 2012)
|
||||
===========================
|
||||
|
||||
* Fixed division by zero while parsing corrupted MP4 files (CVE-2012-2396).
|
||||
* Fixed compilation on Haiku.
|
||||
|
||||
TagLib 1.7.1 (Mar 17, 2012)
|
||||
===========================
|
||||
|
||||
* Improved parsing of corrupted WMA, RIFF and OGG files.
|
||||
* Fixed a memory leak in the WMA parser.
|
||||
* Fixed a memory leak in the FLAC parser.
|
||||
* Fixed a possible division by zero in the APE parser.
|
||||
* Added detection of TTA2 files.
|
||||
* Fixed saving of multiple identically named tags to Vorbis Comments.
|
||||
|
||||
TagLib 1.7 (Mar 11, 2011)
|
||||
=========================
|
||||
|
||||
1.7:
|
||||
|
||||
* Fixed memory leaks in the FLAC file format parser.
|
||||
* Fixed bitrate calculation for WAV files.
|
||||
|
||||
1.7 RC1:
|
||||
|
||||
* Support for reading/writing tags from Monkey's Audio files. (BUG:210404)
|
||||
* Support for reading/writing embedded pictures from WMA files.
|
||||
* Support for reading/writing embedded pictures from FLAC files (BUG:218696).
|
||||
* Implemented APE::Tag::isEmpty() to check for all APE tags, not just the
|
||||
basic ones.
|
||||
* Added reading of WAV audio length. (BUG:116033)
|
||||
* Exposed FLAC MD5 signature of the uncompressed audio stream via
|
||||
FLAC::Properties::signature(). (BUG:160172)
|
||||
* Added function ByteVector::toHex() for hex-encoding of byte vectors.
|
||||
* WavPack reader now tries to get the audio length by finding the final
|
||||
block, if the header doesn't have the information. (BUG:258016)
|
||||
* Fixed a memory leak in the ID3v2.2 PIC frame parser. (BUG:257007)
|
||||
* Fixed writing of RIFF files with even chunk sizes. (BUG:243954)
|
||||
* Fixed compilation on MSVC 2010.
|
||||
* Removed support for building using autoconf/automake.
|
||||
* API docs can be now built using "make docs".
|
||||
|
||||
TagLib 1.6.3 (Apr 17, 2010)
|
||||
===========================
|
||||
|
||||
* Fixed definitions of the TAGLIB_WITH_MP4 and TAGLIB_WITH_ASF macros.
|
||||
* Fixed upgrading of ID3v2.3 genre frame with ID3v1 code 0 (Blues).
|
||||
* New method `int String::toInt(bool *ok)` which can return whether the
|
||||
conversion to a number was successful.
|
||||
* Fixed parsing of incorrectly written lengths in ID3v2 (affects mainly
|
||||
compressed frames). (BUG:231075)
|
||||
|
||||
TagLib 1.6.2 (Apr 9, 2010)
|
||||
==========================
|
||||
|
||||
* Read Vorbis Comments from the first FLAC metadata block, if there are
|
||||
multiple ones. (BUG:211089)
|
||||
* Fixed a memory leak in FileRef's OGA format detection.
|
||||
* Fixed compilation with the Sun Studio compiler. (BUG:215225)
|
||||
* Handle WM/TrackNumber attributes with DWORD content in WMA files.
|
||||
(BUG:218526)
|
||||
* More strict check if something is a valid MP4 file. (BUG:216819)
|
||||
* Correctly save MP4 int-pair atoms with flags set to 0.
|
||||
* Fixed compilation of the test runner on Windows.
|
||||
* Store ASF attributes larger than 64k in the metadata library object.
|
||||
* Ignore trailing non-data atoms when parsing MP4 covr atoms.
|
||||
* Don't upgrade ID3v2.2 frame TDA to TDRC. (BUG:228968)
|
||||
|
||||
TagLib 1.6.1 (Oct 31, 2009)
|
||||
===========================
|
||||
|
||||
* Better detection of the audio codec of .oga files in FileRef.
|
||||
* Fixed saving of Vorbis comments to Ogg FLAC files. TagLib tried to
|
||||
include the Vorbis framing bit, which is only correct for Ogg Vorbis.
|
||||
* Public symbols now have explicitly set visibility to "default" on GCC.
|
||||
* Added missing exports for static ID3v1 functions.
|
||||
* Fixed a typo in taglib_c.pc
|
||||
* Fixed a failing test on ppc64.
|
||||
* Support for binary 'covr' atom in MP4 files. TagLib 1.6 treated them
|
||||
as text atoms, which corrupted them in some cases.
|
||||
* Fixed ID3v1-style genre to string conversion in MP4 files.
|
||||
|
||||
TagLib 1.6 (Sep 13, 2009)
|
||||
=========================
|
||||
|
||||
1.6:
|
||||
|
||||
* New CMake option to build a static version - ENABLE_STATIC.
|
||||
* Added support for disabling dllimport/dllexport on Windows using the
|
||||
TAGLIB_STATIC macro.
|
||||
* Support for parsing the obsolete 'gnre' MP4 atom.
|
||||
* New cpp macros TAGLIB_WITH_MP4 and TAGLIB_WITH_ASF to determine if
|
||||
TagLib was built with MP4/ASF support.
|
||||
|
||||
1.6 RC1:
|
||||
|
||||
* Split Ogg packets larger than 64k into multiple pages. (BUG:171957)
|
||||
* TagLib can now use FLAC padding block. (BUG:107659)
|
||||
* ID3v2.2 frames are now not incorrectly saved. (BUG:176373)
|
||||
* Support for ID3v2.2 PIC frames. (BUG:167786)
|
||||
* Fixed a bug in ByteVectorList::split().
|
||||
* XiphComment::year() now falls back to YEAR if DATE doesn't exist
|
||||
and XiphComment::year() falls back to TRACKNUM if TRACKNUMBER doesn't
|
||||
exist. (BUG:144396)
|
||||
* Improved ID3v2.3 genre parsing. (BUG:188578)
|
||||
* Better checking of corrupted ID3v2 APIC data. (BUG:168382)
|
||||
* Bitrate calculating using the Xing header now uses floating point
|
||||
numbers. (BUG:172556)
|
||||
* New TagLib::String method rfind().
|
||||
* Added support for MP4 file format with iTunes-style metadata [optional].
|
||||
* Added support for ASF (WMA) file format [optional].
|
||||
* Fixed crash when saving a Locator APEv2 tag. (BUG:169810)
|
||||
* Fixed a possible crash in the non-const version of String::operator[]
|
||||
and in String::operator+=. (BUG:169389)
|
||||
* Added support for PRIV ID3v2 frames.
|
||||
* Empty ID3v2 genres are no longer treated as numeric ID3v1 genres.
|
||||
* Added support for the POPM (rating/playcount) ID3v2 frame.
|
||||
* Generic RIFF file format support:
|
||||
* Support for AIFF files with ID3v2 tags.
|
||||
* Support for WAV files with ID3v2 tags.
|
||||
* Fixed crash on handling unsupported ID3v2 frames, e.g. on encrypted
|
||||
frames. (BUG:161721)
|
||||
* Fixed overflow while calculating bitrate of FLAC files with a very
|
||||
high bitrate.
|
|
@ -1,26 +0,0 @@
|
|||
# TagLib
|
||||
|
||||
[](https://travis-ci.org/taglib/taglib)
|
||||
|
||||
### TagLib Audio Metadata Library
|
||||
|
||||
http://taglib.org/
|
||||
|
||||
TagLib is a library for reading and editing the metadata of several
|
||||
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.
|
||||
|
||||
TagLib is distributed under the [GNU Lesser General Public License][]
|
||||
(LGPL) and [Mozilla Public License][] (MPL). Essentially that means that
|
||||
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]: http://www.id3.org
|
||||
[Ogg Vorbis]: http://vorbis.com/
|
||||
[FLAC]: https://xiph.org/flac/
|
||||
[GNU Lesser General Public License]: http://www.gnu.org/licenses/lgpl.html
|
||||
[Mozilla Public License]: http://www.mozilla.org/MPL/MPL-1.1.html
|
||||
|
|
@ -1 +0,0 @@
|
|||
add_subdirectory(c)
|
|
@ -1,6 +0,0 @@
|
|||
There are a few other people that have done bindings externally that I have
|
||||
been made aware of. I have not personally reviewed these bindings, but I'm
|
||||
listing them here so that those who find them useful are able to find them:
|
||||
|
||||
http://developer.kde.org/~wheeler/taglib.html#bindings
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
include_directories(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/toolkit
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/asf
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/mpeg
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/ogg
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/ogg/vorbis
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/ogg/flac
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/flac
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/mpc
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/mp4
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/mpeg/id3v2
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/mpeg/id3v2/frames
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/wavpack
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/ogg/speex
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../taglib/trueaudio
|
||||
)
|
||||
|
||||
set(tag_c_HDRS tag_c.h)
|
||||
|
||||
add_library(tag_c tag_c.cpp ${tag_c_HDRS})
|
||||
|
||||
target_link_libraries(tag_c tag)
|
||||
set_target_properties(tag_c PROPERTIES
|
||||
PUBLIC_HEADER "${tag_c_HDRS}"
|
||||
DEFINE_SYMBOL MAKE_TAGLIB_LIB
|
||||
)
|
||||
if(VISIBILITY_HIDDEN)
|
||||
set_target_properties(tag_c PROPERTIES C_VISIBILITY_PRESET hidden
|
||||
)
|
||||
endif()
|
||||
if(BUILD_FRAMEWORK)
|
||||
set_target_properties(tag_c PROPERTIES FRAMEWORK TRUE)
|
||||
endif()
|
||||
|
||||
# On Solaris we need to explicitly add the C++ standard and runtime
|
||||
# libraries to the libs used by the C bindings, because those C bindings
|
||||
# themselves won't pull in the C++ libs -- and if a C application is
|
||||
# using the C bindings then we get link errors.
|
||||
check_library_exists(Crun __RTTI___ "" HAVE_CRUN_LIB)
|
||||
if(HAVE_CRUN_LIB)
|
||||
# Which libraries to link depends critically on which
|
||||
# STL version is going to be used by your application
|
||||
# and which runtime is in use. While Crun is pretty much
|
||||
# the only game in town, the three available STLs -- Cstd,
|
||||
# stlport4 and stdcxx -- make this a mess. The KDE-Solaris
|
||||
# team supports stdcxx (Apache RogueWave stdcxx 4.1.3).
|
||||
|
||||
# According to http://bugs.kde.org/show_bug.cgi?id=215225 the library can have the following two names:
|
||||
find_library(ROGUEWAVE_STDCXX_LIBRARY NAMES stdcxx4 stdcxx)
|
||||
if(NOT ROGUEWAVE_STDCXX_LIBRARY)
|
||||
message(FATAL_ERROR "Did not find supported STL library (tried stdcxx4 and stdcxx)")
|
||||
endif()
|
||||
target_link_libraries(tag_c ${ROGUEWAVE_STDCXX_LIBRARY} Crun)
|
||||
endif()
|
||||
|
||||
set_target_properties(tag_c PROPERTIES
|
||||
VERSION 0.0.0
|
||||
SOVERSION 0
|
||||
DEFINE_SYMBOL MAKE_TAGLIB_C_LIB
|
||||
INSTALL_NAME_DIR ${LIB_INSTALL_DIR}
|
||||
)
|
||||
install(TARGETS tag_c
|
||||
FRAMEWORK DESTINATION ${FRAMEWORK_INSTALL_DIR}
|
||||
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
|
||||
RUNTIME DESTINATION ${BIN_INSTALL_DIR}
|
||||
ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
|
||||
PUBLIC_HEADER DESTINATION ${INCLUDE_INSTALL_DIR}/taglib
|
||||
)
|
||||
|
||||
if(NOT BUILD_FRAMEWORK)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/taglib_c.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/taglib_c.pc)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/taglib_c.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
|
||||
endif()
|
||||
|
|
@ -1,315 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2003 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
* USA *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <fileref.h>
|
||||
#include <tfile.h>
|
||||
#include <asffile.h>
|
||||
#include <vorbisfile.h>
|
||||
#include <mpegfile.h>
|
||||
#include <flacfile.h>
|
||||
#include <oggflacfile.h>
|
||||
#include <mpcfile.h>
|
||||
#include <wavpackfile.h>
|
||||
#include <speexfile.h>
|
||||
#include <trueaudiofile.h>
|
||||
#include <mp4file.h>
|
||||
#include <tag.h>
|
||||
#include <string.h>
|
||||
#include <id3v2framefactory.h>
|
||||
|
||||
#include "tag_c.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
namespace
|
||||
{
|
||||
List<char *> strings;
|
||||
bool unicodeStrings = true;
|
||||
bool stringManagementEnabled = true;
|
||||
|
||||
char *stringToCharArray(const String &s)
|
||||
{
|
||||
const std::string str = s.to8Bit(unicodeStrings);
|
||||
|
||||
#ifdef HAVE_ISO_STRDUP
|
||||
|
||||
return ::_strdup(str.c_str());
|
||||
|
||||
#else
|
||||
|
||||
return ::strdup(str.c_str());
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
String charArrayToString(const char *s)
|
||||
{
|
||||
return String(s, unicodeStrings ? String::UTF8 : String::Latin1);
|
||||
}
|
||||
}
|
||||
|
||||
void taglib_set_strings_unicode(BOOL unicode)
|
||||
{
|
||||
unicodeStrings = (unicode != 0);
|
||||
}
|
||||
|
||||
void taglib_set_string_management_enabled(BOOL management)
|
||||
{
|
||||
stringManagementEnabled = (management != 0);
|
||||
}
|
||||
|
||||
void taglib_free(void* pointer)
|
||||
{
|
||||
free(pointer);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// TagLib::File wrapper
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TagLib_File *taglib_file_new(const char *filename)
|
||||
{
|
||||
return reinterpret_cast<TagLib_File *>(FileRef::create(filename));
|
||||
}
|
||||
|
||||
TagLib_File *taglib_file_new_type(const char *filename, TagLib_File_Type type)
|
||||
{
|
||||
switch(type) {
|
||||
case TagLib_File_MPEG:
|
||||
return reinterpret_cast<TagLib_File *>(new MPEG::File(filename));
|
||||
case TagLib_File_OggVorbis:
|
||||
return reinterpret_cast<TagLib_File *>(new Ogg::Vorbis::File(filename));
|
||||
case TagLib_File_FLAC:
|
||||
return reinterpret_cast<TagLib_File *>(new FLAC::File(filename));
|
||||
case TagLib_File_MPC:
|
||||
return reinterpret_cast<TagLib_File *>(new MPC::File(filename));
|
||||
case TagLib_File_OggFlac:
|
||||
return reinterpret_cast<TagLib_File *>(new Ogg::FLAC::File(filename));
|
||||
case TagLib_File_WavPack:
|
||||
return reinterpret_cast<TagLib_File *>(new WavPack::File(filename));
|
||||
case TagLib_File_Speex:
|
||||
return reinterpret_cast<TagLib_File *>(new Ogg::Speex::File(filename));
|
||||
case TagLib_File_TrueAudio:
|
||||
return reinterpret_cast<TagLib_File *>(new TrueAudio::File(filename));
|
||||
case TagLib_File_MP4:
|
||||
return reinterpret_cast<TagLib_File *>(new MP4::File(filename));
|
||||
case TagLib_File_ASF:
|
||||
return reinterpret_cast<TagLib_File *>(new ASF::File(filename));
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void taglib_file_free(TagLib_File *file)
|
||||
{
|
||||
delete reinterpret_cast<File *>(file);
|
||||
}
|
||||
|
||||
BOOL taglib_file_is_valid(const TagLib_File *file)
|
||||
{
|
||||
return reinterpret_cast<const File *>(file)->isValid();
|
||||
}
|
||||
|
||||
TagLib_Tag *taglib_file_tag(const TagLib_File *file)
|
||||
{
|
||||
const File *f = reinterpret_cast<const File *>(file);
|
||||
return reinterpret_cast<TagLib_Tag *>(f->tag());
|
||||
}
|
||||
|
||||
const TagLib_AudioProperties *taglib_file_audioproperties(const TagLib_File *file)
|
||||
{
|
||||
const File *f = reinterpret_cast<const File *>(file);
|
||||
return reinterpret_cast<const TagLib_AudioProperties *>(f->audioProperties());
|
||||
}
|
||||
|
||||
BOOL taglib_file_save(TagLib_File *file)
|
||||
{
|
||||
return reinterpret_cast<File *>(file)->save();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// TagLib::Tag wrapper
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char *taglib_tag_title(const TagLib_Tag *tag)
|
||||
{
|
||||
const Tag *t = reinterpret_cast<const Tag *>(tag);
|
||||
char *s = stringToCharArray(t->title());
|
||||
if(stringManagementEnabled)
|
||||
strings.append(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
char *taglib_tag_artist(const TagLib_Tag *tag)
|
||||
{
|
||||
const Tag *t = reinterpret_cast<const Tag *>(tag);
|
||||
char *s = stringToCharArray(t->artist());
|
||||
if(stringManagementEnabled)
|
||||
strings.append(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
char *taglib_tag_album(const TagLib_Tag *tag)
|
||||
{
|
||||
const Tag *t = reinterpret_cast<const Tag *>(tag);
|
||||
char *s = stringToCharArray(t->album());
|
||||
if(stringManagementEnabled)
|
||||
strings.append(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
char *taglib_tag_comment(const TagLib_Tag *tag)
|
||||
{
|
||||
const Tag *t = reinterpret_cast<const Tag *>(tag);
|
||||
char *s = stringToCharArray(t->comment());
|
||||
if(stringManagementEnabled)
|
||||
strings.append(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
char *taglib_tag_genre(const TagLib_Tag *tag)
|
||||
{
|
||||
const Tag *t = reinterpret_cast<const Tag *>(tag);
|
||||
char *s = stringToCharArray(t->genre());
|
||||
if(stringManagementEnabled)
|
||||
strings.append(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
unsigned int taglib_tag_year(const TagLib_Tag *tag)
|
||||
{
|
||||
const Tag *t = reinterpret_cast<const Tag *>(tag);
|
||||
return t->year();
|
||||
}
|
||||
|
||||
unsigned int taglib_tag_track(const TagLib_Tag *tag)
|
||||
{
|
||||
const Tag *t = reinterpret_cast<const Tag *>(tag);
|
||||
return t->track();
|
||||
}
|
||||
|
||||
void taglib_tag_set_title(TagLib_Tag *tag, const char *title)
|
||||
{
|
||||
Tag *t = reinterpret_cast<Tag *>(tag);
|
||||
t->setTitle(charArrayToString(title));
|
||||
}
|
||||
|
||||
void taglib_tag_set_artist(TagLib_Tag *tag, const char *artist)
|
||||
{
|
||||
Tag *t = reinterpret_cast<Tag *>(tag);
|
||||
t->setArtist(charArrayToString(artist));
|
||||
}
|
||||
|
||||
void taglib_tag_set_album(TagLib_Tag *tag, const char *album)
|
||||
{
|
||||
Tag *t = reinterpret_cast<Tag *>(tag);
|
||||
t->setAlbum(charArrayToString(album));
|
||||
}
|
||||
|
||||
void taglib_tag_set_comment(TagLib_Tag *tag, const char *comment)
|
||||
{
|
||||
Tag *t = reinterpret_cast<Tag *>(tag);
|
||||
t->setComment(charArrayToString(comment));
|
||||
}
|
||||
|
||||
void taglib_tag_set_genre(TagLib_Tag *tag, const char *genre)
|
||||
{
|
||||
Tag *t = reinterpret_cast<Tag *>(tag);
|
||||
t->setGenre(charArrayToString(genre));
|
||||
}
|
||||
|
||||
void taglib_tag_set_year(TagLib_Tag *tag, unsigned int year)
|
||||
{
|
||||
Tag *t = reinterpret_cast<Tag *>(tag);
|
||||
t->setYear(year);
|
||||
}
|
||||
|
||||
void taglib_tag_set_track(TagLib_Tag *tag, unsigned int track)
|
||||
{
|
||||
Tag *t = reinterpret_cast<Tag *>(tag);
|
||||
t->setTrack(track);
|
||||
}
|
||||
|
||||
void taglib_tag_free_strings()
|
||||
{
|
||||
if(!stringManagementEnabled)
|
||||
return;
|
||||
|
||||
for(List<char *>::ConstIterator it = strings.begin(); it != strings.end(); ++it)
|
||||
free(*it);
|
||||
strings.clear();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// TagLib::AudioProperties wrapper
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int taglib_audioproperties_length(const TagLib_AudioProperties *audioProperties)
|
||||
{
|
||||
const AudioProperties *p = reinterpret_cast<const AudioProperties *>(audioProperties);
|
||||
return p->length();
|
||||
}
|
||||
|
||||
int taglib_audioproperties_bitrate(const TagLib_AudioProperties *audioProperties)
|
||||
{
|
||||
const AudioProperties *p = reinterpret_cast<const AudioProperties *>(audioProperties);
|
||||
return p->bitrate();
|
||||
}
|
||||
|
||||
int taglib_audioproperties_samplerate(const TagLib_AudioProperties *audioProperties)
|
||||
{
|
||||
const AudioProperties *p = reinterpret_cast<const AudioProperties *>(audioProperties);
|
||||
return p->sampleRate();
|
||||
}
|
||||
|
||||
int taglib_audioproperties_channels(const TagLib_AudioProperties *audioProperties)
|
||||
{
|
||||
const AudioProperties *p = reinterpret_cast<const AudioProperties *>(audioProperties);
|
||||
return p->channels();
|
||||
}
|
||||
|
||||
void taglib_id3v2_set_default_text_encoding(TagLib_ID3v2_Encoding encoding)
|
||||
{
|
||||
String::Type type = String::Latin1;
|
||||
|
||||
switch(encoding)
|
||||
{
|
||||
case TagLib_ID3v2_Latin1:
|
||||
type = String::Latin1;
|
||||
break;
|
||||
case TagLib_ID3v2_UTF16:
|
||||
type = String::UTF16;
|
||||
break;
|
||||
case TagLib_ID3v2_UTF16BE:
|
||||
type = String::UTF16BE;
|
||||
break;
|
||||
case TagLib_ID3v2_UTF8:
|
||||
type = String::UTF8;
|
||||
break;
|
||||
}
|
||||
|
||||
ID3v2::FrameFactory::instance()->setDefaultTextEncoding(type);
|
||||
}
|
|
@ -1,299 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2003 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
* USA *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_TAG_C
|
||||
#define TAGLIB_TAG_C
|
||||
|
||||
/* Do not include this in the main TagLib documentation. */
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(TAGLIB_STATIC)
|
||||
#define TAGLIB_C_EXPORT
|
||||
#elif defined(_WIN32) || defined(_WIN64)
|
||||
#ifdef MAKE_TAGLIB_C_LIB
|
||||
#define TAGLIB_C_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define TAGLIB_C_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
#elif defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 1)
|
||||
#define TAGLIB_C_EXPORT __attribute__ ((visibility("default")))
|
||||
#else
|
||||
#define TAGLIB_C_EXPORT
|
||||
#endif
|
||||
|
||||
#ifndef BOOL
|
||||
#define BOOL int
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
* [ TagLib C Binding ]
|
||||
*
|
||||
* This is an interface to TagLib's "simple" API, meaning that you can read and
|
||||
* modify media files in a generic, but not specialized way. This is a rough
|
||||
* representation of TagLib::File and TagLib::Tag, for which the documentation
|
||||
* is somewhat more complete and worth consulting.
|
||||
*******************************************************************************/
|
||||
|
||||
/*
|
||||
* These are used for type provide some type safety to the C API (as opposed to
|
||||
* using void *, but pointers to them are simply cast to the corresponding C++
|
||||
* types in the implementation.
|
||||
*/
|
||||
|
||||
typedef struct { int dummy; } TagLib_File;
|
||||
typedef struct { int dummy; } TagLib_Tag;
|
||||
typedef struct { int dummy; } TagLib_AudioProperties;
|
||||
|
||||
/*!
|
||||
* By default all strings coming into or out of TagLib's C API are in UTF8.
|
||||
* However, it may be desirable for TagLib to operate on Latin1 (ISO-8859-1)
|
||||
* strings in which case this should be set to FALSE.
|
||||
*/
|
||||
TAGLIB_C_EXPORT void taglib_set_strings_unicode(BOOL unicode);
|
||||
|
||||
/*!
|
||||
* TagLib can keep track of strings that are created when outputting tag values
|
||||
* and clear them using taglib_tag_clear_strings(). This is enabled by default.
|
||||
* However if you wish to do more fine grained management of strings, you can do
|
||||
* so by setting \a management to FALSE.
|
||||
*/
|
||||
TAGLIB_C_EXPORT void taglib_set_string_management_enabled(BOOL management);
|
||||
|
||||
/*!
|
||||
* Explicitly free a string returned from TagLib
|
||||
*/
|
||||
TAGLIB_C_EXPORT void taglib_free(void* pointer);
|
||||
|
||||
/*******************************************************************************
|
||||
* File API
|
||||
******************************************************************************/
|
||||
|
||||
typedef enum {
|
||||
TagLib_File_MPEG,
|
||||
TagLib_File_OggVorbis,
|
||||
TagLib_File_FLAC,
|
||||
TagLib_File_MPC,
|
||||
TagLib_File_OggFlac,
|
||||
TagLib_File_WavPack,
|
||||
TagLib_File_Speex,
|
||||
TagLib_File_TrueAudio,
|
||||
TagLib_File_MP4,
|
||||
TagLib_File_ASF
|
||||
} TagLib_File_Type;
|
||||
|
||||
/*!
|
||||
* Creates a TagLib file based on \a filename. TagLib will try to guess the file
|
||||
* type.
|
||||
*
|
||||
* \returns NULL if the file type cannot be determined or the file cannot
|
||||
* be opened.
|
||||
*/
|
||||
TAGLIB_C_EXPORT TagLib_File *taglib_file_new(const char *filename);
|
||||
|
||||
/*!
|
||||
* Creates a TagLib file based on \a filename. Rather than attempting to guess
|
||||
* the type, it will use the one specified by \a type.
|
||||
*/
|
||||
TAGLIB_C_EXPORT TagLib_File *taglib_file_new_type(const char *filename, TagLib_File_Type type);
|
||||
|
||||
/*!
|
||||
* Frees and closes the file.
|
||||
*/
|
||||
TAGLIB_C_EXPORT void taglib_file_free(TagLib_File *file);
|
||||
|
||||
/*!
|
||||
* Returns true if the file is open and readable and valid information for
|
||||
* the Tag and / or AudioProperties was found.
|
||||
*/
|
||||
|
||||
TAGLIB_C_EXPORT BOOL taglib_file_is_valid(const TagLib_File *file);
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the tag associated with this file. This will be freed
|
||||
* automatically when the file is freed.
|
||||
*/
|
||||
TAGLIB_C_EXPORT TagLib_Tag *taglib_file_tag(const TagLib_File *file);
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the audio properties associated with this file. This
|
||||
* will be freed automatically when the file is freed.
|
||||
*/
|
||||
TAGLIB_C_EXPORT const TagLib_AudioProperties *taglib_file_audioproperties(const TagLib_File *file);
|
||||
|
||||
/*!
|
||||
* Saves the \a file to disk.
|
||||
*/
|
||||
TAGLIB_C_EXPORT BOOL taglib_file_save(TagLib_File *file);
|
||||
|
||||
/******************************************************************************
|
||||
* Tag API
|
||||
******************************************************************************/
|
||||
|
||||
/*!
|
||||
* Returns a string with this tag's title.
|
||||
*
|
||||
* \note By default this string should be UTF8 encoded and its memory should be
|
||||
* freed using taglib_tag_free_strings().
|
||||
*/
|
||||
TAGLIB_C_EXPORT char *taglib_tag_title(const TagLib_Tag *tag);
|
||||
|
||||
/*!
|
||||
* Returns a string with this tag's artist.
|
||||
*
|
||||
* \note By default this string should be UTF8 encoded and its memory should be
|
||||
* freed using taglib_tag_free_strings().
|
||||
*/
|
||||
TAGLIB_C_EXPORT char *taglib_tag_artist(const TagLib_Tag *tag);
|
||||
|
||||
/*!
|
||||
* Returns a string with this tag's album name.
|
||||
*
|
||||
* \note By default this string should be UTF8 encoded and its memory should be
|
||||
* freed using taglib_tag_free_strings().
|
||||
*/
|
||||
TAGLIB_C_EXPORT char *taglib_tag_album(const TagLib_Tag *tag);
|
||||
|
||||
/*!
|
||||
* Returns a string with this tag's comment.
|
||||
*
|
||||
* \note By default this string should be UTF8 encoded and its memory should be
|
||||
* freed using taglib_tag_free_strings().
|
||||
*/
|
||||
TAGLIB_C_EXPORT char *taglib_tag_comment(const TagLib_Tag *tag);
|
||||
|
||||
/*!
|
||||
* Returns a string with this tag's genre.
|
||||
*
|
||||
* \note By default this string should be UTF8 encoded and its memory should be
|
||||
* freed using taglib_tag_free_strings().
|
||||
*/
|
||||
TAGLIB_C_EXPORT char *taglib_tag_genre(const TagLib_Tag *tag);
|
||||
|
||||
/*!
|
||||
* Returns the tag's year or 0 if year is not set.
|
||||
*/
|
||||
TAGLIB_C_EXPORT unsigned int taglib_tag_year(const TagLib_Tag *tag);
|
||||
|
||||
/*!
|
||||
* Returns the tag's track number or 0 if track number is not set.
|
||||
*/
|
||||
TAGLIB_C_EXPORT unsigned int taglib_tag_track(const TagLib_Tag *tag);
|
||||
|
||||
/*!
|
||||
* Sets the tag's title.
|
||||
*
|
||||
* \note By default this string should be UTF8 encoded.
|
||||
*/
|
||||
TAGLIB_C_EXPORT void taglib_tag_set_title(TagLib_Tag *tag, const char *title);
|
||||
|
||||
/*!
|
||||
* Sets the tag's artist.
|
||||
*
|
||||
* \note By default this string should be UTF8 encoded.
|
||||
*/
|
||||
TAGLIB_C_EXPORT void taglib_tag_set_artist(TagLib_Tag *tag, const char *artist);
|
||||
|
||||
/*!
|
||||
* Sets the tag's album.
|
||||
*
|
||||
* \note By default this string should be UTF8 encoded.
|
||||
*/
|
||||
TAGLIB_C_EXPORT void taglib_tag_set_album(TagLib_Tag *tag, const char *album);
|
||||
|
||||
/*!
|
||||
* Sets the tag's comment.
|
||||
*
|
||||
* \note By default this string should be UTF8 encoded.
|
||||
*/
|
||||
TAGLIB_C_EXPORT void taglib_tag_set_comment(TagLib_Tag *tag, const char *comment);
|
||||
|
||||
/*!
|
||||
* Sets the tag's genre.
|
||||
*
|
||||
* \note By default this string should be UTF8 encoded.
|
||||
*/
|
||||
TAGLIB_C_EXPORT void taglib_tag_set_genre(TagLib_Tag *tag, const char *genre);
|
||||
|
||||
/*!
|
||||
* Sets the tag's year. 0 indicates that this field should be cleared.
|
||||
*/
|
||||
TAGLIB_C_EXPORT void taglib_tag_set_year(TagLib_Tag *tag, unsigned int year);
|
||||
|
||||
/*!
|
||||
* Sets the tag's track number. 0 indicates that this field should be cleared.
|
||||
*/
|
||||
TAGLIB_C_EXPORT void taglib_tag_set_track(TagLib_Tag *tag, unsigned int track);
|
||||
|
||||
/*!
|
||||
* Frees all of the strings that have been created by the tag.
|
||||
*/
|
||||
TAGLIB_C_EXPORT void taglib_tag_free_strings(void);
|
||||
|
||||
/******************************************************************************
|
||||
* Audio Properties API
|
||||
******************************************************************************/
|
||||
|
||||
/*!
|
||||
* Returns the length of the file in seconds.
|
||||
*/
|
||||
TAGLIB_C_EXPORT int taglib_audioproperties_length(const TagLib_AudioProperties *audioProperties);
|
||||
|
||||
/*!
|
||||
* Returns the bitrate of the file in kb/s.
|
||||
*/
|
||||
TAGLIB_C_EXPORT int taglib_audioproperties_bitrate(const TagLib_AudioProperties *audioProperties);
|
||||
|
||||
/*!
|
||||
* Returns the sample rate of the file in Hz.
|
||||
*/
|
||||
TAGLIB_C_EXPORT int taglib_audioproperties_samplerate(const TagLib_AudioProperties *audioProperties);
|
||||
|
||||
/*!
|
||||
* Returns the number of channels in the audio stream.
|
||||
*/
|
||||
TAGLIB_C_EXPORT int taglib_audioproperties_channels(const TagLib_AudioProperties *audioProperties);
|
||||
|
||||
/*******************************************************************************
|
||||
* Special convenience ID3v2 functions
|
||||
*******************************************************************************/
|
||||
|
||||
typedef enum {
|
||||
TagLib_ID3v2_Latin1,
|
||||
TagLib_ID3v2_UTF16,
|
||||
TagLib_ID3v2_UTF16BE,
|
||||
TagLib_ID3v2_UTF8
|
||||
} TagLib_ID3v2_Encoding;
|
||||
|
||||
/*!
|
||||
* This sets the default encoding for ID3v2 frames that are written to tags.
|
||||
*/
|
||||
|
||||
TAGLIB_C_EXPORT void taglib_id3v2_set_default_text_encoding(TagLib_ID3v2_Encoding encoding);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* DO_NOT_DOCUMENT */
|
||||
#endif
|
|
@ -1,12 +0,0 @@
|
|||
prefix=${CMAKE_INSTALL_PREFIX}
|
||||
exec_prefix=${CMAKE_INSTALL_PREFIX}
|
||||
libdir=${LIB_INSTALL_DIR}
|
||||
includedir=${INCLUDE_INSTALL_DIR}
|
||||
|
||||
|
||||
Name: TagLib C Bindings
|
||||
Description: Audio meta-data library (C bindings)
|
||||
Requires: taglib
|
||||
Version: ${TAGLIB_LIB_VERSION_STRING}
|
||||
Libs: -L${LIB_INSTALL_DIR} -ltag_c
|
||||
Cflags: -I${INCLUDE_INSTALL_DIR}/taglib
|
|
@ -1,69 +0,0 @@
|
|||
# - Try to find the libcppunit libraries
|
||||
# Once done this will define
|
||||
#
|
||||
# CppUnit_FOUND - system has libcppunit
|
||||
# CPPUNIT_INCLUDE_DIR - the libcppunit include directory
|
||||
# CPPUNIT_LIBRARIES - libcppunit library
|
||||
|
||||
include (MacroEnsureVersion)
|
||||
|
||||
if(NOT CPPUNIT_MIN_VERSION)
|
||||
SET(CPPUNIT_MIN_VERSION 1.12.0)
|
||||
endif(NOT CPPUNIT_MIN_VERSION)
|
||||
|
||||
FIND_PROGRAM(CPPUNIT_CONFIG_EXECUTABLE cppunit-config )
|
||||
|
||||
IF(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES)
|
||||
|
||||
# in cache already
|
||||
SET(CppUnit_FOUND TRUE)
|
||||
|
||||
ELSE(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES)
|
||||
|
||||
SET(CPPUNIT_INCLUDE_DIR)
|
||||
SET(CPPUNIT_LIBRARIES)
|
||||
|
||||
IF(CPPUNIT_CONFIG_EXECUTABLE)
|
||||
EXEC_PROGRAM(${CPPUNIT_CONFIG_EXECUTABLE} ARGS --cflags RETURN_VALUE _return_VALUE OUTPUT_VARIABLE CPPUNIT_CFLAGS)
|
||||
EXEC_PROGRAM(${CPPUNIT_CONFIG_EXECUTABLE} ARGS --libs RETURN_VALUE _return_VALUE OUTPUT_VARIABLE CPPUNIT_LIBRARIES)
|
||||
EXEC_PROGRAM(${CPPUNIT_CONFIG_EXECUTABLE} ARGS --version RETURN_VALUE _return_VALUE OUTPUT_VARIABLE CPPUNIT_INSTALLED_VERSION)
|
||||
STRING(REGEX REPLACE "-I(.+)" "\\1" CPPUNIT_CFLAGS "${CPPUNIT_CFLAGS}")
|
||||
ELSE(CPPUNIT_CONFIG_EXECUTABLE)
|
||||
# in case win32 needs to find it the old way?
|
||||
FIND_PATH(CPPUNIT_CFLAGS cppunit/TestRunner.h PATHS /usr/include /usr/local/include )
|
||||
FIND_LIBRARY(CPPUNIT_LIBRARIES NAMES cppunit PATHS /usr/lib /usr/local/lib )
|
||||
# how can we find cppunit version?
|
||||
MESSAGE (STATUS "Ensure you cppunit installed version is at least ${CPPUNIT_MIN_VERSION}")
|
||||
SET (CPPUNIT_INSTALLED_VERSION ${CPPUNIT_MIN_VERSION})
|
||||
ENDIF(CPPUNIT_CONFIG_EXECUTABLE)
|
||||
|
||||
SET(CPPUNIT_INCLUDE_DIR ${CPPUNIT_CFLAGS} "${CPPUNIT_CFLAGS}/cppunit")
|
||||
|
||||
ENDIF(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES)
|
||||
|
||||
IF(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES)
|
||||
|
||||
SET(CppUnit_FOUND TRUE)
|
||||
|
||||
if(NOT CppUnit_FIND_QUIETLY)
|
||||
MESSAGE (STATUS "Found cppunit: ${CPPUNIT_LIBRARIES}")
|
||||
endif(NOT CppUnit_FIND_QUIETLY)
|
||||
|
||||
IF(CPPUNIT_CONFIG_EXECUTABLE)
|
||||
EXEC_PROGRAM(${CPPUNIT_CONFIG_EXECUTABLE} ARGS --version RETURN_VALUE _return_VALUE OUTPUT_VARIABLE CPPUNIT_INSTALLED_VERSION)
|
||||
ENDIF(CPPUNIT_CONFIG_EXECUTABLE)
|
||||
|
||||
macro_ensure_version( ${CPPUNIT_MIN_VERSION} ${CPPUNIT_INSTALLED_VERSION} CPPUNIT_INSTALLED_VERSION_OK )
|
||||
|
||||
IF(NOT CPPUNIT_INSTALLED_VERSION_OK)
|
||||
MESSAGE ("** CppUnit version is too old: found ${CPPUNIT_INSTALLED_VERSION} installed, ${CPPUNIT_MIN_VERSION} or major is required")
|
||||
SET(CppUnit_FOUND FALSE)
|
||||
ENDIF(NOT CPPUNIT_INSTALLED_VERSION_OK)
|
||||
|
||||
ELSE(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES)
|
||||
|
||||
SET(CppUnit_FOUND FALSE CACHE BOOL "Not found cppunit library")
|
||||
|
||||
ENDIF(CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARIES)
|
||||
|
||||
MARK_AS_ADVANCED(CPPUNIT_INCLUDE_DIR CPPUNIT_LIBRARIES)
|
|
@ -1,71 +0,0 @@
|
|||
# This macro compares version numbers of the form "x.y.z"
|
||||
# MACRO_ENSURE_VERSION( FOO_MIN_VERSION FOO_VERSION_FOUND FOO_VERSION_OK)
|
||||
# will set FOO_VERSIN_OK to true if FOO_VERSION_FOUND >= FOO_MIN_VERSION
|
||||
# where both have to be in a 3-part-version format, leading and trailing
|
||||
# text is ok, e.g.
|
||||
# MACRO_ENSURE_VERSION( "2.5.31" "flex 2.5.4a" VERSION_OK)
|
||||
# which means 2.5.31 is required and "flex 2.5.4a" is what was found on the system
|
||||
|
||||
# Copyright (c) 2006, David Faure, <faure@kde.org>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
|
||||
MACRO(MACRO_ENSURE_VERSION requested_version found_version var_too_old)
|
||||
|
||||
# parse the parts of the version string
|
||||
STRING(REGEX REPLACE "([0-9]+)\\.[0-9]+\\.[0-9]+" "\\1" req_major_vers "${requested_version}")
|
||||
STRING(REGEX REPLACE "[0-9]+\\.([0-9]+)\\.[0-9]+" "\\1" req_minor_vers "${requested_version}")
|
||||
STRING(REGEX REPLACE "[0-9]+\\.[0-9]+\\.([0-9]+)" "\\1" req_patch_vers "${requested_version}")
|
||||
|
||||
STRING(REGEX REPLACE "[^0-9]*([0-9]+)\\.[0-9]+\\.[0-9]+.*" "\\1" found_major_vers "${found_version}")
|
||||
STRING(REGEX REPLACE "[^0-9]*[0-9]+\\.([0-9]+)\\.[0-9]+.*" "\\1" found_minor_vers "${found_version}")
|
||||
STRING(REGEX REPLACE "[^0-9]*[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" found_patch_vers "${found_version}")
|
||||
|
||||
# compute an overall version number which can be compared at once
|
||||
MATH(EXPR req_vers_num "${req_major_vers}*10000 + ${req_minor_vers}*100 + ${req_patch_vers}")
|
||||
MATH(EXPR found_vers_num "${found_major_vers}*10000 + ${found_minor_vers}*100 + ${found_patch_vers}")
|
||||
|
||||
if (found_vers_num LESS req_vers_num)
|
||||
set( ${var_too_old} FALSE )
|
||||
else (found_vers_num LESS req_vers_num)
|
||||
set( ${var_too_old} TRUE )
|
||||
endif (found_vers_num LESS req_vers_num)
|
||||
|
||||
ENDMACRO(MACRO_ENSURE_VERSION)
|
||||
|
||||
|
||||
# This macro compares version numbers of the form "x.y"
|
||||
# MACRO_ENSURE_VERSION( FOO_MIN_VERSION FOO_VERSION_FOUND FOO_VERSION_OK)
|
||||
# will set FOO_VERSIN_OK to true if FOO_VERSION_FOUND >= FOO_MIN_VERSION
|
||||
# where both have to be in a 2-part-version format, leading and trailing
|
||||
# text is ok, e.g.
|
||||
# MACRO_ENSURE_VERSION( "0.5" "foo 0.6" VERSION_OK)
|
||||
# which means 0.5 is required and "foo 0.6" is what was found on the system
|
||||
|
||||
# Copyright (c) 2006, David Faure, <faure@kde.org>
|
||||
# Copyright (c) 2007, Pino Toscano, <pino@kde.org>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
|
||||
MACRO(MACRO_ENSURE_VERSION2 requested_version found_version var_too_old)
|
||||
|
||||
# parse the parts of the version string
|
||||
STRING(REGEX REPLACE "([0-9]+)\\.[0-9]+" "\\1" req_major_vers "${requested_version}")
|
||||
STRING(REGEX REPLACE "[0-9]+\\.([0-9]+)" "\\1" req_minor_vers "${requested_version}")
|
||||
|
||||
STRING(REGEX REPLACE "[^0-9]*([0-9]+)\\.[0-9]+.*" "\\1" found_major_vers "${found_version}")
|
||||
STRING(REGEX REPLACE "[^0-9]*[0-9]+\\.([0-9]+).*" "\\1" found_minor_vers "${found_version}")
|
||||
|
||||
# compute an overall version number which can be compared at once
|
||||
MATH(EXPR req_vers_num "${req_major_vers}*100 + ${req_minor_vers}")
|
||||
MATH(EXPR found_vers_num "${found_major_vers}*100 + ${found_minor_vers}")
|
||||
|
||||
if (found_vers_num LESS req_vers_num)
|
||||
set( ${var_too_old} FALSE )
|
||||
else (found_vers_num LESS req_vers_num)
|
||||
set( ${var_too_old} TRUE )
|
||||
endif (found_vers_num LESS req_vers_num)
|
||||
|
||||
ENDMACRO(MACRO_ENSURE_VERSION2)
|
|
@ -1,21 +0,0 @@
|
|||
if (NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
|
||||
message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"")
|
||||
endif()
|
||||
|
||||
file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
|
||||
string(REGEX REPLACE "\n" ";" files "${files}")
|
||||
foreach (file ${files})
|
||||
message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"")
|
||||
if (EXISTS "$ENV{DESTDIR}${file}")
|
||||
execute_process(
|
||||
COMMAND @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}"
|
||||
OUTPUT_VARIABLE rm_out
|
||||
RESULT_VARIABLE rm_retval
|
||||
)
|
||||
if(NOT ${rm_retval} EQUAL 0)
|
||||
message(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"")
|
||||
endif ()
|
||||
else ()
|
||||
message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.")
|
||||
endif ()
|
||||
endforeach()
|
|
@ -1,34 +0,0 @@
|
|||
/* config.h. Generated by cmake from config.h.cmake */
|
||||
|
||||
#ifndef TAGLIB_CONFIG_H
|
||||
#define TAGLIB_CONFIG_H
|
||||
|
||||
/* Defined if your compiler supports some byte swap functions */
|
||||
#define HAVE_GCC_BYTESWAP 1
|
||||
/* #undef HAVE_GLIBC_BYTESWAP */
|
||||
/* #undef HAVE_MSC_BYTESWAP */
|
||||
/* #undef HAVE_MAC_BYTESWAP */
|
||||
/* #undef HAVE_OPENBSD_BYTESWAP */
|
||||
|
||||
/* Defined if your compiler supports some atomic operations */
|
||||
#define HAVE_GCC_ATOMIC 1
|
||||
/* #undef HAVE_MAC_ATOMIC */
|
||||
/* #undef HAVE_WIN_ATOMIC */
|
||||
/* #undef HAVE_IA64_ATOMIC */
|
||||
|
||||
/* Defined if your compiler supports some safer version of vsprintf */
|
||||
#define HAVE_VSNPRINTF 1
|
||||
/* #undef HAVE_VSPRINTF_S */
|
||||
|
||||
/* Defined if your compiler supports ISO _strdup */
|
||||
/* #undef HAVE_ISO_STRDUP */
|
||||
|
||||
/* Defined if zlib is installed */
|
||||
#define HAVE_ZLIB 1
|
||||
|
||||
/* Indicates whether debug messages are shown even in release mode */
|
||||
/* #undef TRACE_IN_RELEASE */
|
||||
|
||||
#define TESTS_DIR "/Users/nevack/work/taglib/tests/"
|
||||
|
||||
#endif
|
|
@ -1,34 +0,0 @@
|
|||
/* config.h. Generated by cmake from config.h.cmake */
|
||||
|
||||
#ifndef TAGLIB_CONFIG_H
|
||||
#define TAGLIB_CONFIG_H
|
||||
|
||||
/* Defined if your compiler supports some byte swap functions */
|
||||
#cmakedefine HAVE_GCC_BYTESWAP 1
|
||||
#cmakedefine HAVE_GLIBC_BYTESWAP 1
|
||||
#cmakedefine HAVE_MSC_BYTESWAP 1
|
||||
#cmakedefine HAVE_MAC_BYTESWAP 1
|
||||
#cmakedefine HAVE_OPENBSD_BYTESWAP 1
|
||||
|
||||
/* Defined if your compiler supports some atomic operations */
|
||||
#cmakedefine HAVE_GCC_ATOMIC 1
|
||||
#cmakedefine HAVE_MAC_ATOMIC 1
|
||||
#cmakedefine HAVE_WIN_ATOMIC 1
|
||||
#cmakedefine HAVE_IA64_ATOMIC 1
|
||||
|
||||
/* Defined if your compiler supports some safer version of vsprintf */
|
||||
#cmakedefine HAVE_VSNPRINTF 1
|
||||
#cmakedefine HAVE_VSPRINTF_S 1
|
||||
|
||||
/* Defined if your compiler supports ISO _strdup */
|
||||
#cmakedefine HAVE_ISO_STRDUP 1
|
||||
|
||||
/* Defined if zlib is installed */
|
||||
#cmakedefine HAVE_ZLIB 1
|
||||
|
||||
/* Indicates whether debug messages are shown even in release mode */
|
||||
#cmakedefine TRACE_IN_RELEASE 1
|
||||
|
||||
#cmakedefine TESTS_DIR "@TESTS_DIR@"
|
||||
|
||||
#endif
|
|
@ -1 +0,0 @@
|
|||
Run "make docs" in the parent directory to generate the TagLib API documentation.
|
|
@ -1,4 +0,0 @@
|
|||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,41 +0,0 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>$title ($projectname)</title>
|
||||
<link href="taglib-api.css" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
<div id="container">
|
||||
|
||||
<table border="0" width="100%">
|
||||
<tr>
|
||||
<td width="1">
|
||||
<img src="../taglib.png">
|
||||
</td>
|
||||
<td>
|
||||
<div id="intro">
|
||||
<table border="0" height="119" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tr><td valign="top"><h1>TagLib $projectnumber ($title)</h1></td></tr>
|
||||
<tr>
|
||||
<td valign="bottom">
|
||||
<div id="links">
|
||||
<a href="index.html">Home</a>
|
||||
<a href="inherits.html">Class Hierarchy</a>
|
||||
<a href="namespaces.html">Namespaces</a>
|
||||
<a href="annotated.html">Classes</a>
|
||||
<a href="files.html">Headers</a>
|
||||
<a href="namespacemembers.html">Namespace Members</a>
|
||||
<a href="functions.html">Class Members</a>
|
||||
<a href="globals.html">File Members</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div id="text">
|
|
@ -1,395 +0,0 @@
|
|||
body {
|
||||
font-family: sans-serif;
|
||||
background: white;
|
||||
color: black;
|
||||
margin: 0px;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
a:link {
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
color: gray;
|
||||
}
|
||||
|
||||
a:visited {
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
color: gray;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #cccccc;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a:active {
|
||||
color: #cccccc;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
img {
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
/* container */
|
||||
|
||||
#container {
|
||||
position: absolute;
|
||||
border-width: thin;
|
||||
border-style: solid;
|
||||
width: 95%;
|
||||
}
|
||||
|
||||
/* intro */
|
||||
|
||||
#intro {
|
||||
padding: 5px;
|
||||
margin: 0px;
|
||||
background: #cccccc;
|
||||
border-width: medium;
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
#intro h1 {
|
||||
margin: 5px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
/* links */
|
||||
|
||||
#links {
|
||||
font-size: x-small;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
#links a {
|
||||
border-width: thin;
|
||||
border-style: dotted;
|
||||
border-color: white;
|
||||
/* margin: 0px 10px 0px 0px; */
|
||||
margin: 1px;
|
||||
padding: 3px;
|
||||
line-height: 230%
|
||||
}
|
||||
|
||||
#links a:hover {
|
||||
color: black;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#links h3 {
|
||||
outline-width: thin;
|
||||
border-style: solid;
|
||||
padding: 2px;
|
||||
margin: 3px 0px 3px 0px;
|
||||
}
|
||||
|
||||
/* menu */
|
||||
|
||||
#menu h3 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* text */
|
||||
|
||||
#text {
|
||||
margin: 0px;
|
||||
padding: 5px 5px 0px 5px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
#text h3 {
|
||||
border-width: thin;
|
||||
border-style: solid;
|
||||
padding: 2px;
|
||||
margin: 3px 0px 3px 0px;
|
||||
}
|
||||
|
||||
#text li {
|
||||
margin: 0px 0px 10px 0px;
|
||||
}
|
||||
|
||||
#text ul {
|
||||
margin: 5px;
|
||||
padding: 0px 0px 0px 20px;
|
||||
}
|
||||
|
||||
#leftcolumn {
|
||||
float: left;
|
||||
width: 300px;
|
||||
margin: 0px 10px 0px 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
#rightcolumn {
|
||||
float: right;
|
||||
width: 210px;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
/* vspacer */
|
||||
|
||||
.vspacer {
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
.silver {
|
||||
border-width: thin;
|
||||
border-color: black;
|
||||
border-style: solid;
|
||||
background: #cccccc;
|
||||
}
|
||||
|
||||
a.code {
|
||||
text-decoration: none;
|
||||
font-weight: normal;
|
||||
color: #4444ee
|
||||
}
|
||||
|
||||
a.codeRef {
|
||||
font-weight: normal;
|
||||
color: #4444ee
|
||||
}
|
||||
|
||||
div.fragment {
|
||||
width: 98%;
|
||||
border: 1px solid #CCCCCC;
|
||||
background-color: #f5f5f5;
|
||||
padding-left: 4px;
|
||||
margin: 4px;
|
||||
}
|
||||
|
||||
div.ah {
|
||||
background-color: black;
|
||||
font-weight: bold; color: #ffffff;
|
||||
margin-bottom: 3px;
|
||||
margin-top: 3px
|
||||
}
|
||||
|
||||
#text td {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
div.memdoc {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 20px;
|
||||
padding: 10px 10px 10px 40px;
|
||||
}
|
||||
|
||||
div.memproto {
|
||||
border: thin solid black;
|
||||
background-color: #f2f2ff;
|
||||
width: 100%;
|
||||
margin-top: 20px;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
td.paramtype {
|
||||
color: #602020;
|
||||
}
|
||||
|
||||
table.memname {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.groupHeader {
|
||||
margin-left: 16px;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 6px;
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
div.groupText {
|
||||
margin-left: 16px;
|
||||
font-style: italic;
|
||||
font-size: smaller
|
||||
}
|
||||
|
||||
body {
|
||||
background: white;
|
||||
color: black;
|
||||
margin-right: 20px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
td.indexkey {
|
||||
background-color: #eeeeff;
|
||||
font-weight: bold;
|
||||
padding-right : 10px;
|
||||
padding-top : 2px;
|
||||
padding-left : 10px;
|
||||
padding-bottom : 2px;
|
||||
margin-left : 0px;
|
||||
margin-right : 0px;
|
||||
margin-top : 2px;
|
||||
margin-bottom : 2px
|
||||
}
|
||||
|
||||
td.indexvalue {
|
||||
background-color: #eeeeff;
|
||||
font-style: italic;
|
||||
padding-right : 10px;
|
||||
padding-top : 2px;
|
||||
padding-left : 10px;
|
||||
padding-bottom : 2px;
|
||||
margin-left : 0px;
|
||||
margin-right : 0px;
|
||||
margin-top : 2px;
|
||||
margin-bottom : 2px
|
||||
}
|
||||
|
||||
tr.memlist {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
p.formulaDsp {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
img.formulaDsp {
|
||||
|
||||
}
|
||||
|
||||
img.formulaInl {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
span.keyword {
|
||||
color: #008000
|
||||
}
|
||||
|
||||
span.keywordtype {
|
||||
color: #604020
|
||||
}
|
||||
|
||||
span.keywordflow {
|
||||
color: #e08000
|
||||
}
|
||||
|
||||
span.comment {
|
||||
color: #800000
|
||||
}
|
||||
|
||||
span.preprocessor {
|
||||
color: #806020
|
||||
}
|
||||
|
||||
span.stringliteral {
|
||||
color: #002080
|
||||
}
|
||||
|
||||
span.charliteral {
|
||||
color: #008080
|
||||
}
|
||||
|
||||
.mdTable {
|
||||
border: 1px solid #868686;
|
||||
background-color: #f2f2ff;
|
||||
}
|
||||
|
||||
.mdRow {
|
||||
padding: 8px 20px;
|
||||
}
|
||||
|
||||
.mdescLeft {
|
||||
font-size: smaller;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
background-color: #FAFAFA;
|
||||
padding-left: 8px;
|
||||
border-top: 1px none #E0E0E0;
|
||||
border-right: 1px none #E0E0E0;
|
||||
border-bottom: 1px none #E0E0E0;
|
||||
border-left: 1px none #E0E0E0;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.mdescRight {
|
||||
font-size: smaller;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-style: italic;
|
||||
background-color: #FAFAFA;
|
||||
padding-left: 4px;
|
||||
border-top: 1px none #E0E0E0;
|
||||
border-right: 1px none #E0E0E0;
|
||||
border-bottom: 1px none #E0E0E0;
|
||||
border-left: 1px none #E0E0E0;
|
||||
margin: 0px;
|
||||
padding-bottom: 0px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.memItemLeft {
|
||||
padding: 1px 0px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-style: solid;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
background-color: #FAFAFA;
|
||||
font-family: Geneva, Arial, Helvetica, sans-serif;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.memItemRight {
|
||||
padding: 1px 0px 0px 8px;
|
||||
margin: 4px;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
border-top-style: solid;
|
||||
border-top-color: #E0E0E0;
|
||||
border-right-color: #E0E0E0;
|
||||
border-bottom-color: #E0E0E0;
|
||||
border-left-color: #E0E0E0;
|
||||
border-right-style: none;
|
||||
border-bottom-style: none;
|
||||
border-left-style: none;
|
||||
background-color: #FAFAFA;
|
||||
font-family: Geneva, Arial, Helvetica, sans-serif;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.search {
|
||||
color: #0000ee;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
form.search {
|
||||
margin-bottom: 0px;
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
input.search {
|
||||
font-size: 75%;
|
||||
color: #000080;
|
||||
font-weight: normal;
|
||||
background-color: #eeeeff;
|
||||
}
|
||||
|
||||
td.tiny {
|
||||
font-size: 75%;
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 2.7 KiB |
|
@ -1,40 +0,0 @@
|
|||
include_directories(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../taglib
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/toolkit
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/ape
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../taglib/mpeg
|
||||
${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}/../bindings/c/
|
||||
)
|
||||
|
||||
if(NOT BUILD_SHARED_LIBS)
|
||||
add_definitions(-DTAGLIB_STATIC)
|
||||
endif()
|
||||
|
||||
########### next target ###############
|
||||
|
||||
add_executable(tagreader tagreader.cpp)
|
||||
target_link_libraries(tagreader tag)
|
||||
|
||||
########### next target ###############
|
||||
|
||||
add_executable(tagreader_c tagreader_c.c)
|
||||
target_link_libraries(tagreader_c tag_c)
|
||||
|
||||
########### next target ###############
|
||||
|
||||
add_executable(tagwriter tagwriter.cpp)
|
||||
target_link_libraries(tagwriter tag)
|
||||
|
||||
########### next target ###############
|
||||
|
||||
add_executable(framelist framelist.cpp)
|
||||
target_link_libraries(framelist tag)
|
||||
|
||||
########### next target ###############
|
||||
|
||||
add_executable(strip-id3v1 strip-id3v1.cpp)
|
||||
target_link_libraries(strip-id3v1 tag)
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
/* Copyright (C) 2003 Scott Wheeler <wheeler@kde.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <tbytevector.h>
|
||||
|
||||
#include <mpegfile.h>
|
||||
|
||||
#include <id3v2tag.h>
|
||||
#include <id3v2frame.h>
|
||||
#include <id3v2header.h>
|
||||
#include <commentsframe.h>
|
||||
|
||||
#include <id3v1tag.h>
|
||||
|
||||
#include <apetag.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace TagLib;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// process the command line args
|
||||
|
||||
|
||||
for(int i = 1; i < argc; i++) {
|
||||
|
||||
cout << "******************** \"" << argv[i] << "\"********************" << endl;
|
||||
|
||||
MPEG::File f(argv[i]);
|
||||
|
||||
ID3v2::Tag *id3v2tag = f.ID3v2Tag();
|
||||
|
||||
if(id3v2tag) {
|
||||
|
||||
cout << "ID3v2."
|
||||
<< id3v2tag->header()->majorVersion()
|
||||
<< "."
|
||||
<< id3v2tag->header()->revisionNumber()
|
||||
<< ", "
|
||||
<< id3v2tag->header()->tagSize()
|
||||
<< " bytes in tag"
|
||||
<< endl;
|
||||
|
||||
ID3v2::FrameList::ConstIterator it = id3v2tag->frameList().begin();
|
||||
for(; it != id3v2tag->frameList().end(); it++) {
|
||||
cout << (*it)->frameID();
|
||||
|
||||
if(ID3v2::CommentsFrame *comment = dynamic_cast<ID3v2::CommentsFrame *>(*it))
|
||||
if(!comment->description().isEmpty())
|
||||
cout << " [" << comment->description() << "]";
|
||||
|
||||
cout << " - \"" << (*it)->toString() << "\"" << endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
cout << "file does not have a valid id3v2 tag" << endl;
|
||||
|
||||
cout << endl << "ID3v1" << endl;
|
||||
|
||||
ID3v1::Tag *id3v1tag = f.ID3v1Tag();
|
||||
|
||||
if(id3v1tag) {
|
||||
cout << "title - \"" << id3v1tag->title() << "\"" << endl;
|
||||
cout << "artist - \"" << id3v1tag->artist() << "\"" << endl;
|
||||
cout << "album - \"" << id3v1tag->album() << "\"" << endl;
|
||||
cout << "year - \"" << id3v1tag->year() << "\"" << endl;
|
||||
cout << "comment - \"" << id3v1tag->comment() << "\"" << endl;
|
||||
cout << "track - \"" << id3v1tag->track() << "\"" << endl;
|
||||
cout << "genre - \"" << id3v1tag->genre() << "\"" << endl;
|
||||
}
|
||||
else
|
||||
cout << "file does not have a valid id3v1 tag" << endl;
|
||||
|
||||
APE::Tag *ape = f.APETag();
|
||||
|
||||
cout << endl << "APE" << endl;
|
||||
|
||||
if(ape) {
|
||||
for(APE::ItemListMap::ConstIterator it = ape->itemListMap().begin();
|
||||
it != ape->itemListMap().end(); ++it)
|
||||
{
|
||||
if((*it).second.type() != APE::Item::Binary)
|
||||
cout << (*it).first << " - \"" << (*it).second.toString() << "\"" << endl;
|
||||
else
|
||||
cout << (*it).first << " - Binary data (" << (*it).second.binaryData().size() << " bytes)" << endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
cout << "file does not have a valid APE tag" << endl;
|
||||
|
||||
cout << endl;
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
/* Copyright (C) 2003 Scott Wheeler <wheeler@kde.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <mpegfile.h>
|
||||
#include <tstring.h>
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
for(int i = 1; i < argc; i++) {
|
||||
|
||||
std::cout << "******************** Stripping ID3v1 Tag From: \"" << argv[i] << "\"********************" << std::endl;
|
||||
|
||||
MPEG::File f(argv[i]);
|
||||
f.strip(MPEG::File::ID3v1);
|
||||
}
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
/* Copyright (C) 2003 Scott Wheeler <wheeler@kde.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <fileref.h>
|
||||
#include <tag.h>
|
||||
#include <tpropertymap.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
for(int i = 1; i < argc; i++) {
|
||||
|
||||
cout << "******************** \"" << argv[i] << "\" ********************" << endl;
|
||||
|
||||
TagLib::FileRef f(argv[i]);
|
||||
|
||||
if(!f.isNull() && f.tag()) {
|
||||
|
||||
TagLib::Tag *tag = f.tag();
|
||||
|
||||
cout << "-- TAG (basic) --" << endl;
|
||||
cout << "title - \"" << tag->title() << "\"" << endl;
|
||||
cout << "artist - \"" << tag->artist() << "\"" << endl;
|
||||
cout << "album - \"" << tag->album() << "\"" << endl;
|
||||
cout << "year - \"" << tag->year() << "\"" << endl;
|
||||
cout << "comment - \"" << tag->comment() << "\"" << endl;
|
||||
cout << "track - \"" << tag->track() << "\"" << endl;
|
||||
cout << "genre - \"" << tag->genre() << "\"" << endl;
|
||||
|
||||
TagLib::PropertyMap tags = f.file()->properties();
|
||||
|
||||
unsigned int longest = 0;
|
||||
for(TagLib::PropertyMap::ConstIterator i = tags.begin(); i != tags.end(); ++i) {
|
||||
if (i->first.size() > longest) {
|
||||
longest = i->first.size();
|
||||
}
|
||||
}
|
||||
|
||||
cout << "-- TAG (properties) --" << endl;
|
||||
for(TagLib::PropertyMap::ConstIterator i = tags.begin(); i != tags.end(); ++i) {
|
||||
for(TagLib::StringList::ConstIterator j = i->second.begin(); j != i->second.end(); ++j) {
|
||||
cout << left << std::setw(longest) << i->first << " - " << '"' << *j << '"' << endl;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(!f.isNull() && f.audioProperties()) {
|
||||
|
||||
TagLib::AudioProperties *properties = f.audioProperties();
|
||||
|
||||
int seconds = properties->length() % 60;
|
||||
int minutes = (properties->length() - seconds) / 60;
|
||||
|
||||
cout << "-- AUDIO --" << endl;
|
||||
cout << "bitrate - " << properties->bitrate() << endl;
|
||||
cout << "sample rate - " << properties->sampleRate() << endl;
|
||||
cout << "channels - " << properties->channels() << endl;
|
||||
cout << "length - " << minutes << ":" << setfill('0') << setw(2) << seconds << endl;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
/* Copyright (C) 2003 Scott Wheeler <wheeler@kde.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <tag_c.h>
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
int seconds;
|
||||
int minutes;
|
||||
TagLib_File *file;
|
||||
TagLib_Tag *tag;
|
||||
const TagLib_AudioProperties *properties;
|
||||
|
||||
taglib_set_strings_unicode(FALSE);
|
||||
|
||||
for(i = 1; i < argc; i++) {
|
||||
printf("******************** \"%s\" ********************\n", argv[i]);
|
||||
|
||||
file = taglib_file_new(argv[i]);
|
||||
|
||||
if(file == NULL)
|
||||
break;
|
||||
|
||||
tag = taglib_file_tag(file);
|
||||
properties = taglib_file_audioproperties(file);
|
||||
|
||||
if(tag != NULL) {
|
||||
printf("-- TAG --\n");
|
||||
printf("title - \"%s\"\n", taglib_tag_title(tag));
|
||||
printf("artist - \"%s\"\n", taglib_tag_artist(tag));
|
||||
printf("album - \"%s\"\n", taglib_tag_album(tag));
|
||||
printf("year - \"%i\"\n", taglib_tag_year(tag));
|
||||
printf("comment - \"%s\"\n", taglib_tag_comment(tag));
|
||||
printf("track - \"%i\"\n", taglib_tag_track(tag));
|
||||
printf("genre - \"%s\"\n", taglib_tag_genre(tag));
|
||||
}
|
||||
|
||||
if(properties != NULL) {
|
||||
seconds = taglib_audioproperties_length(properties) % 60;
|
||||
minutes = (taglib_audioproperties_length(properties) - seconds) / 60;
|
||||
|
||||
printf("-- AUDIO --\n");
|
||||
printf("bitrate - %i\n", taglib_audioproperties_bitrate(properties));
|
||||
printf("sample rate - %i\n", taglib_audioproperties_samplerate(properties));
|
||||
printf("channels - %i\n", taglib_audioproperties_channels(properties));
|
||||
printf("length - %i:%02i\n", minutes, seconds);
|
||||
}
|
||||
|
||||
taglib_tag_free_strings();
|
||||
taglib_file_free(file);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,185 +0,0 @@
|
|||
/* Copyright (C) 2004 Scott Wheeler <wheeler@kde.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <string.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <tlist.h>
|
||||
#include <fileref.h>
|
||||
#include <tfile.h>
|
||||
#include <tag.h>
|
||||
#include <tpropertymap.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
bool isArgument(const char *s)
|
||||
{
|
||||
return strlen(s) == 2 && s[0] == '-';
|
||||
}
|
||||
|
||||
bool isFile(const char *s)
|
||||
{
|
||||
struct stat st;
|
||||
#ifdef _WIN32
|
||||
return ::stat(s, &st) == 0 && (st.st_mode & (S_IFREG));
|
||||
#else
|
||||
return ::stat(s, &st) == 0 && (st.st_mode & (S_IFREG | S_IFLNK));
|
||||
#endif
|
||||
}
|
||||
|
||||
void usage()
|
||||
{
|
||||
cout << endl;
|
||||
cout << "Usage: tagwriter <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 << endl;
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void checkForRejectedProperties(const TagLib::PropertyMap &tags)
|
||||
{ // stolen from tagreader.cpp
|
||||
if(tags.size() > 0) {
|
||||
unsigned int longest = 0;
|
||||
for(TagLib::PropertyMap::ConstIterator i = tags.begin(); i != tags.end(); ++i) {
|
||||
if(i->first.size() > longest) {
|
||||
longest = i->first.size();
|
||||
}
|
||||
}
|
||||
cout << "-- rejected TAGs (properties) --" << endl;
|
||||
for(TagLib::PropertyMap::ConstIterator i = tags.begin(); i != tags.end(); ++i) {
|
||||
for(TagLib::StringList::ConstIterator j = i->second.begin(); j != i->second.end(); ++j) {
|
||||
cout << left << std::setw(longest) << i->first << " - " << '"' << *j << '"' << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
TagLib::List<TagLib::FileRef> fileList;
|
||||
|
||||
while(argc > 0 && isFile(argv[argc - 1])) {
|
||||
|
||||
TagLib::FileRef f(argv[argc - 1]);
|
||||
|
||||
if(!f.isNull() && f.tag())
|
||||
fileList.append(f);
|
||||
|
||||
argc--;
|
||||
}
|
||||
|
||||
if(fileList.isEmpty())
|
||||
usage();
|
||||
|
||||
for(int i = 1; i < argc - 1; i += 2) {
|
||||
|
||||
if(isArgument(argv[i]) && i + 1 < argc && !isArgument(argv[i + 1])) {
|
||||
|
||||
char field = argv[i][1];
|
||||
TagLib::String value = argv[i + 1];
|
||||
|
||||
TagLib::List<TagLib::FileRef>::ConstIterator it;
|
||||
for(it = fileList.begin(); it != fileList.end(); ++it) {
|
||||
|
||||
TagLib::Tag *t = (*it).tag();
|
||||
|
||||
switch (field) {
|
||||
case 't':
|
||||
t->setTitle(value);
|
||||
break;
|
||||
case 'a':
|
||||
t->setArtist(value);
|
||||
break;
|
||||
case 'A':
|
||||
t->setAlbum(value);
|
||||
break;
|
||||
case 'c':
|
||||
t->setComment(value);
|
||||
break;
|
||||
case 'g':
|
||||
t->setGenre(value);
|
||||
break;
|
||||
case 'y':
|
||||
t->setYear(value.toInt());
|
||||
break;
|
||||
case 'T':
|
||||
t->setTrack(value.toInt());
|
||||
break;
|
||||
case 'R':
|
||||
case 'I':
|
||||
if(i + 2 < argc) {
|
||||
TagLib::PropertyMap map = (*it).file()->properties ();
|
||||
if(field == 'R') {
|
||||
map.replace(value, TagLib::String(argv[i + 2]));
|
||||
}
|
||||
else {
|
||||
map.insert(value, TagLib::String(argv[i + 2]));
|
||||
}
|
||||
++i;
|
||||
checkForRejectedProperties((*it).file()->setProperties(map));
|
||||
}
|
||||
else {
|
||||
usage();
|
||||
}
|
||||
break;
|
||||
case 'D': {
|
||||
TagLib::PropertyMap map = (*it).file()->properties();
|
||||
map.erase(value);
|
||||
checkForRejectedProperties((*it).file()->setProperties(map));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
usage();
|
||||
}
|
||||
|
||||
TagLib::List<TagLib::FileRef>::ConstIterator it;
|
||||
for(it = fileList.begin(); it != fileList.end(); ++it)
|
||||
(*it).file()->save();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
usage()
|
||||
{
|
||||
echo "usage: $0 [OPTIONS]"
|
||||
cat << EOH
|
||||
|
||||
options:
|
||||
[--libs]
|
||||
[--cflags]
|
||||
[--version]
|
||||
[--prefix]
|
||||
EOH
|
||||
exit 1;
|
||||
}
|
||||
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
exec_prefix=@CMAKE_INSTALL_PREFIX@
|
||||
libdir=@LIB_INSTALL_DIR@
|
||||
includedir=@INCLUDE_INSTALL_DIR@
|
||||
|
||||
flags=""
|
||||
|
||||
if test $# -eq 0 ; then
|
||||
usage
|
||||
fi
|
||||
|
||||
while test $# -gt 0
|
||||
do
|
||||
case $1 in
|
||||
--libs)
|
||||
flags="$flags -L$libdir -ltag @ZLIB_LIBRARIES_FLAGS@"
|
||||
;;
|
||||
--cflags)
|
||||
flags="$flags -I$includedir -I$includedir/taglib"
|
||||
;;
|
||||
--version)
|
||||
echo @TAGLIB_LIB_VERSION_STRING@
|
||||
;;
|
||||
--prefix)
|
||||
echo $prefix
|
||||
;;
|
||||
*)
|
||||
echo "$0: unknown option $1"
|
||||
echo
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if test -n "$flags"
|
||||
then
|
||||
echo $flags
|
||||
fi
|
|
@ -1,36 +0,0 @@
|
|||
@echo off
|
||||
goto beginning
|
||||
*
|
||||
* It is what it is, you can do with it as you please.
|
||||
*
|
||||
* Just don't blame me if it teaches your computer to smoke!
|
||||
*
|
||||
* -Enjoy
|
||||
* fh :)_~
|
||||
*
|
||||
:beginning
|
||||
if /i "%1#" == "--libs#" goto doit
|
||||
if /i "%1#" == "--cflags#" goto doit
|
||||
if /i "%1#" == "--version#" goto doit
|
||||
if /i "%1#" == "--prefix#" goto doit
|
||||
|
||||
echo "usage: %0 [OPTIONS]"
|
||||
echo [--libs]
|
||||
echo [--cflags]
|
||||
echo [--version]
|
||||
echo [--prefix]
|
||||
goto theend
|
||||
|
||||
*
|
||||
* NOTE: Windows does not assume libraries are prefixed with 'lib'.
|
||||
* NOTE: If '-llibtag' is the last element, it is easily appended in the users installation/makefile process
|
||||
* to allow for static, shared or debug builds.
|
||||
* It would be preferable if the top level CMakeLists.txt provided the library name during config. ??
|
||||
:doit
|
||||
if /i "%1#" == "--libs#" echo -L${LIB_INSTALL_DIR} -llibtag
|
||||
if /i "%1#" == "--cflags#" echo -I${INCLUDE_INSTALL_DIR} -I${INCLUDE_INSTALL_DIR}/taglib
|
||||
if /i "%1#" == "--version#" echo ${TAGLIB_LIB_VERSION_STRING}
|
||||
if /i "%1#" == "--prefix#" echo ${CMAKE_INSTALL_PREFIX}
|
||||
|
||||
:theend
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
exec_prefix=@CMAKE_INSTALL_PREFIX@
|
||||
libdir=@LIB_INSTALL_DIR@
|
||||
includedir=@INCLUDE_INSTALL_DIR@
|
||||
|
||||
Name: TagLib
|
||||
Description: Audio meta-data library
|
||||
Requires:
|
||||
Version: @TAGLIB_LIB_VERSION_STRING@
|
||||
Libs: -L${libdir} -ltag @ZLIB_LIBRARIES_FLAGS@
|
||||
Cflags: -I${includedir} -I${includedir}/taglib
|
|
@ -1,372 +0,0 @@
|
|||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
include_directories(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/toolkit
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/asf
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/mpeg
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ogg
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ogg/flac
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/flac
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/mpc
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/mp4
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ogg/vorbis
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ogg/speex
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ogg/opus
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/mpeg/id3v2
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/mpeg/id3v2/frames
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/mpeg/id3v1
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ape
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wavpack
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/trueaudio
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/riff
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/riff/aiff
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/riff/wav
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/mod
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/s3m
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/it
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/xm
|
||||
${taglib_SOURCE_DIR}/3rdparty
|
||||
)
|
||||
|
||||
if(ZLIB_FOUND)
|
||||
include_directories(${ZLIB_INCLUDE_DIR})
|
||||
elseif(HAVE_ZLIB_SOURCE)
|
||||
include_directories(${ZLIB_SOURCE})
|
||||
endif()
|
||||
|
||||
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
|
||||
toolkit/tlist.tcc
|
||||
toolkit/tstringlist.h
|
||||
toolkit/tbytevector.h
|
||||
toolkit/tbytevectorlist.h
|
||||
toolkit/tbytevectorstream.h
|
||||
toolkit/tiostream.h
|
||||
toolkit/tfile.h
|
||||
toolkit/tfilestream.h
|
||||
toolkit/tmap.h
|
||||
toolkit/tmap.tcc
|
||||
toolkit/tpropertymap.h
|
||||
toolkit/trefcounter.h
|
||||
toolkit/tdebuglistener.h
|
||||
mpeg/mpegfile.h
|
||||
mpeg/mpegproperties.h
|
||||
mpeg/mpegheader.h
|
||||
mpeg/xingheader.h
|
||||
mpeg/id3v1/id3v1tag.h
|
||||
mpeg/id3v1/id3v1genres.h
|
||||
mpeg/id3v2/id3v2.h
|
||||
mpeg/id3v2/id3v2extendedheader.h
|
||||
mpeg/id3v2/id3v2frame.h
|
||||
mpeg/id3v2/id3v2header.h
|
||||
mpeg/id3v2/id3v2synchdata.h
|
||||
mpeg/id3v2/id3v2footer.h
|
||||
mpeg/id3v2/id3v2framefactory.h
|
||||
mpeg/id3v2/id3v2tag.h
|
||||
mpeg/id3v2/frames/attachedpictureframe.h
|
||||
mpeg/id3v2/frames/commentsframe.h
|
||||
mpeg/id3v2/frames/eventtimingcodesframe.h
|
||||
mpeg/id3v2/frames/generalencapsulatedobjectframe.h
|
||||
mpeg/id3v2/frames/ownershipframe.h
|
||||
mpeg/id3v2/frames/popularimeterframe.h
|
||||
mpeg/id3v2/frames/privateframe.h
|
||||
mpeg/id3v2/frames/relativevolumeframe.h
|
||||
mpeg/id3v2/frames/synchronizedlyricsframe.h
|
||||
mpeg/id3v2/frames/textidentificationframe.h
|
||||
mpeg/id3v2/frames/uniquefileidentifierframe.h
|
||||
mpeg/id3v2/frames/unknownframe.h
|
||||
mpeg/id3v2/frames/unsynchronizedlyricsframe.h
|
||||
mpeg/id3v2/frames/urllinkframe.h
|
||||
mpeg/id3v2/frames/chapterframe.h
|
||||
mpeg/id3v2/frames/tableofcontentsframe.h
|
||||
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
|
||||
mod/modfilebase.h
|
||||
mod/modfile.h
|
||||
mod/modtag.h
|
||||
mod/modproperties.h
|
||||
it/itfile.h
|
||||
it/itproperties.h
|
||||
s3m/s3mfile.h
|
||||
s3m/s3mproperties.h
|
||||
xm/xmfile.h
|
||||
xm/xmproperties.h
|
||||
)
|
||||
|
||||
set(mpeg_SRCS
|
||||
mpeg/mpegfile.cpp
|
||||
mpeg/mpegproperties.cpp
|
||||
mpeg/mpegheader.cpp
|
||||
mpeg/xingheader.cpp
|
||||
)
|
||||
|
||||
set(id3v1_SRCS
|
||||
mpeg/id3v1/id3v1tag.cpp
|
||||
mpeg/id3v1/id3v1genres.cpp
|
||||
)
|
||||
|
||||
set(id3v2_SRCS
|
||||
mpeg/id3v2/id3v2framefactory.cpp
|
||||
mpeg/id3v2/id3v2synchdata.cpp
|
||||
mpeg/id3v2/id3v2tag.cpp
|
||||
mpeg/id3v2/id3v2header.cpp
|
||||
mpeg/id3v2/id3v2frame.cpp
|
||||
mpeg/id3v2/id3v2footer.cpp
|
||||
mpeg/id3v2/id3v2extendedheader.cpp
|
||||
)
|
||||
|
||||
set(frames_SRCS
|
||||
mpeg/id3v2/frames/attachedpictureframe.cpp
|
||||
mpeg/id3v2/frames/commentsframe.cpp
|
||||
mpeg/id3v2/frames/eventtimingcodesframe.cpp
|
||||
mpeg/id3v2/frames/generalencapsulatedobjectframe.cpp
|
||||
mpeg/id3v2/frames/ownershipframe.cpp
|
||||
mpeg/id3v2/frames/popularimeterframe.cpp
|
||||
mpeg/id3v2/frames/privateframe.cpp
|
||||
mpeg/id3v2/frames/relativevolumeframe.cpp
|
||||
mpeg/id3v2/frames/synchronizedlyricsframe.cpp
|
||||
mpeg/id3v2/frames/textidentificationframe.cpp
|
||||
mpeg/id3v2/frames/uniquefileidentifierframe.cpp
|
||||
mpeg/id3v2/frames/unknownframe.cpp
|
||||
mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp
|
||||
mpeg/id3v2/frames/urllinkframe.cpp
|
||||
mpeg/id3v2/frames/chapterframe.cpp
|
||||
mpeg/id3v2/frames/tableofcontentsframe.cpp
|
||||
mpeg/id3v2/frames/podcastframe.cpp
|
||||
)
|
||||
|
||||
set(ogg_SRCS
|
||||
ogg/oggfile.cpp
|
||||
ogg/oggpage.cpp
|
||||
ogg/oggpageheader.cpp
|
||||
ogg/xiphcomment.cpp
|
||||
)
|
||||
|
||||
set(vorbis_SRCS
|
||||
ogg/vorbis/vorbisfile.cpp
|
||||
ogg/vorbis/vorbisproperties.cpp
|
||||
)
|
||||
|
||||
set(flacs_SRCS
|
||||
flac/flacfile.cpp
|
||||
flac/flacpicture.cpp
|
||||
flac/flacproperties.cpp
|
||||
flac/flacmetadatablock.cpp
|
||||
flac/flacunknownmetadatablock.cpp
|
||||
)
|
||||
|
||||
set(oggflacs_SRCS
|
||||
ogg/flac/oggflacfile.cpp
|
||||
)
|
||||
|
||||
set(mpc_SRCS
|
||||
mpc/mpcfile.cpp
|
||||
mpc/mpcproperties.cpp
|
||||
)
|
||||
|
||||
set(mp4_SRCS
|
||||
mp4/mp4file.cpp
|
||||
mp4/mp4atom.cpp
|
||||
mp4/mp4tag.cpp
|
||||
mp4/mp4item.cpp
|
||||
mp4/mp4properties.cpp
|
||||
mp4/mp4coverart.cpp
|
||||
)
|
||||
|
||||
set(ape_SRCS
|
||||
ape/apetag.cpp
|
||||
ape/apefooter.cpp
|
||||
ape/apeitem.cpp
|
||||
ape/apefile.cpp
|
||||
ape/apeproperties.cpp
|
||||
)
|
||||
|
||||
set(wavpack_SRCS
|
||||
wavpack/wavpackfile.cpp
|
||||
wavpack/wavpackproperties.cpp
|
||||
)
|
||||
|
||||
set(speex_SRCS
|
||||
ogg/speex/speexfile.cpp
|
||||
ogg/speex/speexproperties.cpp
|
||||
)
|
||||
|
||||
set(opus_SRCS
|
||||
ogg/opus/opusfile.cpp
|
||||
ogg/opus/opusproperties.cpp
|
||||
)
|
||||
|
||||
set(trueaudio_SRCS
|
||||
trueaudio/trueaudiofile.cpp
|
||||
trueaudio/trueaudioproperties.cpp
|
||||
)
|
||||
|
||||
set(asf_SRCS
|
||||
asf/asftag.cpp
|
||||
asf/asffile.cpp
|
||||
asf/asfproperties.cpp
|
||||
asf/asfattribute.cpp
|
||||
asf/asfpicture.cpp
|
||||
)
|
||||
|
||||
set(riff_SRCS
|
||||
riff/rifffile.cpp
|
||||
)
|
||||
|
||||
set(aiff_SRCS
|
||||
riff/aiff/aifffile.cpp
|
||||
riff/aiff/aiffproperties.cpp
|
||||
)
|
||||
|
||||
set(wav_SRCS
|
||||
riff/wav/wavfile.cpp
|
||||
riff/wav/wavproperties.cpp
|
||||
riff/wav/infotag.cpp
|
||||
)
|
||||
|
||||
set(mod_SRCS
|
||||
mod/modfilebase.cpp
|
||||
mod/modfile.cpp
|
||||
mod/modtag.cpp
|
||||
mod/modproperties.cpp
|
||||
)
|
||||
|
||||
set(s3m_SRCS
|
||||
s3m/s3mfile.cpp
|
||||
s3m/s3mproperties.cpp
|
||||
)
|
||||
|
||||
set(it_SRCS
|
||||
it/itfile.cpp
|
||||
it/itproperties.cpp
|
||||
)
|
||||
|
||||
set(xm_SRCS
|
||||
xm/xmfile.cpp
|
||||
xm/xmproperties.cpp
|
||||
)
|
||||
|
||||
set(toolkit_SRCS
|
||||
toolkit/tstring.cpp
|
||||
toolkit/tstringlist.cpp
|
||||
toolkit/tbytevector.cpp
|
||||
toolkit/tbytevectorlist.cpp
|
||||
toolkit/tbytevectorstream.cpp
|
||||
toolkit/tiostream.cpp
|
||||
toolkit/tfile.cpp
|
||||
toolkit/tfilestream.cpp
|
||||
toolkit/tdebug.cpp
|
||||
toolkit/tpropertymap.cpp
|
||||
toolkit/trefcounter.cpp
|
||||
toolkit/tdebuglistener.cpp
|
||||
toolkit/tzlib.cpp
|
||||
)
|
||||
|
||||
if(HAVE_ZLIB_SOURCE)
|
||||
set(zlib_SRCS
|
||||
${ZLIB_SOURCE}/adler32.c
|
||||
${ZLIB_SOURCE}/crc32.c
|
||||
${ZLIB_SOURCE}/inffast.c
|
||||
${ZLIB_SOURCE}/inflate.c
|
||||
${ZLIB_SOURCE}/inftrees.c
|
||||
${ZLIB_SOURCE}/zutil.c
|
||||
)
|
||||
endif()
|
||||
|
||||
set(tag_LIB_SRCS
|
||||
${mpeg_SRCS} ${id3v1_SRCS} ${id3v2_SRCS} ${frames_SRCS} ${ogg_SRCS}
|
||||
${vorbis_SRCS} ${oggflacs_SRCS} ${mpc_SRCS} ${ape_SRCS} ${toolkit_SRCS} ${flacs_SRCS}
|
||||
${wavpack_SRCS} ${speex_SRCS} ${trueaudio_SRCS} ${riff_SRCS} ${aiff_SRCS} ${wav_SRCS}
|
||||
${asf_SRCS} ${mp4_SRCS} ${mod_SRCS} ${s3m_SRCS} ${it_SRCS} ${xm_SRCS} ${opus_SRCS}
|
||||
${zlib_SRCS}
|
||||
tag.cpp
|
||||
tagunion.cpp
|
||||
fileref.cpp
|
||||
audioproperties.cpp
|
||||
tagutils.cpp
|
||||
)
|
||||
|
||||
add_library(tag ${tag_LIB_SRCS} ${tag_HDRS})
|
||||
set_property(TARGET tag PROPERTY CXX_STANDARD 98)
|
||||
|
||||
if(HAVE_ZLIB AND NOT HAVE_ZLIB_SOURCE)
|
||||
target_link_libraries(tag ${ZLIB_LIBRARIES})
|
||||
endif()
|
||||
|
||||
set_target_properties(tag PROPERTIES
|
||||
VERSION ${TAGLIB_SOVERSION_MAJOR}.${TAGLIB_SOVERSION_MINOR}.${TAGLIB_SOVERSION_PATCH}
|
||||
SOVERSION ${TAGLIB_SOVERSION_MAJOR}
|
||||
INSTALL_NAME_DIR ${LIB_INSTALL_DIR}
|
||||
DEFINE_SYMBOL MAKE_TAGLIB_LIB
|
||||
LINK_INTERFACE_LIBRARIES ""
|
||||
PUBLIC_HEADER "${tag_HDRS}"
|
||||
)
|
||||
if(VISIBILITY_HIDDEN)
|
||||
set_target_properties(tag PROPERTIES C_VISIBILITY_PRESET hidden)
|
||||
endif()
|
||||
|
||||
if(BUILD_FRAMEWORK)
|
||||
unset(INSTALL_NAME_DIR)
|
||||
set_target_properties(tag PROPERTIES
|
||||
FRAMEWORK TRUE
|
||||
MACOSX_RPATH 1
|
||||
VERSION "A"
|
||||
SOVERSION "A"
|
||||
)
|
||||
endif()
|
||||
|
||||
install(TARGETS tag
|
||||
FRAMEWORK DESTINATION ${FRAMEWORK_INSTALL_DIR}
|
||||
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
|
||||
RUNTIME DESTINATION ${BIN_INSTALL_DIR}
|
||||
ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
|
||||
PUBLIC_HEADER DESTINATION ${INCLUDE_INSTALL_DIR}/taglib
|
||||
)
|
|
@ -1,170 +0,0 @@
|
|||
================================================================================
|
||||
= APE Tag Specification, Version 2.000
|
||||
================================================================================
|
||||
|
||||
Original Content (C) 2004, Frank Klemm <frank.klemm@elster.offl.uni-jena.de>
|
||||
Formatting / Editing (C) 2004, Scott Wheeler <wheeler@kde.org>
|
||||
|
||||
================================================================================
|
||||
= Contents
|
||||
================================================================================
|
||||
|
||||
1 - APE Tag General Structure
|
||||
2 - APE Tag Header / Footer Format
|
||||
3 - APE Tag Flags
|
||||
4 - APE Tag Item Format
|
||||
5 - APE Tag Item Supported Keys
|
||||
6 - APE Tag Item Content
|
||||
7 - Data Types
|
||||
7.1 - Data Types / UTF-8
|
||||
7.2 - Data Types / Dates
|
||||
7.3 - Data Types / Timestamps
|
||||
|
||||
================================================================================
|
||||
= 1 - APE Tag General Structure
|
||||
================================================================================
|
||||
|
||||
Member of Basic Components of SV8 Stream Note:
|
||||
|
||||
It is strongly recommended that the data size be stored in the tags. The size
|
||||
should normally be in the roughly one kilobyte, never more than 8 kilobytes.
|
||||
|
||||
Larger data should be stored externally using link entries. Linked data is much
|
||||
easier to process by normal programs, so for instance JPEG data should not be
|
||||
included inside the audio file.
|
||||
|
||||
APE Tag Version 2.000 (with header, recommended):
|
||||
|
||||
/================================\
|
||||
| APE Tag Header | 32 bytes |
|
||||
|-------------------|------------|
|
||||
| APE Tag Item 1 | > 10 bytes |
|
||||
| APE Tag Item 2 | > 10 bytes |
|
||||
| APE Tag Item n-1 | > 10 bytes |
|
||||
| APE Tag Item n | > 10 bytes |
|
||||
|-------------------|------------|
|
||||
| APE Tag Footer | 32 bytes |
|
||||
\================================/
|
||||
|
||||
|
||||
APE tag items should be sorted ascending by size. When streaming, parts of the
|
||||
APE tag may be dropped to reduce the danger of drop outs between tracks. This
|
||||
is not required, but is strongly recommended. It would be desirable for the
|
||||
items to be sorted by importance / size, but this is not feasible. This
|
||||
convention should only be broken when adding less important small items and it
|
||||
is not desirable to rewrite the entire tag. An APE tag at the end of a file
|
||||
(the recommended location) must have at least a footer; an APE tag at the
|
||||
beginning of a file (strongly discouraged) must have at least a header.
|
||||
|
||||
APE Tag Version 1.000 (without header, deprecated)
|
||||
|
||||
/================================\
|
||||
| APE Tag Item 1 | > 10 bytes |
|
||||
| APE Tag Item 2 | > 10 bytes |
|
||||
| APE Tag Item n-1 | > 10 bytes |
|
||||
| APE Tag Item n | > 10 bytes |
|
||||
|-------------------|------------|
|
||||
| APE Tag Footer | 32 bytes |
|
||||
\================================/
|
||||
|
||||
================================================================================
|
||||
= 2 - APE Tag Header / Footer Format
|
||||
================================================================================
|
||||
|
||||
Contains number, length and attributes of all tag items
|
||||
|
||||
Header and Footer are different in 1 bit in the Tags Flags to distinguish
|
||||
between them.
|
||||
|
||||
Member of APE Tag 2.0
|
||||
|
||||
/===========================================================================\
|
||||
| Preamble | 8 bytes | { 'A', 'P', 'E', 'T', 'A', 'G', 'E', 'X' } |
|
||||
|----------------|---------|------------------------------------------------|
|
||||
| Version Number | 4 bytes | 1000 = Version 1.000, 2000 = Version 2.000 |
|
||||
|----------------|---------|------------------------------------------------|
|
||||
| Tag Size | 4 bytes | Tag size in bytes including footer and all tag |
|
||||
| | | items excluding the header (for 1.000 |
|
||||
| | | compatibility) |
|
||||
|----------------|---------|------------------------------------------------|
|
||||
| Item Count | 4 bytes | Number of items in the tag |
|
||||
|----------------|---------|------------------------------------------------|
|
||||
| Tag Flags | 4 bytes | Global flags |
|
||||
|----------------|---------|------------------------------------------------|
|
||||
| Reserved | 8 bytes | Must be zeroed |
|
||||
\===========================================================================/
|
||||
|
||||
================================================================================
|
||||
= 3 - APE Tag Flags
|
||||
================================================================================
|
||||
|
||||
The general flag structure for either items or headers / footers is the same.
|
||||
Bits 31, 30 and 29 are specific to headers / footers, whereas 2 through 0 are
|
||||
item specific.
|
||||
|
||||
Note: APE Tags from Version 1.0 do not use any of the following. All flags in
|
||||
that version are zeroed and ignored when reading.
|
||||
|
||||
/=================================================================\
|
||||
| Contains Header | Bit 31 | 1 - has header | 0 - no header |
|
||||
|-----------------|-------------|---------------------------------|
|
||||
| Contains Footer | Bit 30 | 1 - has footer | 0 - no footer |
|
||||
|-----------------|-------------|---------------------------------|
|
||||
| Is Header | Bit 29 | 1 - is header | 0 - is footer |
|
||||
|-----------------|-------------|---------------------------------|
|
||||
| Undefined | Bits 28 - 3 | Undefined, must be zeroed |
|
||||
|-----------------|-------------|---------------------------------|
|
||||
| Encoding | Bits 2 - 1 | 00 - UTF-8 |
|
||||
| | | 01 - Binary Data * |
|
||||
| | | 10 - External Reference ** |
|
||||
| | | 11 - Reserved |
|
||||
|-----------------|-------------|---------------------------------|
|
||||
| Read Only | Bit 0 | 1 - read only | 0 - read/write |
|
||||
\=================================================================/
|
||||
|
||||
(*) Should be ignored by tools for editing text values
|
||||
(**) Allowed external reference formats:
|
||||
- http://host/directory/filename.ext
|
||||
- ftp://host/directory/filename.ext
|
||||
- filename.ext
|
||||
- /directory/filename.ext
|
||||
- DRIVE:/directory/filename.ext
|
||||
|
||||
Note: External references are also UTF-8 encoded.
|
||||
|
||||
================================================================================
|
||||
= 4 - APE Tag Item Format
|
||||
================================================================================
|
||||
|
||||
APE Tag Items are stored as key-value pairs. APE Tags Item Key are case
|
||||
sensitive, however it is illegal to use keys which only differ in case and
|
||||
it is recommended that tag reading not be case sensitive.
|
||||
|
||||
Every key can only occur (at most) once. It is not possible to repeat a key
|
||||
to signify updated contents.
|
||||
|
||||
Tags can be partially or completely repeated in the streaming format. This
|
||||
makes it possible to display an artist and / or title if it was missed at the
|
||||
beginning of the stream. It is recommended that the important information like
|
||||
artist, album and title should occur approximately every 2 minutes in the
|
||||
stream and again 5 to 10 seconds before the end. However, care should be tak
|
||||
en not to replicate this information too often or during passages with high
|
||||
bitrate demands to avoid unnecessary drop-outs.
|
||||
|
||||
/==============================================================================\
|
||||
| Content Size | 4 bytes | Length of the value in bytes |
|
||||
|----------------|---------------|---------------------------------------------|
|
||||
| Flags | 4 bytes | Item flags |
|
||||
|----------------|---------------|---------------------------------------------|
|
||||
| Key | 2 - 255 bytes | Item key |
|
||||
|----------------|---------------|---------------------------------------------|
|
||||
| Key Terminator | 1 byte | Null byte that indicates the end of the key |
|
||||
|----------------|---------------|---------------------------------------------|
|
||||
| Value | variable | Content (formatted according to the flags) |
|
||||
\==============================================================================/
|
||||
|
||||
================================================================================
|
||||
|
||||
Sections 5 - 7 haven't yet been converted from:
|
||||
|
||||
http://www.personal.uni-jena.de/~pfk/mpp/sv8/apetag.html
|
|
@ -1,314 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2010 by Alex Novichkov
|
||||
email : novichko@atnet.ru
|
||||
|
||||
copyright : (C) 2006 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
(original WavPack implementation)
|
||||
|
||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||
email : kde@carewolf.org
|
||||
(original MPC implementation)
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/toolkit/tbytevector.h>
|
||||
#include <taglib/toolkit/tstring.h>
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <taglib/tagunion.h>
|
||||
#include <taglib/mpeg/id3v1/id3v1tag.h>
|
||||
#include <taglib/mpeg/id3v2/id3v2header.h>
|
||||
#include <taglib/toolkit/tpropertymap.h>
|
||||
#include <taglib/tagutils.h>
|
||||
|
||||
#include <taglib/ape/apefile.h>
|
||||
#include <taglib/ape/apetag.h>
|
||||
#include <taglib/ape/apefooter.h>
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
namespace
|
||||
{
|
||||
enum { ApeAPEIndex = 0, ApeID3v1Index = 1 };
|
||||
}
|
||||
|
||||
class APE::File::FilePrivate
|
||||
{
|
||||
public:
|
||||
FilePrivate() :
|
||||
APELocation(-1),
|
||||
APESize(0),
|
||||
ID3v1Location(-1),
|
||||
ID3v2Header(0),
|
||||
ID3v2Location(-1),
|
||||
ID3v2Size(0),
|
||||
properties(0) {}
|
||||
|
||||
~FilePrivate()
|
||||
{
|
||||
delete ID3v2Header;
|
||||
delete properties;
|
||||
}
|
||||
|
||||
long APELocation;
|
||||
long APESize;
|
||||
|
||||
long ID3v1Location;
|
||||
|
||||
ID3v2::Header *ID3v2Header;
|
||||
long ID3v2Location;
|
||||
long ID3v2Size;
|
||||
|
||||
TagUnion tag;
|
||||
|
||||
Properties *properties;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// static members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool APE::File::isSupported(IOStream *stream)
|
||||
{
|
||||
// An APE file has an ID "MAC " somewhere. An ID3v2 tag may precede.
|
||||
|
||||
const ByteVector buffer = Utils::readHeader(stream, bufferSize(), true);
|
||||
return (buffer.find("MAC ") >= 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
APE::File::File(FileName file, bool readProperties, Properties::ReadStyle) :
|
||||
TagLib::File(file),
|
||||
d(new FilePrivate())
|
||||
{
|
||||
if(isOpen())
|
||||
read(readProperties);
|
||||
}
|
||||
|
||||
APE::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle) :
|
||||
TagLib::File(stream),
|
||||
d(new FilePrivate())
|
||||
{
|
||||
if(isOpen())
|
||||
read(readProperties);
|
||||
}
|
||||
|
||||
APE::File::~File()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
TagLib::Tag *APE::File::tag() const
|
||||
{
|
||||
return &d->tag;
|
||||
}
|
||||
|
||||
PropertyMap APE::File::properties() const
|
||||
{
|
||||
return d->tag.properties();
|
||||
}
|
||||
|
||||
void APE::File::removeUnsupportedProperties(const StringList &properties)
|
||||
{
|
||||
d->tag.removeUnsupportedProperties(properties);
|
||||
}
|
||||
|
||||
PropertyMap APE::File::setProperties(const PropertyMap &properties)
|
||||
{
|
||||
if(ID3v1Tag())
|
||||
ID3v1Tag()->setProperties(properties);
|
||||
|
||||
return APETag(true)->setProperties(properties);
|
||||
}
|
||||
|
||||
APE::Properties *APE::File::audioProperties() const
|
||||
{
|
||||
return d->properties;
|
||||
}
|
||||
|
||||
bool APE::File::save()
|
||||
{
|
||||
if(readOnly()) {
|
||||
debug("APE::File::save() -- File is read only.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update ID3v1 tag
|
||||
|
||||
if(ID3v1Tag() && !ID3v1Tag()->isEmpty()) {
|
||||
|
||||
// ID3v1 tag is not empty. Update the old one or create a new one.
|
||||
|
||||
if(d->ID3v1Location >= 0) {
|
||||
seek(d->ID3v1Location);
|
||||
}
|
||||
else {
|
||||
seek(0, End);
|
||||
d->ID3v1Location = tell();
|
||||
}
|
||||
|
||||
writeBlock(ID3v1Tag()->render());
|
||||
}
|
||||
else {
|
||||
|
||||
// ID3v1 tag is empty. Remove the old one.
|
||||
|
||||
if(d->ID3v1Location >= 0) {
|
||||
truncate(d->ID3v1Location);
|
||||
d->ID3v1Location = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Update APE tag
|
||||
|
||||
if(APETag() && !APETag()->isEmpty()) {
|
||||
|
||||
// APE tag is not empty. Update the old one or create a new one.
|
||||
|
||||
if(d->APELocation < 0) {
|
||||
if(d->ID3v1Location >= 0)
|
||||
d->APELocation = d->ID3v1Location;
|
||||
else
|
||||
d->APELocation = length();
|
||||
}
|
||||
|
||||
const ByteVector data = APETag()->render();
|
||||
insert(data, d->APELocation, d->APESize);
|
||||
|
||||
if(d->ID3v1Location >= 0)
|
||||
d->ID3v1Location += (static_cast<long>(data.size()) - d->APESize);
|
||||
|
||||
d->APESize = data.size();
|
||||
}
|
||||
else {
|
||||
|
||||
// APE tag is empty. Remove the old one.
|
||||
|
||||
if(d->APELocation >= 0) {
|
||||
removeBlock(d->APELocation, d->APESize);
|
||||
|
||||
if(d->ID3v1Location >= 0)
|
||||
d->ID3v1Location -= d->APESize;
|
||||
|
||||
d->APELocation = -1;
|
||||
d->APESize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ID3v1::Tag *APE::File::ID3v1Tag(bool create)
|
||||
{
|
||||
return d->tag.access<ID3v1::Tag>(ApeID3v1Index, create);
|
||||
}
|
||||
|
||||
APE::Tag *APE::File::APETag(bool create)
|
||||
{
|
||||
return d->tag.access<APE::Tag>(ApeAPEIndex, create);
|
||||
}
|
||||
|
||||
void APE::File::strip(int tags)
|
||||
{
|
||||
if(tags & ID3v1)
|
||||
d->tag.set(ApeID3v1Index, 0);
|
||||
|
||||
if(tags & APE)
|
||||
d->tag.set(ApeAPEIndex, 0);
|
||||
|
||||
if(!ID3v1Tag())
|
||||
APETag(true);
|
||||
}
|
||||
|
||||
bool APE::File::hasAPETag() const
|
||||
{
|
||||
return (d->APELocation >= 0);
|
||||
}
|
||||
|
||||
bool APE::File::hasID3v1Tag() const
|
||||
{
|
||||
return (d->ID3v1Location >= 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void APE::File::read(bool readProperties)
|
||||
{
|
||||
// Look for an ID3v2 tag
|
||||
|
||||
d->ID3v2Location = Utils::findID3v2(this);
|
||||
|
||||
if(d->ID3v2Location >= 0) {
|
||||
seek(d->ID3v2Location);
|
||||
d->ID3v2Header = new ID3v2::Header(readBlock(ID3v2::Header::size()));
|
||||
d->ID3v2Size = d->ID3v2Header->completeTagSize();
|
||||
}
|
||||
|
||||
// Look for an ID3v1 tag
|
||||
|
||||
d->ID3v1Location = Utils::findID3v1(this);
|
||||
|
||||
if(d->ID3v1Location >= 0)
|
||||
d->tag.set(ApeID3v1Index, new ID3v1::Tag(this, d->ID3v1Location));
|
||||
|
||||
// Look for an APE tag
|
||||
|
||||
d->APELocation = Utils::findAPE(this, d->ID3v1Location);
|
||||
|
||||
if(d->APELocation >= 0) {
|
||||
d->tag.set(ApeAPEIndex, new APE::Tag(this, d->APELocation));
|
||||
d->APESize = APETag()->footer()->completeTagSize();
|
||||
d->APELocation = d->APELocation + APE::Footer::size() - d->APESize;
|
||||
}
|
||||
|
||||
if(d->ID3v1Location < 0)
|
||||
APETag(true);
|
||||
|
||||
// Look for APE audio properties
|
||||
|
||||
if(readProperties) {
|
||||
|
||||
long streamLength;
|
||||
|
||||
if(d->APELocation >= 0)
|
||||
streamLength = d->APELocation;
|
||||
else if(d->ID3v1Location >= 0)
|
||||
streamLength = d->ID3v1Location;
|
||||
else
|
||||
streamLength = length();
|
||||
|
||||
if(d->ID3v2Location >= 0) {
|
||||
seek(d->ID3v2Location + d->ID3v2Size);
|
||||
streamLength -= (d->ID3v2Location + d->ID3v2Size);
|
||||
}
|
||||
else {
|
||||
seek(0);
|
||||
}
|
||||
|
||||
d->properties = new Properties(this, streamLength);
|
||||
}
|
||||
}
|
|
@ -1,234 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||
(C) 2002 - 2008 by Scott Wheeler (id3v2header.cpp)
|
||||
email : kde@carewolf.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
#include <bitset>
|
||||
|
||||
#include <taglib/toolkit/tstring.h>
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
|
||||
#include <taglib/ape/apefooter.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace APE;
|
||||
|
||||
class APE::Footer::FooterPrivate
|
||||
{
|
||||
public:
|
||||
FooterPrivate() :
|
||||
version(0),
|
||||
footerPresent(true),
|
||||
headerPresent(false),
|
||||
isHeader(false),
|
||||
itemCount(0),
|
||||
tagSize(0) {}
|
||||
|
||||
unsigned int version;
|
||||
|
||||
bool footerPresent;
|
||||
bool headerPresent;
|
||||
|
||||
bool isHeader;
|
||||
|
||||
unsigned int itemCount;
|
||||
unsigned int tagSize;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// static members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsigned int APE::Footer::size()
|
||||
{
|
||||
return 32;
|
||||
}
|
||||
|
||||
ByteVector APE::Footer::fileIdentifier()
|
||||
{
|
||||
return ByteVector("APETAGEX");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
APE::Footer::Footer() :
|
||||
d(new FooterPrivate())
|
||||
{
|
||||
}
|
||||
|
||||
APE::Footer::Footer(const ByteVector &data) :
|
||||
d(new FooterPrivate())
|
||||
{
|
||||
parse(data);
|
||||
}
|
||||
|
||||
APE::Footer::~Footer()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
unsigned int APE::Footer::version() const
|
||||
{
|
||||
return d->version;
|
||||
}
|
||||
|
||||
bool APE::Footer::headerPresent() const
|
||||
{
|
||||
return d->headerPresent;
|
||||
}
|
||||
|
||||
bool APE::Footer::footerPresent() const
|
||||
{
|
||||
return d->footerPresent;
|
||||
}
|
||||
|
||||
bool APE::Footer::isHeader() const
|
||||
{
|
||||
return d->isHeader;
|
||||
}
|
||||
|
||||
void APE::Footer::setHeaderPresent(bool b) const
|
||||
{
|
||||
d->headerPresent = b;
|
||||
}
|
||||
|
||||
unsigned int APE::Footer::itemCount() const
|
||||
{
|
||||
return d->itemCount;
|
||||
}
|
||||
|
||||
void APE::Footer::setItemCount(unsigned int s)
|
||||
{
|
||||
d->itemCount = s;
|
||||
}
|
||||
|
||||
unsigned int APE::Footer::tagSize() const
|
||||
{
|
||||
return d->tagSize;
|
||||
}
|
||||
|
||||
unsigned int APE::Footer::completeTagSize() const
|
||||
{
|
||||
if(d->headerPresent)
|
||||
return d->tagSize + size();
|
||||
else
|
||||
return d->tagSize;
|
||||
}
|
||||
|
||||
void APE::Footer::setTagSize(unsigned int s)
|
||||
{
|
||||
d->tagSize = s;
|
||||
}
|
||||
|
||||
void APE::Footer::setData(const ByteVector &data)
|
||||
{
|
||||
parse(data);
|
||||
}
|
||||
|
||||
ByteVector APE::Footer::renderFooter() const
|
||||
{
|
||||
return render(false);
|
||||
}
|
||||
|
||||
ByteVector APE::Footer::renderHeader() const
|
||||
{
|
||||
if(!d->headerPresent)
|
||||
return ByteVector();
|
||||
else
|
||||
return render(true);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void APE::Footer::parse(const ByteVector &data)
|
||||
{
|
||||
if(data.size() < size())
|
||||
return;
|
||||
|
||||
// The first eight bytes, data[0..7], are the File Identifier, "APETAGEX".
|
||||
|
||||
// Read the version number
|
||||
|
||||
d->version = data.toUInt(8, false);
|
||||
|
||||
// Read the tag size
|
||||
|
||||
d->tagSize = data.toUInt(12, false);
|
||||
|
||||
// Read the item count
|
||||
|
||||
d->itemCount = data.toUInt(16, false);
|
||||
|
||||
// Read the flags
|
||||
|
||||
std::bitset<32> flags(TAGLIB_CONSTRUCT_BITSET(data.toUInt(20, false)));
|
||||
|
||||
d->headerPresent = flags[31];
|
||||
d->footerPresent = !flags[30];
|
||||
d->isHeader = flags[29];
|
||||
|
||||
}
|
||||
|
||||
ByteVector APE::Footer::render(bool isHeader) const
|
||||
{
|
||||
ByteVector v;
|
||||
|
||||
// add the file identifier -- "APETAGEX"
|
||||
|
||||
v.append(fileIdentifier());
|
||||
|
||||
// add the version number -- we always render a 2.000 tag regardless of what
|
||||
// the tag originally was.
|
||||
|
||||
v.append(ByteVector::fromUInt(2000, false));
|
||||
|
||||
// add the tag size
|
||||
|
||||
v.append(ByteVector::fromUInt(d->tagSize, false));
|
||||
|
||||
// add the item count
|
||||
|
||||
v.append(ByteVector::fromUInt(d->itemCount, false));
|
||||
|
||||
// render and add the flags
|
||||
|
||||
std::bitset<32> flags;
|
||||
|
||||
flags[31] = d->headerPresent;
|
||||
flags[30] = false; // footer is always present
|
||||
flags[29] = isHeader;
|
||||
|
||||
v.append(ByteVector::fromUInt(flags.to_ulong(), false));
|
||||
|
||||
// add the reserved 64bit
|
||||
|
||||
v.append(ByteVector::fromLongLong(0));
|
||||
|
||||
return v;
|
||||
}
|
|
@ -1,204 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2010 by Alex Novichkov
|
||||
email : novichko@atnet.ru
|
||||
|
||||
copyright : (C) 2006 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
(original WavPack implementation)
|
||||
|
||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||
email : kde@carewolf.org
|
||||
(original MPC implementation)
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/toolkit/tbytevector.h>
|
||||
#include <taglib/toolkit/tstring.h>
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <taglib/tagunion.h>
|
||||
#include <taglib/mpeg/id3v1/id3v1tag.h>
|
||||
#include <taglib/mpeg/id3v2/id3v2header.h>
|
||||
#include <taglib/toolkit/tpropertymap.h>
|
||||
#include <taglib/tagutils.h>
|
||||
|
||||
#include <taglib/ape/apegenfile.h>
|
||||
#include <taglib/ape/apetag.h>
|
||||
#include <taglib/ape/apefooter.h>
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
namespace
|
||||
{
|
||||
enum { ApeGenAPEIndex = 0 };
|
||||
}
|
||||
|
||||
class APEGen::File::FilePrivate
|
||||
{
|
||||
public:
|
||||
FilePrivate() :
|
||||
APELocation(-1),
|
||||
APESize(0) {}
|
||||
|
||||
~FilePrivate()
|
||||
{
|
||||
}
|
||||
|
||||
long APELocation;
|
||||
long APESize;
|
||||
|
||||
TagUnion tag;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// static members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool APEGen::File::isSupported(IOStream *stream)
|
||||
{
|
||||
// Generic file support for anything with APE tags
|
||||
const ByteVector buffer = Utils::readHeader(stream, bufferSize(), true);
|
||||
return (buffer.find("APETAGEX") >= 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
APEGen::File::File(FileName file, bool readProperties, Properties::ReadStyle) :
|
||||
TagLib::File(file),
|
||||
d(new FilePrivate())
|
||||
{
|
||||
if(isOpen())
|
||||
read(readProperties);
|
||||
}
|
||||
|
||||
APEGen::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle) :
|
||||
TagLib::File(stream),
|
||||
d(new FilePrivate())
|
||||
{
|
||||
if(isOpen())
|
||||
read(readProperties);
|
||||
}
|
||||
|
||||
APEGen::File::~File()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
TagLib::Tag *APEGen::File::tag() const
|
||||
{
|
||||
return &d->tag;
|
||||
}
|
||||
|
||||
PropertyMap APEGen::File::properties() const
|
||||
{
|
||||
return d->tag.properties();
|
||||
}
|
||||
|
||||
void APEGen::File::removeUnsupportedProperties(const StringList &properties)
|
||||
{
|
||||
d->tag.removeUnsupportedProperties(properties);
|
||||
}
|
||||
|
||||
PropertyMap APEGen::File::setProperties(const PropertyMap &properties)
|
||||
{
|
||||
return APETag(true)->setProperties(properties);
|
||||
}
|
||||
|
||||
APEGen::Properties *APEGen::File::audioProperties() const
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool APEGen::File::save()
|
||||
{
|
||||
if(readOnly()) {
|
||||
debug("APEGen::File::save() -- File is read only.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update APE tag
|
||||
|
||||
if(APETag() && !APETag()->isEmpty()) {
|
||||
|
||||
// APE tag is not empty. Update the old one or create a new one.
|
||||
|
||||
if(d->APELocation < 0) {
|
||||
d->APELocation = length();
|
||||
}
|
||||
|
||||
const ByteVector data = APETag()->render();
|
||||
insert(data, d->APELocation, d->APESize);
|
||||
|
||||
d->APESize = data.size();
|
||||
}
|
||||
else {
|
||||
|
||||
// APE tag is empty. Remove the old one.
|
||||
|
||||
if(d->APELocation >= 0) {
|
||||
removeBlock(d->APELocation, d->APESize);
|
||||
|
||||
d->APELocation = -1;
|
||||
d->APESize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
APE::Tag *APEGen::File::APETag(bool create)
|
||||
{
|
||||
return d->tag.access<APE::Tag>(ApeGenAPEIndex, create);
|
||||
}
|
||||
|
||||
void APEGen::File::strip(int tags)
|
||||
{
|
||||
if(tags & APE)
|
||||
d->tag.set(ApeGenAPEIndex, 0);
|
||||
|
||||
APETag(true);
|
||||
}
|
||||
|
||||
bool APEGen::File::hasAPETag() const
|
||||
{
|
||||
return (d->APELocation >= 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void APEGen::File::read(bool readProperties)
|
||||
{
|
||||
// Look for an APE tag
|
||||
|
||||
d->APELocation = Utils::findAPE(this, -1);
|
||||
|
||||
if(d->APELocation >= 0) {
|
||||
d->tag.set(ApeGenAPEIndex, new APE::Tag(this, d->APELocation));
|
||||
d->APESize = APETag()->footer()->completeTagSize();
|
||||
d->APELocation = d->APELocation + APE::Footer::size() - d->APESize;
|
||||
}
|
||||
|
||||
APETag(true);
|
||||
}
|
|
@ -1,201 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2010 by Alex Novichkov
|
||||
email : novichko@atnet.ru
|
||||
|
||||
copyright : (C) 2006 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
(original WavPack implementation)
|
||||
|
||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||
email : kde@carewolf.org
|
||||
(original MPC implementation)
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_APEGENFILE_H
|
||||
#define TAGLIB_APEGENFILE_H
|
||||
|
||||
#include <taglib/toolkit/tfile.h>
|
||||
#include <taglib/taglib_export.h>
|
||||
#include <taglib/ape/apeproperties.h>
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
class Tag;
|
||||
|
||||
namespace APE { class Tag; }
|
||||
|
||||
//! An implementation of APE metadata
|
||||
|
||||
/*!
|
||||
* This is implementation of APE metadata.
|
||||
*
|
||||
* This supports APE (v1 and v2) style comments only.
|
||||
*/
|
||||
|
||||
namespace APEGen {
|
||||
|
||||
class Properties : public APE::Properties { };
|
||||
|
||||
//! An implementation of TagLib::File with APE specific methods
|
||||
|
||||
/*!
|
||||
* This implements and provides an interface for any arbitrary file with
|
||||
* APE tags appended, and no other tag format, using TagLib::Tag and
|
||||
* TagLib::AudioProperties interfaces by way of implementing the abstract
|
||||
* TagLib::File API as well as providing some additional information
|
||||
* specific to APE tagged files. No technical info supported.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT File : public TagLib::File
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* This set of flags is used for various operations and is suitable for
|
||||
* being OR-ed together.
|
||||
*/
|
||||
enum TagTypes {
|
||||
//! Empty set. Matches no tag types.
|
||||
NoTags = 0x0000,
|
||||
//! Matches APE tags.
|
||||
APE = 0x0001,
|
||||
//! Matches all tag types.
|
||||
AllTags = 0xffff
|
||||
};
|
||||
|
||||
/*!
|
||||
* Constructs an APE file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read.
|
||||
*
|
||||
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Constructs an APE file from \a stream. If \a readProperties is true the
|
||||
* file's audio properties will also be read.
|
||||
*
|
||||
* \note TagLib will *not* take ownership of the stream, the caller is
|
||||
* responsible for deleting it after the File object.
|
||||
*
|
||||
* \note In the current implementation, \a propertiesStyle is ignored.
|
||||
*/
|
||||
File(IOStream *stream, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
virtual ~File();
|
||||
|
||||
/*!
|
||||
* Returns the Tag for this file. This will be an APE tag.
|
||||
*/
|
||||
virtual TagLib::Tag *tag() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- export function.
|
||||
*/
|
||||
PropertyMap properties() const;
|
||||
|
||||
/*!
|
||||
* Removes unsupported properties. Forwards to the actual Tag's
|
||||
* removeUnsupportedProperties() function.
|
||||
*/
|
||||
void removeUnsupportedProperties(const StringList &properties);
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- import function.
|
||||
* Creates an APEv2 tag if necessary.
|
||||
*/
|
||||
PropertyMap setProperties(const PropertyMap &);
|
||||
|
||||
/*!
|
||||
* Returns the APE::Properties for this file. If no audio properties
|
||||
* were read then this will return a null pointer.
|
||||
*/
|
||||
virtual Properties *audioProperties() const;
|
||||
|
||||
/*!
|
||||
* Saves the file.
|
||||
*
|
||||
* Updates an existing APE tag, adds a new APEv2 tag, or removes it.
|
||||
*/
|
||||
virtual bool save();
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the APE tag of the file.
|
||||
*
|
||||
* If \a create is false (the default) this may return a null pointer
|
||||
* if there is no valid APE tag. If \a create is true it will create
|
||||
* an APE tag if one does not exist and returns a valid pointer.
|
||||
*
|
||||
* \note This may return a valid pointer regardless of whether or not the
|
||||
* file on disk has an APE tag. Use hasAPETag() to check if the file
|
||||
* on disk actually has an APE tag.
|
||||
*
|
||||
* \note The Tag <b>is still</b> owned by the MPEG::File and should not be
|
||||
* deleted by the user. It will be deleted when the file (object) is
|
||||
* destroyed.
|
||||
*
|
||||
* \see hasAPETag()
|
||||
*/
|
||||
APE::Tag *APETag(bool create = false);
|
||||
|
||||
/*!
|
||||
* This will remove the tags that match the OR-ed together TagTypes from the
|
||||
* file. By default it removes all tags.
|
||||
*
|
||||
* \note This will also invalidate pointers to the tags
|
||||
* as their memory will be freed.
|
||||
* \note In order to make the removal permanent save() still needs to be called
|
||||
*/
|
||||
void strip(int tags = AllTags);
|
||||
|
||||
/*!
|
||||
* Returns whether or not the file on disk actually has an APE tag.
|
||||
*
|
||||
* \see APETag()
|
||||
*/
|
||||
bool hasAPETag() const;
|
||||
|
||||
/*!
|
||||
* Returns whether or not the given \a stream can be opened using an
|
||||
* APE tag parser. Does no other validation.
|
||||
*
|
||||
* \note This method is designed to do a quick check. The result may
|
||||
* not necessarily be correct.
|
||||
*/
|
||||
static bool isSupported(IOStream *stream);
|
||||
|
||||
private:
|
||||
File(const File &);
|
||||
File &operator=(const File &);
|
||||
|
||||
void read(bool readProperties);
|
||||
|
||||
class FilePrivate;
|
||||
FilePrivate *d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,301 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||
email : kde@carewolf.com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/toolkit/tbytevectorlist.h>
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
|
||||
#include <taglib/ape/apeitem.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace APE;
|
||||
|
||||
class APE::Item::ItemPrivate
|
||||
{
|
||||
public:
|
||||
ItemPrivate() :
|
||||
type(Text),
|
||||
readOnly(false) {}
|
||||
|
||||
Item::ItemTypes type;
|
||||
String key;
|
||||
ByteVector value;
|
||||
StringList text;
|
||||
bool readOnly;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
APE::Item::Item() :
|
||||
d(new ItemPrivate())
|
||||
{
|
||||
}
|
||||
|
||||
APE::Item::Item(const String &key, const String &value) :
|
||||
d(new ItemPrivate())
|
||||
{
|
||||
d->key = key;
|
||||
d->text.append(value);
|
||||
}
|
||||
|
||||
APE::Item::Item(const String &key, const StringList &values) :
|
||||
d(new ItemPrivate())
|
||||
{
|
||||
d->key = key;
|
||||
d->text = values;
|
||||
}
|
||||
|
||||
APE::Item::Item(const String &key, const ByteVector &value, bool binary) :
|
||||
d(new ItemPrivate())
|
||||
{
|
||||
d->key = key;
|
||||
if(binary) {
|
||||
d->type = Binary;
|
||||
d->value = value;
|
||||
}
|
||||
else {
|
||||
d->text.append(value);
|
||||
}
|
||||
}
|
||||
|
||||
APE::Item::Item(const Item &item) :
|
||||
d(new ItemPrivate(*item.d))
|
||||
{
|
||||
}
|
||||
|
||||
APE::Item::~Item()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
Item &APE::Item::operator=(const Item &item)
|
||||
{
|
||||
Item(item).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void APE::Item::swap(Item &item)
|
||||
{
|
||||
using std::swap;
|
||||
|
||||
swap(d, item.d);
|
||||
}
|
||||
|
||||
void APE::Item::setReadOnly(bool readOnly)
|
||||
{
|
||||
d->readOnly = readOnly;
|
||||
}
|
||||
|
||||
bool APE::Item::isReadOnly() const
|
||||
{
|
||||
return d->readOnly;
|
||||
}
|
||||
|
||||
void APE::Item::setType(APE::Item::ItemTypes val)
|
||||
{
|
||||
d->type = val;
|
||||
}
|
||||
|
||||
APE::Item::ItemTypes APE::Item::type() const
|
||||
{
|
||||
return d->type;
|
||||
}
|
||||
|
||||
String APE::Item::key() const
|
||||
{
|
||||
return d->key;
|
||||
}
|
||||
|
||||
ByteVector APE::Item::binaryData() const
|
||||
{
|
||||
return d->value;
|
||||
}
|
||||
|
||||
void APE::Item::setBinaryData(const ByteVector &value)
|
||||
{
|
||||
d->type = Binary;
|
||||
d->value = value;
|
||||
d->text.clear();
|
||||
}
|
||||
|
||||
ByteVector APE::Item::value() const
|
||||
{
|
||||
// This seems incorrect as it won't be actually rendering the value to keep it
|
||||
// up to date.
|
||||
|
||||
return d->value;
|
||||
}
|
||||
|
||||
void APE::Item::setKey(const String &key)
|
||||
{
|
||||
d->key = key;
|
||||
}
|
||||
|
||||
void APE::Item::setValue(const String &value)
|
||||
{
|
||||
d->type = Text;
|
||||
d->text = value;
|
||||
d->value.clear();
|
||||
}
|
||||
|
||||
void APE::Item::setValues(const StringList &value)
|
||||
{
|
||||
d->type = Text;
|
||||
d->text = value;
|
||||
d->value.clear();
|
||||
}
|
||||
|
||||
void APE::Item::appendValue(const String &value)
|
||||
{
|
||||
d->type = Text;
|
||||
d->text.append(value);
|
||||
d->value.clear();
|
||||
}
|
||||
|
||||
void APE::Item::appendValues(const StringList &values)
|
||||
{
|
||||
d->type = Text;
|
||||
d->text.append(values);
|
||||
d->value.clear();
|
||||
}
|
||||
|
||||
int APE::Item::size() const
|
||||
{
|
||||
int result = 8 + d->key.size() + 1;
|
||||
switch(d->type) {
|
||||
case Text:
|
||||
if(!d->text.isEmpty()) {
|
||||
StringList::ConstIterator it = d->text.begin();
|
||||
|
||||
result += it->data(String::UTF8).size();
|
||||
it++;
|
||||
for(; it != d->text.end(); ++it)
|
||||
result += 1 + it->data(String::UTF8).size();
|
||||
}
|
||||
break;
|
||||
|
||||
case Binary:
|
||||
case Locator:
|
||||
result += d->value.size();
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
StringList APE::Item::toStringList() const
|
||||
{
|
||||
return d->text;
|
||||
}
|
||||
|
||||
StringList APE::Item::values() const
|
||||
{
|
||||
return d->text;
|
||||
}
|
||||
|
||||
String APE::Item::toString() const
|
||||
{
|
||||
if(d->type == Text && !isEmpty())
|
||||
return d->text.front();
|
||||
else
|
||||
return String();
|
||||
}
|
||||
|
||||
bool APE::Item::isEmpty() const
|
||||
{
|
||||
switch(d->type) {
|
||||
case Text:
|
||||
if(d->text.isEmpty())
|
||||
return true;
|
||||
if(d->text.size() == 1 && d->text.front().isEmpty())
|
||||
return true;
|
||||
return false;
|
||||
case Binary:
|
||||
case Locator:
|
||||
return d->value.isEmpty();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void APE::Item::parse(const ByteVector &data)
|
||||
{
|
||||
// 11 bytes is the minimum size for an APE item
|
||||
|
||||
if(data.size() < 11) {
|
||||
debug("APE::Item::parse() -- no data in item");
|
||||
return;
|
||||
}
|
||||
|
||||
const unsigned int valueLength = data.toUInt(0, false);
|
||||
const unsigned int flags = data.toUInt(4, false);
|
||||
|
||||
// An item key can contain ASCII characters from 0x20 up to 0x7E, not UTF-8.
|
||||
// We assume that the validity of the given key has been checked.
|
||||
|
||||
d->key = String(&data[8], String::Latin1);
|
||||
|
||||
const ByteVector value = data.mid(8 + d->key.size() + 1, valueLength);
|
||||
|
||||
setReadOnly(flags & 1);
|
||||
setType(ItemTypes((flags >> 1) & 3));
|
||||
|
||||
if(Text == d->type)
|
||||
d->text = StringList(ByteVectorList::split(value, '\0'), String::UTF8);
|
||||
else
|
||||
d->value = value;
|
||||
}
|
||||
|
||||
ByteVector APE::Item::render() const
|
||||
{
|
||||
ByteVector data;
|
||||
unsigned int flags = ((d->readOnly) ? 1 : 0) | (d->type << 1);
|
||||
ByteVector value;
|
||||
|
||||
if(isEmpty())
|
||||
return data;
|
||||
|
||||
if(d->type == Text) {
|
||||
StringList::ConstIterator it = d->text.begin();
|
||||
|
||||
value.append(it->data(String::UTF8));
|
||||
it++;
|
||||
for(; it != d->text.end(); ++it) {
|
||||
value.append('\0');
|
||||
value.append(it->data(String::UTF8));
|
||||
}
|
||||
d->value = value;
|
||||
}
|
||||
else
|
||||
value.append(d->value);
|
||||
|
||||
data.append(ByteVector::fromUInt(value.size(), false));
|
||||
data.append(ByteVector::fromUInt(flags, false));
|
||||
data.append(d->key.data(String::Latin1));
|
||||
data.append(ByteVector('\0'));
|
||||
data.append(value);
|
||||
|
||||
return data;
|
||||
}
|
|
@ -1,252 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2010 by Alex Novichkov
|
||||
email : novichko@atnet.ru
|
||||
|
||||
copyright : (C) 2006 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
(original WavPack implementation)
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/toolkit/tstring.h>
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <bitset>
|
||||
#include <taglib/mpeg/id3v2/id3v2tag.h>
|
||||
#include <taglib/ape/apeproperties.h>
|
||||
#include <taglib/ape/apefile.h>
|
||||
#include <taglib/ape/apetag.h>
|
||||
#include <taglib/ape/apefooter.h>
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class APE::Properties::PropertiesPrivate
|
||||
{
|
||||
public:
|
||||
PropertiesPrivate() :
|
||||
length(0),
|
||||
bitrate(0),
|
||||
sampleRate(0),
|
||||
channels(0),
|
||||
version(0),
|
||||
bitsPerSample(0),
|
||||
sampleFrames(0) {}
|
||||
|
||||
int length;
|
||||
int bitrate;
|
||||
int sampleRate;
|
||||
int channels;
|
||||
int version;
|
||||
int bitsPerSample;
|
||||
unsigned int sampleFrames;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
APE::Properties::Properties(File *, ReadStyle style) :
|
||||
AudioProperties(style),
|
||||
d(new PropertiesPrivate())
|
||||
{
|
||||
debug("APE::Properties::Properties() -- This constructor is no longer used.");
|
||||
}
|
||||
|
||||
APE::Properties::Properties(File *file, long streamLength, ReadStyle style) :
|
||||
AudioProperties(style),
|
||||
d(new PropertiesPrivate())
|
||||
{
|
||||
read(file, streamLength);
|
||||
}
|
||||
|
||||
APE::Properties::~Properties()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
int APE::Properties::length() const
|
||||
{
|
||||
return lengthInSeconds();
|
||||
}
|
||||
|
||||
int APE::Properties::lengthInSeconds() const
|
||||
{
|
||||
return d->length / 1000;
|
||||
}
|
||||
|
||||
int APE::Properties::lengthInMilliseconds() const
|
||||
{
|
||||
return d->length;
|
||||
}
|
||||
|
||||
int APE::Properties::bitrate() const
|
||||
{
|
||||
return d->bitrate;
|
||||
}
|
||||
|
||||
int APE::Properties::sampleRate() const
|
||||
{
|
||||
return d->sampleRate;
|
||||
}
|
||||
|
||||
int APE::Properties::channels() const
|
||||
{
|
||||
return d->channels;
|
||||
}
|
||||
|
||||
int APE::Properties::version() const
|
||||
{
|
||||
return d->version;
|
||||
}
|
||||
|
||||
int APE::Properties::bitsPerSample() const
|
||||
{
|
||||
return d->bitsPerSample;
|
||||
}
|
||||
|
||||
unsigned int APE::Properties::sampleFrames() const
|
||||
{
|
||||
return d->sampleFrames;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace
|
||||
{
|
||||
int headerVersion(const ByteVector &header)
|
||||
{
|
||||
if(header.size() < 6 || !header.startsWith("MAC "))
|
||||
return -1;
|
||||
|
||||
return header.toUShort(4, false);
|
||||
}
|
||||
}
|
||||
|
||||
void APE::Properties::read(File *file, long streamLength)
|
||||
{
|
||||
// First, we assume that the file pointer is set at the first descriptor.
|
||||
long offset = file->tell();
|
||||
int version = headerVersion(file->readBlock(6));
|
||||
|
||||
// Next, we look for the descriptor.
|
||||
if(version < 0) {
|
||||
offset = file->find("MAC ", offset);
|
||||
file->seek(offset);
|
||||
version = headerVersion(file->readBlock(6));
|
||||
}
|
||||
|
||||
if(version < 0) {
|
||||
debug("APE::Properties::read() -- APE descriptor not found");
|
||||
return;
|
||||
}
|
||||
|
||||
d->version = version;
|
||||
|
||||
if(d->version >= 3980)
|
||||
analyzeCurrent(file);
|
||||
else
|
||||
analyzeOld(file);
|
||||
|
||||
if(d->sampleFrames > 0 && d->sampleRate > 0) {
|
||||
const double length = d->sampleFrames * 1000.0 / d->sampleRate;
|
||||
d->length = static_cast<int>(length + 0.5);
|
||||
d->bitrate = static_cast<int>(streamLength * 8.0 / length + 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
void APE::Properties::analyzeCurrent(File *file)
|
||||
{
|
||||
// Read the descriptor
|
||||
file->seek(2, File::Current);
|
||||
const ByteVector descriptor = file->readBlock(44);
|
||||
if(descriptor.size() < 44) {
|
||||
debug("APE::Properties::analyzeCurrent() -- descriptor is too short.");
|
||||
return;
|
||||
}
|
||||
|
||||
const unsigned int descriptorBytes = descriptor.toUInt(0, false);
|
||||
|
||||
if((descriptorBytes - 52) > 0)
|
||||
file->seek(descriptorBytes - 52, File::Current);
|
||||
|
||||
// Read the header
|
||||
const ByteVector header = file->readBlock(24);
|
||||
if(header.size() < 24) {
|
||||
debug("APE::Properties::analyzeCurrent() -- MAC header is too short.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the APE info
|
||||
d->channels = header.toShort(18, false);
|
||||
d->sampleRate = header.toUInt(20, false);
|
||||
d->bitsPerSample = header.toShort(16, false);
|
||||
|
||||
const unsigned int totalFrames = header.toUInt(12, false);
|
||||
if(totalFrames == 0)
|
||||
return;
|
||||
|
||||
const unsigned int blocksPerFrame = header.toUInt(4, false);
|
||||
const unsigned int finalFrameBlocks = header.toUInt(8, false);
|
||||
d->sampleFrames = (totalFrames - 1) * blocksPerFrame + finalFrameBlocks;
|
||||
}
|
||||
|
||||
void APE::Properties::analyzeOld(File *file)
|
||||
{
|
||||
const ByteVector header = file->readBlock(26);
|
||||
if(header.size() < 26) {
|
||||
debug("APE::Properties::analyzeOld() -- MAC header is too short.");
|
||||
return;
|
||||
}
|
||||
|
||||
const unsigned int totalFrames = header.toUInt(18, false);
|
||||
|
||||
// Fail on 0 length APE files (catches non-finalized APE files)
|
||||
if(totalFrames == 0)
|
||||
return;
|
||||
|
||||
const short compressionLevel = header.toShort(0, false);
|
||||
unsigned int blocksPerFrame;
|
||||
if(d->version >= 3950)
|
||||
blocksPerFrame = 73728 * 4;
|
||||
else if(d->version >= 3900 || (d->version >= 3800 && compressionLevel == 4000))
|
||||
blocksPerFrame = 73728;
|
||||
else
|
||||
blocksPerFrame = 9216;
|
||||
|
||||
// Get the APE info
|
||||
d->channels = header.toShort(4, false);
|
||||
d->sampleRate = header.toUInt(6, false);
|
||||
|
||||
const unsigned int finalFrameBlocks = header.toUInt(22, false);
|
||||
d->sampleFrames = (totalFrames - 1) * blocksPerFrame + finalFrameBlocks;
|
||||
|
||||
// Get the bit depth from the RIFF-fmt chunk.
|
||||
file->seek(16, File::Current);
|
||||
const ByteVector fmt = file->readBlock(28);
|
||||
if(fmt.size() < 28 || !fmt.startsWith("WAVEfmt ")) {
|
||||
debug("APE::Properties::analyzeOld() -- fmt header is too short.");
|
||||
return;
|
||||
}
|
||||
|
||||
d->bitsPerSample = fmt.toShort(26, false);
|
||||
}
|
|
@ -1,572 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||
email : kde@carewolf.com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#if defined(__SUNPRO_CC) && (__SUNPRO_CC < 0x5130)
|
||||
// Sun Studio finds multiple specializations of Map because
|
||||
// it considers specializations with and without class types
|
||||
// to be different; this define forces Map to use only the
|
||||
// specialization with the class keyword.
|
||||
#define WANT_CLASS_INSTANTIATION_OF_MAP (1)
|
||||
#endif
|
||||
|
||||
#include <taglib/toolkit/tfile.h>
|
||||
#include <taglib/toolkit/tstring.h>
|
||||
#include <taglib/toolkit/tmap.h>
|
||||
#include <taglib/toolkit/tpropertymap.h>
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <taglib/toolkit/tutils.h>
|
||||
|
||||
#include <taglib/ape/apetag.h>
|
||||
#include <taglib/ape/apefooter.h>
|
||||
#include <taglib/ape/apeitem.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace APE;
|
||||
|
||||
namespace
|
||||
{
|
||||
const unsigned int MinKeyLength = 2;
|
||||
const unsigned int MaxKeyLength = 255;
|
||||
|
||||
bool isKeyValid(const ByteVector &key)
|
||||
{
|
||||
const char *invalidKeys[] = { "ID3", "TAG", "OGGS", "MP+", 0 };
|
||||
|
||||
// only allow printable ASCII including space (32..126)
|
||||
|
||||
for(ByteVector::ConstIterator it = key.begin(); it != key.end(); ++it) {
|
||||
const int c = static_cast<unsigned char>(*it);
|
||||
if(c < 32 || c > 126)
|
||||
return false;
|
||||
}
|
||||
|
||||
const String upperKey = String(key).upper();
|
||||
for(size_t i = 0; invalidKeys[i] != 0; ++i) {
|
||||
if(upperKey == invalidKeys[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class APE::Tag::TagPrivate
|
||||
{
|
||||
public:
|
||||
TagPrivate() :
|
||||
file(0),
|
||||
footerLocation(0) {}
|
||||
|
||||
File *file;
|
||||
long footerLocation;
|
||||
|
||||
Footer footer;
|
||||
ItemListMap itemListMap;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
APE::Tag::Tag() :
|
||||
TagLib::Tag(),
|
||||
d(new TagPrivate())
|
||||
{
|
||||
}
|
||||
|
||||
APE::Tag::Tag(TagLib::File *file, long footerLocation) :
|
||||
TagLib::Tag(),
|
||||
d(new TagPrivate())
|
||||
{
|
||||
d->file = file;
|
||||
d->footerLocation = footerLocation;
|
||||
|
||||
read();
|
||||
}
|
||||
|
||||
APE::Tag::~Tag()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
ByteVector APE::Tag::fileIdentifier()
|
||||
{
|
||||
return ByteVector::fromCString("APETAGEX");
|
||||
}
|
||||
|
||||
String APE::Tag::title() const
|
||||
{
|
||||
if(d->itemListMap["TITLE"].isEmpty())
|
||||
return String();
|
||||
return d->itemListMap["TITLE"].values().toString();
|
||||
}
|
||||
|
||||
String APE::Tag::albumartist() const
|
||||
{
|
||||
if(!d->itemListMap["ALBUMARTIST"].isEmpty())
|
||||
return d->itemListMap["ALBUMARTIST"].values().toString();
|
||||
if(!d->itemListMap["ALBUM ARTIST"].isEmpty())
|
||||
return d->itemListMap["ALBUM ARTIST"].values().toString();
|
||||
return String();
|
||||
}
|
||||
|
||||
String APE::Tag::artist() const
|
||||
{
|
||||
if(d->itemListMap["ARTIST"].isEmpty())
|
||||
return String();
|
||||
return d->itemListMap["ARTIST"].values().toString();
|
||||
}
|
||||
|
||||
String APE::Tag::composer() const
|
||||
{
|
||||
if(!d->itemListMap["COMPOSER"].isEmpty())
|
||||
return d->itemListMap["COMPOSER"].values().toString();
|
||||
return String();
|
||||
}
|
||||
|
||||
String APE::Tag::album() const
|
||||
{
|
||||
if(d->itemListMap["ALBUM"].isEmpty())
|
||||
return String();
|
||||
return d->itemListMap["ALBUM"].values().toString();
|
||||
}
|
||||
|
||||
String APE::Tag::unsyncedlyrics() const
|
||||
{
|
||||
if(!d->itemListMap["UNSYNCEDLYRICS"].isEmpty())
|
||||
return d->itemListMap["UNSYNCEDLYRICS"].values().toString();
|
||||
if(!d->itemListMap["UNSYNCED LYRICS"].isEmpty())
|
||||
return d->itemListMap["UNSYNCED LYRICS"].values().toString();
|
||||
if(!d->itemListMap["LYRICS"].isEmpty())
|
||||
return d->itemListMap["LYRICS"].values().toString();
|
||||
return String();
|
||||
}
|
||||
|
||||
String APE::Tag::comment() const
|
||||
{
|
||||
if(d->itemListMap["COMMENT"].isEmpty())
|
||||
return String();
|
||||
return d->itemListMap["COMMENT"].values().toString();
|
||||
}
|
||||
|
||||
String APE::Tag::genre() const
|
||||
{
|
||||
if(d->itemListMap["GENRE"].isEmpty())
|
||||
return String();
|
||||
return d->itemListMap["GENRE"].values().toString();
|
||||
}
|
||||
|
||||
unsigned int APE::Tag::year() const
|
||||
{
|
||||
if(d->itemListMap["YEAR"].isEmpty())
|
||||
return 0;
|
||||
return d->itemListMap["YEAR"].toString().toInt();
|
||||
}
|
||||
|
||||
unsigned int APE::Tag::track() const
|
||||
{
|
||||
if(d->itemListMap["TRACK"].isEmpty())
|
||||
return 0;
|
||||
return d->itemListMap["TRACK"].toString().toInt();
|
||||
}
|
||||
|
||||
unsigned int APE::Tag::disc() const
|
||||
{
|
||||
if(d->itemListMap["DISC"].isEmpty())
|
||||
return 0;
|
||||
return d->itemListMap["DISC"].toString().toInt();
|
||||
}
|
||||
|
||||
String APE::Tag::cuesheet() const
|
||||
{
|
||||
if(d->itemListMap["CUESHEET"].isEmpty())
|
||||
return String();
|
||||
return d->itemListMap["CUESHEET"].toString();
|
||||
}
|
||||
|
||||
float APE::Tag::rgAlbumGain() const
|
||||
{
|
||||
if (d->itemListMap["REPLAYGAIN_ALBUM_GAIN"].isEmpty())
|
||||
return 0;
|
||||
return d->itemListMap["REPLAYGAIN_ALBUM_GAIN"].toString().toFloat();
|
||||
}
|
||||
|
||||
float APE::Tag::rgAlbumPeak() const
|
||||
{
|
||||
if (d->itemListMap["REPLAYGAIN_ALBUM_PEAK"].isEmpty())
|
||||
return 0;
|
||||
return d->itemListMap["REPLAYGAIN_ALBUM_PEAK"].toString().toFloat();
|
||||
}
|
||||
|
||||
float APE::Tag::rgTrackGain() const
|
||||
{
|
||||
if (d->itemListMap["REPLAYGAIN_TRACK_GAIN"].isEmpty())
|
||||
return 0;
|
||||
return d->itemListMap["REPLAYGAIN_TRACK_GAIN"].toString().toFloat();
|
||||
}
|
||||
|
||||
float APE::Tag::rgTrackPeak() const
|
||||
{
|
||||
if (d->itemListMap["REPLAYGAIN_TRACK_PEAK"].isEmpty())
|
||||
return 0;
|
||||
return d->itemListMap["REPLAYGAIN_TRACK_PEAK"].toString().toFloat();
|
||||
}
|
||||
|
||||
String APE::Tag::soundcheck() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
void APE::Tag::setTitle(const String &s)
|
||||
{
|
||||
addValue("TITLE", s, true);
|
||||
}
|
||||
|
||||
void APE::Tag::setAlbumArtist(const String &s)
|
||||
{
|
||||
addValue("ALBUMARTIST", s, true);
|
||||
}
|
||||
|
||||
void APE::Tag::setArtist(const String &s)
|
||||
{
|
||||
addValue("ARTIST", s, true);
|
||||
}
|
||||
|
||||
void APE::Tag::setComposer(const String &s)
|
||||
{
|
||||
addValue("COMPOSER", s, true);
|
||||
}
|
||||
|
||||
void APE::Tag::setAlbum(const String &s)
|
||||
{
|
||||
addValue("ALBUM", s, true);
|
||||
}
|
||||
|
||||
void APE::Tag::setUnsyncedlyrics(const String &s)
|
||||
{
|
||||
addValue("UNSYNCED LYRICS", s);
|
||||
}
|
||||
|
||||
void APE::Tag::setComment(const String &s)
|
||||
{
|
||||
addValue("COMMENT", s, true);
|
||||
}
|
||||
|
||||
void APE::Tag::setGenre(const String &s)
|
||||
{
|
||||
addValue("GENRE", s, true);
|
||||
}
|
||||
|
||||
void APE::Tag::setYear(unsigned int i)
|
||||
{
|
||||
if(i == 0)
|
||||
removeItem("YEAR");
|
||||
else
|
||||
addValue("YEAR", String::number(i), true);
|
||||
}
|
||||
|
||||
void APE::Tag::setTrack(unsigned int i)
|
||||
{
|
||||
if(i == 0)
|
||||
removeItem("TRACK");
|
||||
else
|
||||
addValue("TRACK", String::number(i), true);
|
||||
}
|
||||
|
||||
void APE::Tag::setDisc(unsigned int i)
|
||||
{
|
||||
if(i == 0)
|
||||
removeItem("DISC");
|
||||
else
|
||||
addValue("DISC", String::number(i), true);
|
||||
}
|
||||
|
||||
void APE::Tag::setCuesheet(const String &)
|
||||
{
|
||||
}
|
||||
|
||||
void APE::Tag::setRGAlbumGain(float f)
|
||||
{
|
||||
if (f == 0)
|
||||
removeItem("REPLAYGAIN_ALBUM_GAIN");
|
||||
else
|
||||
addValue("REPLAYGAIN_ALBUM_GAIN", String::number(f) + " dB", true);
|
||||
}
|
||||
|
||||
void APE::Tag::setRGAlbumPeak(float f)
|
||||
{
|
||||
if (f == 0)
|
||||
removeItem("REPLAYGAIN_ALBUM_PEAK");
|
||||
else
|
||||
addValue("REPLAYGAIN_ALBUM_PEAK", String::number(f), true);
|
||||
}
|
||||
|
||||
void APE::Tag::setRGTrackGain(float f)
|
||||
{
|
||||
if (f == 0)
|
||||
removeItem("REPLAYGAIN_TRACK_GAIN");
|
||||
else
|
||||
addValue("REPLAYGAIN_TRACK_GAIN", String::number(f) + " dB", true);
|
||||
}
|
||||
|
||||
void APE::Tag::setRGTrackPeak(float f)
|
||||
{
|
||||
if (f == 0)
|
||||
removeItem("REPLAYGAIN_TRACK_PEAK");
|
||||
else
|
||||
addValue("REPLAYGAIN_TRACK_PEAK", String::number(f), true);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
// conversions of tag keys between what we use in PropertyMap and what's usual
|
||||
// for APE tags
|
||||
// usual, APE
|
||||
const char *keyConversions[][2] = {{"TRACKNUMBER", "TRACK" },
|
||||
{"DATE", "YEAR" },
|
||||
{"ALBUMARTIST", "ALBUM ARTIST"},
|
||||
{"DISCNUMBER", "DISC" },
|
||||
{"REMIXER", "MIXARTIST" },
|
||||
{"RELEASESTATUS", "MUSICBRAINZ_ALBUMSTATUS" },
|
||||
{"RELEASETYPE", "MUSICBRAINZ_ALBUMTYPE" }};
|
||||
const size_t keyConversionsSize = sizeof(keyConversions) / sizeof(keyConversions[0]);
|
||||
}
|
||||
|
||||
PropertyMap APE::Tag::properties() const
|
||||
{
|
||||
PropertyMap properties;
|
||||
ItemListMap::ConstIterator it = itemListMap().begin();
|
||||
for(; it != itemListMap().end(); ++it) {
|
||||
String tagName = it->first.upper();
|
||||
// if the item is Binary or Locator, or if the key is an invalid string,
|
||||
// add to unsupportedData
|
||||
if(it->second.type() != Item::Text || tagName.isEmpty()) {
|
||||
properties.unsupportedData().append(it->first);
|
||||
}
|
||||
else {
|
||||
// Some tags need to be handled specially
|
||||
for(size_t i = 0; i < keyConversionsSize; ++i) {
|
||||
if(tagName == keyConversions[i][1])
|
||||
tagName = keyConversions[i][0];
|
||||
}
|
||||
properties[tagName].append(it->second.toStringList());
|
||||
}
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
void APE::Tag::removeUnsupportedProperties(const StringList &properties)
|
||||
{
|
||||
StringList::ConstIterator it = properties.begin();
|
||||
for(; it != properties.end(); ++it)
|
||||
removeItem(*it);
|
||||
}
|
||||
|
||||
PropertyMap APE::Tag::setProperties(const PropertyMap &origProps)
|
||||
{
|
||||
PropertyMap properties(origProps); // make a local copy that can be modified
|
||||
|
||||
// see comment in properties()
|
||||
for(size_t i = 0; i < keyConversionsSize; ++i)
|
||||
if(properties.contains(keyConversions[i][0])) {
|
||||
properties.insert(keyConversions[i][1], properties[keyConversions[i][0]]);
|
||||
properties.erase(keyConversions[i][0]);
|
||||
}
|
||||
|
||||
// first check if tags need to be removed completely
|
||||
StringList toRemove;
|
||||
ItemListMap::ConstIterator remIt = itemListMap().begin();
|
||||
for(; remIt != itemListMap().end(); ++remIt) {
|
||||
String key = remIt->first.upper();
|
||||
// only remove if a) key is valid, b) type is text, c) key not contained in new properties
|
||||
if(!key.isEmpty() && remIt->second.type() == APE::Item::Text && !properties.contains(key))
|
||||
toRemove.append(remIt->first);
|
||||
}
|
||||
|
||||
for(StringList::ConstIterator removeIt = toRemove.begin(); removeIt != toRemove.end(); removeIt++)
|
||||
removeItem(*removeIt);
|
||||
|
||||
// now sync in the "forward direction"
|
||||
PropertyMap::ConstIterator it = properties.begin();
|
||||
PropertyMap invalid;
|
||||
for(; it != properties.end(); ++it) {
|
||||
const String &tagName = it->first;
|
||||
if(!checkKey(tagName))
|
||||
invalid.insert(it->first, it->second);
|
||||
else if(!(itemListMap().contains(tagName)) || !(itemListMap()[tagName].values() == it->second)) {
|
||||
if(it->second.isEmpty())
|
||||
removeItem(tagName);
|
||||
else {
|
||||
StringList::ConstIterator valueIt = it->second.begin();
|
||||
addValue(tagName, *valueIt, true);
|
||||
++valueIt;
|
||||
for(; valueIt != it->second.end(); ++valueIt)
|
||||
addValue(tagName, *valueIt, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
return invalid;
|
||||
}
|
||||
|
||||
bool APE::Tag::checkKey(const String &key)
|
||||
{
|
||||
if(key.size() < MinKeyLength || key.size() > MaxKeyLength)
|
||||
return false;
|
||||
|
||||
return isKeyValid(key.data(String::UTF8));
|
||||
}
|
||||
|
||||
APE::Footer *APE::Tag::footer() const
|
||||
{
|
||||
return &d->footer;
|
||||
}
|
||||
|
||||
const APE::ItemListMap& APE::Tag::itemListMap() const
|
||||
{
|
||||
return d->itemListMap;
|
||||
}
|
||||
|
||||
void APE::Tag::removeItem(const String &key)
|
||||
{
|
||||
d->itemListMap.erase(key.upper());
|
||||
}
|
||||
|
||||
void APE::Tag::addValue(const String &key, const String &value, bool replace)
|
||||
{
|
||||
if(replace)
|
||||
removeItem(key);
|
||||
|
||||
if(value.isEmpty())
|
||||
return;
|
||||
|
||||
// Text items may contain more than one value.
|
||||
// Binary or locator items may have only one value, hence always replaced.
|
||||
|
||||
ItemListMap::Iterator it = d->itemListMap.find(key.upper());
|
||||
|
||||
if(it != d->itemListMap.end() && it->second.type() == Item::Text)
|
||||
it->second.appendValue(value);
|
||||
else
|
||||
setItem(key, Item(key, value));
|
||||
}
|
||||
|
||||
void APE::Tag::setData(const String &key, const ByteVector &value)
|
||||
{
|
||||
removeItem(key);
|
||||
|
||||
if(value.isEmpty())
|
||||
return;
|
||||
|
||||
setItem(key, Item(key, value, true));
|
||||
}
|
||||
|
||||
void APE::Tag::setItem(const String &key, const Item &item)
|
||||
{
|
||||
if(!checkKey(key)) {
|
||||
debug("APE::Tag::setItem() - Couldn't set an item due to an invalid key.");
|
||||
return;
|
||||
}
|
||||
|
||||
d->itemListMap[key.upper()] = item;
|
||||
}
|
||||
|
||||
bool APE::Tag::isEmpty() const
|
||||
{
|
||||
return d->itemListMap.isEmpty();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void APE::Tag::read()
|
||||
{
|
||||
if(d->file && d->file->isValid()) {
|
||||
|
||||
d->file->seek(d->footerLocation);
|
||||
d->footer.setData(d->file->readBlock(Footer::size()));
|
||||
|
||||
if(d->footer.tagSize() <= Footer::size() ||
|
||||
d->footer.tagSize() > static_cast<unsigned long>(d->file->length()))
|
||||
return;
|
||||
|
||||
d->file->seek(d->footerLocation + Footer::size() - d->footer.tagSize());
|
||||
parse(d->file->readBlock(d->footer.tagSize() - Footer::size()));
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector APE::Tag::render() const
|
||||
{
|
||||
ByteVector data;
|
||||
unsigned int itemCount = 0;
|
||||
|
||||
for(ItemListMap::ConstIterator it = d->itemListMap.begin(); it != d->itemListMap.end(); ++it) {
|
||||
data.append(it->second.render());
|
||||
itemCount++;
|
||||
}
|
||||
|
||||
d->footer.setItemCount(itemCount);
|
||||
d->footer.setTagSize(data.size() + Footer::size());
|
||||
d->footer.setHeaderPresent(true);
|
||||
|
||||
return d->footer.renderHeader() + data + d->footer.renderFooter();
|
||||
}
|
||||
|
||||
void APE::Tag::parse(const ByteVector &data)
|
||||
{
|
||||
// 11 bytes is the minimum size for an APE item
|
||||
|
||||
if(data.size() < 11)
|
||||
return;
|
||||
|
||||
unsigned int pos = 0;
|
||||
|
||||
for(unsigned int i = 0; i < d->footer.itemCount() && pos <= data.size() - 11; i++) {
|
||||
|
||||
const int nullPos = data.find('\0', pos + 8);
|
||||
if(nullPos < 0) {
|
||||
debug("APE::Tag::parse() - Couldn't find a key/value separator. Stopped parsing.");
|
||||
return;
|
||||
}
|
||||
|
||||
const unsigned int keyLength = nullPos - pos - 8;
|
||||
const unsigned int valLegnth = data.toUInt(pos, false);
|
||||
|
||||
if(keyLength >= MinKeyLength
|
||||
&& keyLength <= MaxKeyLength
|
||||
&& isKeyValid(data.mid(pos + 8, keyLength)))
|
||||
{
|
||||
APE::Item item;
|
||||
item.parse(data.mid(pos));
|
||||
|
||||
d->itemListMap.insert(item.key().upper(), item);
|
||||
}
|
||||
else {
|
||||
debug("APE::Tag::parse() - Skipped an item due to an invalid key.");
|
||||
}
|
||||
|
||||
pos += keyLength + valLegnth + 9;
|
||||
}
|
||||
}
|
|
@ -1,351 +0,0 @@
|
|||
/**************************************************************************
|
||||
copyright : (C) 2005-2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/toolkit/taglib.h>
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <taglib/toolkit/trefcounter.h>
|
||||
|
||||
#include <taglib/asf/asfattribute.h>
|
||||
#include <taglib/asf/asffile.h>
|
||||
#include <taglib/asf/asfutils.h>
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class ASF::Attribute::AttributePrivate : public RefCounter
|
||||
{
|
||||
public:
|
||||
AttributePrivate() :
|
||||
pictureValue(ASF::Picture::fromInvalid()),
|
||||
numericValue(0),
|
||||
stream(0),
|
||||
language(0) {}
|
||||
AttributeTypes type;
|
||||
String stringValue;
|
||||
ByteVector byteVectorValue;
|
||||
ASF::Picture pictureValue;
|
||||
unsigned long long numericValue;
|
||||
int stream;
|
||||
int language;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ASF::Attribute::Attribute() :
|
||||
d(new AttributePrivate())
|
||||
{
|
||||
d->type = UnicodeType;
|
||||
}
|
||||
|
||||
ASF::Attribute::Attribute(const ASF::Attribute &other) :
|
||||
d(other.d)
|
||||
{
|
||||
d->ref();
|
||||
}
|
||||
|
||||
ASF::Attribute::Attribute(const String &value) :
|
||||
d(new AttributePrivate())
|
||||
{
|
||||
d->type = UnicodeType;
|
||||
d->stringValue = value;
|
||||
}
|
||||
|
||||
ASF::Attribute::Attribute(const ByteVector &value) :
|
||||
d(new AttributePrivate())
|
||||
{
|
||||
d->type = BytesType;
|
||||
d->byteVectorValue = value;
|
||||
}
|
||||
|
||||
ASF::Attribute::Attribute(const ASF::Picture &value) :
|
||||
d(new AttributePrivate())
|
||||
{
|
||||
d->type = BytesType;
|
||||
d->pictureValue = value;
|
||||
}
|
||||
|
||||
ASF::Attribute::Attribute(unsigned int value) :
|
||||
d(new AttributePrivate())
|
||||
{
|
||||
d->type = DWordType;
|
||||
d->numericValue = value;
|
||||
}
|
||||
|
||||
ASF::Attribute::Attribute(unsigned long long value) :
|
||||
d(new AttributePrivate())
|
||||
{
|
||||
d->type = QWordType;
|
||||
d->numericValue = value;
|
||||
}
|
||||
|
||||
ASF::Attribute::Attribute(unsigned short value) :
|
||||
d(new AttributePrivate())
|
||||
{
|
||||
d->type = WordType;
|
||||
d->numericValue = value;
|
||||
}
|
||||
|
||||
ASF::Attribute::Attribute(bool value) :
|
||||
d(new AttributePrivate())
|
||||
{
|
||||
d->type = BoolType;
|
||||
d->numericValue = value;
|
||||
}
|
||||
|
||||
ASF::Attribute &ASF::Attribute::operator=(const ASF::Attribute &other)
|
||||
{
|
||||
Attribute(other).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void ASF::Attribute::swap(Attribute &other)
|
||||
{
|
||||
using std::swap;
|
||||
|
||||
swap(d, other.d);
|
||||
}
|
||||
|
||||
ASF::Attribute::~Attribute()
|
||||
{
|
||||
if(d->deref())
|
||||
delete d;
|
||||
}
|
||||
|
||||
ASF::Attribute::AttributeTypes ASF::Attribute::type() const
|
||||
{
|
||||
return d->type;
|
||||
}
|
||||
|
||||
String ASF::Attribute::toString() const
|
||||
{
|
||||
return d->stringValue;
|
||||
}
|
||||
|
||||
ByteVector ASF::Attribute::toByteVector() const
|
||||
{
|
||||
if(d->pictureValue.isValid())
|
||||
return d->pictureValue.render();
|
||||
return d->byteVectorValue;
|
||||
}
|
||||
|
||||
unsigned short ASF::Attribute::toBool() const
|
||||
{
|
||||
return d->numericValue ? 1 : 0;
|
||||
}
|
||||
|
||||
unsigned short ASF::Attribute::toUShort() const
|
||||
{
|
||||
return static_cast<unsigned short>(d->numericValue);
|
||||
}
|
||||
|
||||
unsigned int ASF::Attribute::toUInt() const
|
||||
{
|
||||
return static_cast<unsigned int>(d->numericValue);
|
||||
}
|
||||
|
||||
unsigned long long ASF::Attribute::toULongLong() const
|
||||
{
|
||||
return static_cast<unsigned long long>(d->numericValue);
|
||||
}
|
||||
|
||||
ASF::Picture ASF::Attribute::toPicture() const
|
||||
{
|
||||
return d->pictureValue;
|
||||
}
|
||||
|
||||
String ASF::Attribute::parse(ASF::File &f, int kind)
|
||||
{
|
||||
unsigned int size, nameLength;
|
||||
String name;
|
||||
d->pictureValue = Picture::fromInvalid();
|
||||
// extended content descriptor
|
||||
if(kind == 0) {
|
||||
nameLength = readWORD(&f);
|
||||
name = readString(&f, nameLength);
|
||||
d->type = ASF::Attribute::AttributeTypes(readWORD(&f));
|
||||
size = readWORD(&f);
|
||||
}
|
||||
// metadata & metadata library
|
||||
else {
|
||||
int temp = readWORD(&f);
|
||||
// metadata library
|
||||
if(kind == 2) {
|
||||
d->language = temp;
|
||||
}
|
||||
d->stream = readWORD(&f);
|
||||
nameLength = readWORD(&f);
|
||||
d->type = ASF::Attribute::AttributeTypes(readWORD(&f));
|
||||
size = readDWORD(&f);
|
||||
name = readString(&f, nameLength);
|
||||
}
|
||||
|
||||
if(kind != 2 && size > 65535) {
|
||||
debug("ASF::Attribute::parse() -- Value larger than 64kB");
|
||||
}
|
||||
|
||||
switch(d->type) {
|
||||
case WordType:
|
||||
d->numericValue = readWORD(&f);
|
||||
break;
|
||||
|
||||
case BoolType:
|
||||
if(kind == 0) {
|
||||
d->numericValue = (readDWORD(&f) != 0);
|
||||
}
|
||||
else {
|
||||
d->numericValue = (readWORD(&f) != 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case DWordType:
|
||||
d->numericValue = readDWORD(&f);
|
||||
break;
|
||||
|
||||
case QWordType:
|
||||
d->numericValue = readQWORD(&f);
|
||||
break;
|
||||
|
||||
case UnicodeType:
|
||||
d->stringValue = readString(&f, size);
|
||||
break;
|
||||
|
||||
case BytesType:
|
||||
case GuidType:
|
||||
d->byteVectorValue = f.readBlock(size);
|
||||
break;
|
||||
}
|
||||
|
||||
if(d->type == BytesType && name == "WM/Picture") {
|
||||
d->pictureValue.parse(d->byteVectorValue);
|
||||
if(d->pictureValue.isValid()) {
|
||||
d->byteVectorValue.clear();
|
||||
}
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
int ASF::Attribute::dataSize() const
|
||||
{
|
||||
switch (d->type) {
|
||||
case WordType:
|
||||
return 2;
|
||||
case BoolType:
|
||||
return 4;
|
||||
case DWordType:
|
||||
return 4;
|
||||
case QWordType:
|
||||
return 5;
|
||||
case UnicodeType:
|
||||
return d->stringValue.size() * 2 + 2;
|
||||
case BytesType:
|
||||
if(d->pictureValue.isValid())
|
||||
return d->pictureValue.dataSize();
|
||||
case GuidType:
|
||||
return d->byteVectorValue.size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ByteVector ASF::Attribute::render(const String &name, int kind) const
|
||||
{
|
||||
ByteVector data;
|
||||
|
||||
switch (d->type) {
|
||||
case WordType:
|
||||
data.append(ByteVector::fromShort(toUShort(), false));
|
||||
break;
|
||||
|
||||
case BoolType:
|
||||
if(kind == 0) {
|
||||
data.append(ByteVector::fromUInt(toBool(), false));
|
||||
}
|
||||
else {
|
||||
data.append(ByteVector::fromShort(toBool(), false));
|
||||
}
|
||||
break;
|
||||
|
||||
case DWordType:
|
||||
data.append(ByteVector::fromUInt(toUInt(), false));
|
||||
break;
|
||||
|
||||
case QWordType:
|
||||
data.append(ByteVector::fromLongLong(toULongLong(), false));
|
||||
break;
|
||||
|
||||
case UnicodeType:
|
||||
data.append(renderString(d->stringValue));
|
||||
break;
|
||||
|
||||
case BytesType:
|
||||
if(d->pictureValue.isValid()) {
|
||||
data.append(d->pictureValue.render());
|
||||
break;
|
||||
}
|
||||
case GuidType:
|
||||
data.append(d->byteVectorValue);
|
||||
break;
|
||||
}
|
||||
|
||||
if(kind == 0) {
|
||||
data = renderString(name, true) +
|
||||
ByteVector::fromShort((int)d->type, false) +
|
||||
ByteVector::fromShort(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((int)d->type, false) +
|
||||
ByteVector::fromUInt(data.size(), false) +
|
||||
nameData +
|
||||
data;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
int ASF::Attribute::language() const
|
||||
{
|
||||
return d->language;
|
||||
}
|
||||
|
||||
void ASF::Attribute::setLanguage(int value)
|
||||
{
|
||||
d->language = value;
|
||||
}
|
||||
|
||||
int ASF::Attribute::stream() const
|
||||
{
|
||||
return d->stream;
|
||||
}
|
||||
|
||||
void ASF::Attribute::setStream(int value)
|
||||
{
|
||||
d->stream = value;
|
||||
}
|
|
@ -1,705 +0,0 @@
|
|||
/**************************************************************************
|
||||
copyright : (C) 2005-2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <taglib/toolkit/tbytevectorlist.h>
|
||||
#include <taglib/toolkit/tpropertymap.h>
|
||||
#include <taglib/toolkit/tstring.h>
|
||||
#include <taglib/tagutils.h>
|
||||
|
||||
#include <taglib/asf/asffile.h>
|
||||
#include <taglib/asf/asftag.h>
|
||||
#include <taglib/asf/asfproperties.h>
|
||||
#include <taglib/asf/asfutils.h>
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class ASF::File::FilePrivate
|
||||
{
|
||||
public:
|
||||
class BaseObject;
|
||||
class UnknownObject;
|
||||
class FilePropertiesObject;
|
||||
class StreamPropertiesObject;
|
||||
class ContentDescriptionObject;
|
||||
class ExtendedContentDescriptionObject;
|
||||
class HeaderExtensionObject;
|
||||
class CodecListObject;
|
||||
class MetadataObject;
|
||||
class MetadataLibraryObject;
|
||||
|
||||
FilePrivate():
|
||||
headerSize(0),
|
||||
tag(0),
|
||||
properties(0),
|
||||
contentDescriptionObject(0),
|
||||
extendedContentDescriptionObject(0),
|
||||
headerExtensionObject(0),
|
||||
metadataObject(0),
|
||||
metadataLibraryObject(0)
|
||||
{
|
||||
objects.setAutoDelete(true);
|
||||
}
|
||||
|
||||
~FilePrivate()
|
||||
{
|
||||
delete tag;
|
||||
delete properties;
|
||||
}
|
||||
|
||||
unsigned long long headerSize;
|
||||
|
||||
ASF::Tag *tag;
|
||||
ASF::Properties *properties;
|
||||
|
||||
List<BaseObject *> objects;
|
||||
|
||||
ContentDescriptionObject *contentDescriptionObject;
|
||||
ExtendedContentDescriptionObject *extendedContentDescriptionObject;
|
||||
HeaderExtensionObject *headerExtensionObject;
|
||||
MetadataObject *metadataObject;
|
||||
MetadataLibraryObject *metadataLibraryObject;
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
const ByteVector headerGuid("\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
|
||||
const ByteVector filePropertiesGuid("\xA1\xDC\xAB\x8C\x47\xA9\xCF\x11\x8E\xE4\x00\xC0\x0C\x20\x53\x65", 16);
|
||||
const ByteVector streamPropertiesGuid("\x91\x07\xDC\xB7\xB7\xA9\xCF\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65", 16);
|
||||
const ByteVector contentDescriptionGuid("\x33\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
|
||||
const ByteVector extendedContentDescriptionGuid("\x40\xA4\xD0\xD2\x07\xE3\xD2\x11\x97\xF0\x00\xA0\xC9\x5E\xA8\x50", 16);
|
||||
const ByteVector headerExtensionGuid("\xb5\x03\xbf_.\xa9\xcf\x11\x8e\xe3\x00\xc0\x0c Se", 16);
|
||||
const ByteVector metadataGuid("\xEA\xCB\xF8\xC5\xAF[wH\204g\xAA\214D\xFAL\xCA", 16);
|
||||
const ByteVector metadataLibraryGuid("\224\034#D\230\224\321I\241A\x1d\x13NEpT", 16);
|
||||
const ByteVector codecListGuid("\x40\x52\xd1\x86\x1d\x31\xd0\x11\xa3\xa4\x00\xa0\xc9\x03\x48\xf6", 16);
|
||||
const ByteVector contentEncryptionGuid("\xFB\xB3\x11\x22\x23\xBD\xD2\x11\xB4\xB7\x00\xA0\xC9\x55\xFC\x6E", 16);
|
||||
const ByteVector extendedContentEncryptionGuid("\x14\xE6\x8A\x29\x22\x26 \x17\x4C\xB9\x35\xDA\xE0\x7E\xE9\x28\x9C", 16);
|
||||
const ByteVector advancedContentEncryptionGuid("\xB6\x9B\x07\x7A\xA4\xDA\x12\x4E\xA5\xCA\x91\xD3\x8D\xC1\x1A\x8D", 16);
|
||||
}
|
||||
|
||||
class ASF::File::FilePrivate::BaseObject
|
||||
{
|
||||
public:
|
||||
ByteVector data;
|
||||
virtual ~BaseObject() {}
|
||||
virtual ByteVector guid() const = 0;
|
||||
virtual void parse(ASF::File *file, unsigned int size);
|
||||
virtual ByteVector render(ASF::File *file);
|
||||
};
|
||||
|
||||
class ASF::File::FilePrivate::UnknownObject : public ASF::File::FilePrivate::BaseObject
|
||||
{
|
||||
ByteVector myGuid;
|
||||
public:
|
||||
UnknownObject(const ByteVector &guid);
|
||||
ByteVector guid() const;
|
||||
};
|
||||
|
||||
class ASF::File::FilePrivate::FilePropertiesObject : public ASF::File::FilePrivate::BaseObject
|
||||
{
|
||||
public:
|
||||
ByteVector guid() const;
|
||||
void parse(ASF::File *file, unsigned int size);
|
||||
};
|
||||
|
||||
class ASF::File::FilePrivate::StreamPropertiesObject : public ASF::File::FilePrivate::BaseObject
|
||||
{
|
||||
public:
|
||||
ByteVector guid() const;
|
||||
void parse(ASF::File *file, unsigned int size);
|
||||
};
|
||||
|
||||
class ASF::File::FilePrivate::ContentDescriptionObject : public ASF::File::FilePrivate::BaseObject
|
||||
{
|
||||
public:
|
||||
ByteVector guid() const;
|
||||
void parse(ASF::File *file, unsigned int size);
|
||||
ByteVector render(ASF::File *file);
|
||||
};
|
||||
|
||||
class ASF::File::FilePrivate::ExtendedContentDescriptionObject : public ASF::File::FilePrivate::BaseObject
|
||||
{
|
||||
public:
|
||||
ByteVectorList attributeData;
|
||||
ByteVector guid() const;
|
||||
void parse(ASF::File *file, unsigned int size);
|
||||
ByteVector render(ASF::File *file);
|
||||
};
|
||||
|
||||
class ASF::File::FilePrivate::MetadataObject : public ASF::File::FilePrivate::BaseObject
|
||||
{
|
||||
public:
|
||||
ByteVectorList attributeData;
|
||||
ByteVector guid() const;
|
||||
void parse(ASF::File *file, unsigned int size);
|
||||
ByteVector render(ASF::File *file);
|
||||
};
|
||||
|
||||
class ASF::File::FilePrivate::MetadataLibraryObject : public ASF::File::FilePrivate::BaseObject
|
||||
{
|
||||
public:
|
||||
ByteVectorList attributeData;
|
||||
ByteVector guid() const;
|
||||
void parse(ASF::File *file, unsigned int size);
|
||||
ByteVector render(ASF::File *file);
|
||||
};
|
||||
|
||||
class ASF::File::FilePrivate::HeaderExtensionObject : public ASF::File::FilePrivate::BaseObject
|
||||
{
|
||||
public:
|
||||
List<ASF::File::FilePrivate::BaseObject *> objects;
|
||||
HeaderExtensionObject();
|
||||
ByteVector guid() const;
|
||||
void parse(ASF::File *file, unsigned int size);
|
||||
ByteVector render(ASF::File *file);
|
||||
};
|
||||
|
||||
class ASF::File::FilePrivate::CodecListObject : public ASF::File::FilePrivate::BaseObject
|
||||
{
|
||||
public:
|
||||
ByteVector guid() const;
|
||||
void parse(ASF::File *file, unsigned int size);
|
||||
|
||||
private:
|
||||
enum CodecType
|
||||
{
|
||||
Video = 0x0001,
|
||||
Audio = 0x0002,
|
||||
Unknown = 0xFFFF
|
||||
};
|
||||
};
|
||||
|
||||
void ASF::File::FilePrivate::BaseObject::parse(ASF::File *file, unsigned int size)
|
||||
{
|
||||
data.clear();
|
||||
if(size > 24 && size <= (unsigned int)(file->length()))
|
||||
data = file->readBlock(size - 24);
|
||||
else
|
||||
data = ByteVector();
|
||||
}
|
||||
|
||||
ByteVector ASF::File::FilePrivate::BaseObject::render(ASF::File * /*file*/)
|
||||
{
|
||||
return guid() + ByteVector::fromLongLong(data.size() + 24, false) + data;
|
||||
}
|
||||
|
||||
ASF::File::FilePrivate::UnknownObject::UnknownObject(const ByteVector &guid) : myGuid(guid)
|
||||
{
|
||||
}
|
||||
|
||||
ByteVector ASF::File::FilePrivate::UnknownObject::guid() const
|
||||
{
|
||||
return myGuid;
|
||||
}
|
||||
|
||||
ByteVector ASF::File::FilePrivate::FilePropertiesObject::guid() const
|
||||
{
|
||||
return filePropertiesGuid;
|
||||
}
|
||||
|
||||
void ASF::File::FilePrivate::FilePropertiesObject::parse(ASF::File *file, unsigned int size)
|
||||
{
|
||||
BaseObject::parse(file, size);
|
||||
if(data.size() < 64) {
|
||||
debug("ASF::File::FilePrivate::FilePropertiesObject::parse() -- data is too short.");
|
||||
return;
|
||||
}
|
||||
|
||||
const long long duration = data.toLongLong(40, false);
|
||||
const long long preroll = data.toLongLong(56, false);
|
||||
file->d->properties->setLengthInMilliseconds(static_cast<int>(duration / 10000.0 - preroll + 0.5));
|
||||
}
|
||||
|
||||
ByteVector ASF::File::FilePrivate::StreamPropertiesObject::guid() const
|
||||
{
|
||||
return streamPropertiesGuid;
|
||||
}
|
||||
|
||||
void ASF::File::FilePrivate::StreamPropertiesObject::parse(ASF::File *file, unsigned int size)
|
||||
{
|
||||
BaseObject::parse(file, size);
|
||||
if(data.size() < 70) {
|
||||
debug("ASF::File::FilePrivate::StreamPropertiesObject::parse() -- data is too short.");
|
||||
return;
|
||||
}
|
||||
|
||||
file->d->properties->setCodec(data.toUShort(54, false));
|
||||
file->d->properties->setChannels(data.toUShort(56, false));
|
||||
file->d->properties->setSampleRate(data.toUInt(58, false));
|
||||
file->d->properties->setBitrate(static_cast<int>(data.toUInt(62, false) * 8.0 / 1000.0 + 0.5));
|
||||
file->d->properties->setBitsPerSample(data.toUShort(68, false));
|
||||
}
|
||||
|
||||
ByteVector ASF::File::FilePrivate::ContentDescriptionObject::guid() const
|
||||
{
|
||||
return contentDescriptionGuid;
|
||||
}
|
||||
|
||||
void ASF::File::FilePrivate::ContentDescriptionObject::parse(ASF::File *file, unsigned int /*size*/)
|
||||
{
|
||||
const int titleLength = readWORD(file);
|
||||
const int artistLength = readWORD(file);
|
||||
const int copyrightLength = readWORD(file);
|
||||
const int commentLength = readWORD(file);
|
||||
const int ratingLength = readWORD(file);
|
||||
file->d->tag->setTitle(readString(file,titleLength));
|
||||
file->d->tag->setArtist(readString(file,artistLength));
|
||||
file->d->tag->setCopyright(readString(file,copyrightLength));
|
||||
file->d->tag->setComment(readString(file,commentLength));
|
||||
file->d->tag->setRating(readString(file,ratingLength));
|
||||
}
|
||||
|
||||
ByteVector ASF::File::FilePrivate::ContentDescriptionObject::render(ASF::File *file)
|
||||
{
|
||||
const ByteVector v1 = renderString(file->d->tag->title());
|
||||
const ByteVector v2 = renderString(file->d->tag->artist());
|
||||
const ByteVector v3 = renderString(file->d->tag->copyright());
|
||||
const ByteVector v4 = renderString(file->d->tag->comment());
|
||||
const ByteVector v5 = renderString(file->d->tag->rating());
|
||||
data.clear();
|
||||
data.append(ByteVector::fromShort(v1.size(), false));
|
||||
data.append(ByteVector::fromShort(v2.size(), false));
|
||||
data.append(ByteVector::fromShort(v3.size(), false));
|
||||
data.append(ByteVector::fromShort(v4.size(), false));
|
||||
data.append(ByteVector::fromShort(v5.size(), false));
|
||||
data.append(v1);
|
||||
data.append(v2);
|
||||
data.append(v3);
|
||||
data.append(v4);
|
||||
data.append(v5);
|
||||
return BaseObject::render(file);
|
||||
}
|
||||
|
||||
ByteVector ASF::File::FilePrivate::ExtendedContentDescriptionObject::guid() const
|
||||
{
|
||||
return extendedContentDescriptionGuid;
|
||||
}
|
||||
|
||||
void ASF::File::FilePrivate::ExtendedContentDescriptionObject::parse(ASF::File *file, unsigned int /*size*/)
|
||||
{
|
||||
int count = readWORD(file);
|
||||
while(count--) {
|
||||
ASF::Attribute attribute;
|
||||
String name = attribute.parse(*file);
|
||||
file->d->tag->addAttribute(name, attribute);
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector ASF::File::FilePrivate::ExtendedContentDescriptionObject::render(ASF::File *file)
|
||||
{
|
||||
data.clear();
|
||||
data.append(ByteVector::fromShort(attributeData.size(), false));
|
||||
data.append(attributeData.toByteVector(""));
|
||||
return BaseObject::render(file);
|
||||
}
|
||||
|
||||
ByteVector ASF::File::FilePrivate::MetadataObject::guid() const
|
||||
{
|
||||
return metadataGuid;
|
||||
}
|
||||
|
||||
void ASF::File::FilePrivate::MetadataObject::parse(ASF::File *file, unsigned int /*size*/)
|
||||
{
|
||||
int count = readWORD(file);
|
||||
while(count--) {
|
||||
ASF::Attribute attribute;
|
||||
String name = attribute.parse(*file, 1);
|
||||
file->d->tag->addAttribute(name, attribute);
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector ASF::File::FilePrivate::MetadataObject::render(ASF::File *file)
|
||||
{
|
||||
data.clear();
|
||||
data.append(ByteVector::fromShort(attributeData.size(), false));
|
||||
data.append(attributeData.toByteVector(""));
|
||||
return BaseObject::render(file);
|
||||
}
|
||||
|
||||
ByteVector ASF::File::FilePrivate::MetadataLibraryObject::guid() const
|
||||
{
|
||||
return metadataLibraryGuid;
|
||||
}
|
||||
|
||||
void ASF::File::FilePrivate::MetadataLibraryObject::parse(ASF::File *file, unsigned int /*size*/)
|
||||
{
|
||||
int count = readWORD(file);
|
||||
while(count--) {
|
||||
ASF::Attribute attribute;
|
||||
String name = attribute.parse(*file, 2);
|
||||
file->d->tag->addAttribute(name, attribute);
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector ASF::File::FilePrivate::MetadataLibraryObject::render(ASF::File *file)
|
||||
{
|
||||
data.clear();
|
||||
data.append(ByteVector::fromShort(attributeData.size(), false));
|
||||
data.append(attributeData.toByteVector(""));
|
||||
return BaseObject::render(file);
|
||||
}
|
||||
|
||||
ASF::File::FilePrivate::HeaderExtensionObject::HeaderExtensionObject()
|
||||
{
|
||||
objects.setAutoDelete(true);
|
||||
}
|
||||
|
||||
ByteVector ASF::File::FilePrivate::HeaderExtensionObject::guid() const
|
||||
{
|
||||
return headerExtensionGuid;
|
||||
}
|
||||
|
||||
void ASF::File::FilePrivate::HeaderExtensionObject::parse(ASF::File *file, unsigned int /*size*/)
|
||||
{
|
||||
file->seek(18, File::Current);
|
||||
long long dataSize = readDWORD(file);
|
||||
long long dataPos = 0;
|
||||
while(dataPos < dataSize) {
|
||||
ByteVector guid = file->readBlock(16);
|
||||
if(guid.size() != 16) {
|
||||
file->setValid(false);
|
||||
break;
|
||||
}
|
||||
bool ok;
|
||||
long long size = readQWORD(file, &ok);
|
||||
if(!ok) {
|
||||
file->setValid(false);
|
||||
break;
|
||||
}
|
||||
BaseObject *obj;
|
||||
if(guid == metadataGuid) {
|
||||
file->d->metadataObject = new MetadataObject();
|
||||
obj = file->d->metadataObject;
|
||||
}
|
||||
else if(guid == metadataLibraryGuid) {
|
||||
file->d->metadataLibraryObject = new MetadataLibraryObject();
|
||||
obj = file->d->metadataLibraryObject;
|
||||
}
|
||||
else {
|
||||
obj = new UnknownObject(guid);
|
||||
}
|
||||
obj->parse(file, (unsigned int)size);
|
||||
objects.append(obj);
|
||||
dataPos += size;
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector ASF::File::FilePrivate::HeaderExtensionObject::render(ASF::File *file)
|
||||
{
|
||||
data.clear();
|
||||
for(List<BaseObject *>::ConstIterator it = objects.begin(); it != objects.end(); ++it) {
|
||||
data.append((*it)->render(file));
|
||||
}
|
||||
data = ByteVector("\x11\xD2\xD3\xAB\xBA\xA9\xcf\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65\x06\x00", 18) + ByteVector::fromUInt(data.size(), false) + data;
|
||||
return BaseObject::render(file);
|
||||
}
|
||||
|
||||
ByteVector ASF::File::FilePrivate::CodecListObject::guid() const
|
||||
{
|
||||
return codecListGuid;
|
||||
}
|
||||
|
||||
void ASF::File::FilePrivate::CodecListObject::parse(ASF::File *file, unsigned int size)
|
||||
{
|
||||
BaseObject::parse(file, size);
|
||||
if(data.size() <= 20) {
|
||||
debug("ASF::File::FilePrivate::CodecListObject::parse() -- data is too short.");
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int pos = 16;
|
||||
|
||||
const int count = data.toUInt(pos, false);
|
||||
pos += 4;
|
||||
|
||||
for(int i = 0; i < count; ++i) {
|
||||
|
||||
if(pos >= data.size())
|
||||
break;
|
||||
|
||||
const CodecType type = static_cast<CodecType>(data.toUShort(pos, false));
|
||||
pos += 2;
|
||||
|
||||
int nameLength = data.toUShort(pos, false);
|
||||
pos += 2;
|
||||
|
||||
const unsigned int namePos = pos;
|
||||
pos += nameLength * 2;
|
||||
|
||||
const int descLength = data.toUShort(pos, false);
|
||||
pos += 2;
|
||||
|
||||
const unsigned int descPos = pos;
|
||||
pos += descLength * 2;
|
||||
|
||||
const int infoLength = data.toUShort(pos, false);
|
||||
pos += 2 + infoLength * 2;
|
||||
|
||||
if(type == CodecListObject::Audio) {
|
||||
// First audio codec found.
|
||||
|
||||
const String name(data.mid(namePos, nameLength * 2), String::UTF16LE);
|
||||
file->d->properties->setCodecName(name.stripWhiteSpace());
|
||||
|
||||
const String desc(data.mid(descPos, descLength * 2), String::UTF16LE);
|
||||
file->d->properties->setCodecDescription(desc.stripWhiteSpace());
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// static members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool ASF::File::isSupported(IOStream *stream)
|
||||
{
|
||||
// An ASF file has to start with the designated GUID.
|
||||
|
||||
const ByteVector id = Utils::readHeader(stream, 16, false);
|
||||
return (id == headerGuid);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ASF::File::File(FileName file, bool, Properties::ReadStyle) :
|
||||
TagLib::File(file),
|
||||
d(new FilePrivate())
|
||||
{
|
||||
if(isOpen())
|
||||
read();
|
||||
}
|
||||
|
||||
ASF::File::File(IOStream *stream, bool, Properties::ReadStyle) :
|
||||
TagLib::File(stream),
|
||||
d(new FilePrivate())
|
||||
{
|
||||
if(isOpen())
|
||||
read();
|
||||
}
|
||||
|
||||
ASF::File::~File()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
ASF::Tag *ASF::File::tag() const
|
||||
{
|
||||
return d->tag;
|
||||
}
|
||||
|
||||
PropertyMap ASF::File::properties() const
|
||||
{
|
||||
return d->tag->properties();
|
||||
}
|
||||
|
||||
void ASF::File::removeUnsupportedProperties(const StringList &properties)
|
||||
{
|
||||
d->tag->removeUnsupportedProperties(properties);
|
||||
}
|
||||
|
||||
PropertyMap ASF::File::setProperties(const PropertyMap &properties)
|
||||
{
|
||||
return d->tag->setProperties(properties);
|
||||
}
|
||||
|
||||
ASF::Properties *ASF::File::audioProperties() const
|
||||
{
|
||||
return d->properties;
|
||||
}
|
||||
|
||||
bool ASF::File::save()
|
||||
{
|
||||
if(readOnly()) {
|
||||
debug("ASF::File::save() -- File is read only.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!isValid()) {
|
||||
debug("ASF::File::save() -- Trying to save invalid file.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!d->contentDescriptionObject) {
|
||||
d->contentDescriptionObject = new FilePrivate::ContentDescriptionObject();
|
||||
d->objects.append(d->contentDescriptionObject);
|
||||
}
|
||||
if(!d->extendedContentDescriptionObject) {
|
||||
d->extendedContentDescriptionObject = new FilePrivate::ExtendedContentDescriptionObject();
|
||||
d->objects.append(d->extendedContentDescriptionObject);
|
||||
}
|
||||
if(!d->headerExtensionObject) {
|
||||
d->headerExtensionObject = new FilePrivate::HeaderExtensionObject();
|
||||
d->objects.append(d->headerExtensionObject);
|
||||
}
|
||||
if(!d->metadataObject) {
|
||||
d->metadataObject = new FilePrivate::MetadataObject();
|
||||
d->headerExtensionObject->objects.append(d->metadataObject);
|
||||
}
|
||||
if(!d->metadataLibraryObject) {
|
||||
d->metadataLibraryObject = new FilePrivate::MetadataLibraryObject();
|
||||
d->headerExtensionObject->objects.append(d->metadataLibraryObject);
|
||||
}
|
||||
|
||||
d->extendedContentDescriptionObject->attributeData.clear();
|
||||
d->metadataObject->attributeData.clear();
|
||||
d->metadataLibraryObject->attributeData.clear();
|
||||
|
||||
const AttributeListMap allAttributes = d->tag->attributeListMap();
|
||||
|
||||
for(AttributeListMap::ConstIterator it = allAttributes.begin(); it != allAttributes.end(); ++it) {
|
||||
|
||||
const String &name = it->first;
|
||||
const AttributeList &attributes = it->second;
|
||||
|
||||
bool inExtendedContentDescriptionObject = false;
|
||||
bool inMetadataObject = false;
|
||||
|
||||
for(AttributeList::ConstIterator jt = attributes.begin(); jt != attributes.end(); ++jt) {
|
||||
|
||||
const Attribute &attribute = *jt;
|
||||
const bool largeValue = (attribute.dataSize() > 65535);
|
||||
const bool guid = (attribute.type() == Attribute::GuidType);
|
||||
|
||||
if(!inExtendedContentDescriptionObject && !guid && !largeValue && attribute.language() == 0 && attribute.stream() == 0) {
|
||||
d->extendedContentDescriptionObject->attributeData.append(attribute.render(name));
|
||||
inExtendedContentDescriptionObject = true;
|
||||
}
|
||||
else if(!inMetadataObject && !guid && !largeValue && attribute.language() == 0 && attribute.stream() != 0) {
|
||||
d->metadataObject->attributeData.append(attribute.render(name, 1));
|
||||
inMetadataObject = true;
|
||||
}
|
||||
else {
|
||||
d->metadataLibraryObject->attributeData.append(attribute.render(name, 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector data;
|
||||
for(List<FilePrivate::BaseObject *>::ConstIterator it = d->objects.begin(); it != d->objects.end(); ++it) {
|
||||
data.append((*it)->render(this));
|
||||
}
|
||||
|
||||
seek(16);
|
||||
writeBlock(ByteVector::fromLongLong(data.size() + 30, false));
|
||||
writeBlock(ByteVector::fromUInt(d->objects.size(), false));
|
||||
writeBlock(ByteVector("\x01\x02", 2));
|
||||
|
||||
insert(data, 30, static_cast<unsigned long>(d->headerSize - 30));
|
||||
|
||||
d->headerSize = data.size() + 30;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ASF::File::read()
|
||||
{
|
||||
if(!isValid())
|
||||
return;
|
||||
|
||||
if(readBlock(16) != headerGuid) {
|
||||
debug("ASF::File::read(): Not an ASF file.");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
d->tag = new ASF::Tag();
|
||||
d->properties = new ASF::Properties();
|
||||
|
||||
bool ok;
|
||||
d->headerSize = readQWORD(this, &ok);
|
||||
if(!ok) {
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
int numObjects = readDWORD(this, &ok);
|
||||
if(!ok) {
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
seek(2, Current);
|
||||
|
||||
FilePrivate::FilePropertiesObject *filePropertiesObject = 0;
|
||||
FilePrivate::StreamPropertiesObject *streamPropertiesObject = 0;
|
||||
for(int i = 0; i < numObjects; i++) {
|
||||
const ByteVector guid = readBlock(16);
|
||||
if(guid.size() != 16) {
|
||||
setValid(false);
|
||||
break;
|
||||
}
|
||||
long size = (long)readQWORD(this, &ok);
|
||||
if(!ok) {
|
||||
setValid(false);
|
||||
break;
|
||||
}
|
||||
FilePrivate::BaseObject *obj;
|
||||
if(guid == filePropertiesGuid) {
|
||||
filePropertiesObject = new FilePrivate::FilePropertiesObject();
|
||||
obj = filePropertiesObject;
|
||||
}
|
||||
else if(guid == streamPropertiesGuid) {
|
||||
streamPropertiesObject = new FilePrivate::StreamPropertiesObject();
|
||||
obj = streamPropertiesObject;
|
||||
}
|
||||
else if(guid == contentDescriptionGuid) {
|
||||
d->contentDescriptionObject = new FilePrivate::ContentDescriptionObject();
|
||||
obj = d->contentDescriptionObject;
|
||||
}
|
||||
else if(guid == extendedContentDescriptionGuid) {
|
||||
d->extendedContentDescriptionObject = new FilePrivate::ExtendedContentDescriptionObject();
|
||||
obj = d->extendedContentDescriptionObject;
|
||||
}
|
||||
else if(guid == headerExtensionGuid) {
|
||||
d->headerExtensionObject = new FilePrivate::HeaderExtensionObject();
|
||||
obj = d->headerExtensionObject;
|
||||
}
|
||||
else if(guid == codecListGuid) {
|
||||
obj = new FilePrivate::CodecListObject();
|
||||
}
|
||||
else {
|
||||
if(guid == contentEncryptionGuid ||
|
||||
guid == extendedContentEncryptionGuid ||
|
||||
guid == advancedContentEncryptionGuid) {
|
||||
d->properties->setEncrypted(true);
|
||||
}
|
||||
obj = new FilePrivate::UnknownObject(guid);
|
||||
}
|
||||
obj->parse(this, size);
|
||||
d->objects.append(obj);
|
||||
}
|
||||
|
||||
if(!filePropertiesObject || !streamPropertiesObject) {
|
||||
debug("ASF::File::read(): Missing mandatory header objects.");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
}
|
|
@ -1,183 +0,0 @@
|
|||
/**************************************************************************
|
||||
copyright : (C) 2010 by Anton Sergunov
|
||||
email : setosha@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/toolkit/taglib.h>
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <taglib/toolkit/trefcounter.h>
|
||||
|
||||
#include <taglib/asf/asfattribute.h>
|
||||
#include <taglib/asf/asffile.h>
|
||||
#include <taglib/asf/asfpicture.h>
|
||||
#include <taglib/asf/asfutils.h>
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class ASF::Picture::PicturePrivate : public RefCounter
|
||||
{
|
||||
public:
|
||||
bool valid;
|
||||
Type type;
|
||||
String mimeType;
|
||||
String description;
|
||||
ByteVector picture;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Picture class members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ASF::Picture::Picture() :
|
||||
d(new PicturePrivate())
|
||||
{
|
||||
d->valid = true;
|
||||
}
|
||||
|
||||
ASF::Picture::Picture(const Picture& other) :
|
||||
d(other.d)
|
||||
{
|
||||
d->ref();
|
||||
}
|
||||
|
||||
ASF::Picture::~Picture()
|
||||
{
|
||||
if(d->deref())
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool ASF::Picture::isValid() const
|
||||
{
|
||||
return d->valid;
|
||||
}
|
||||
|
||||
String ASF::Picture::mimeType() const
|
||||
{
|
||||
return d->mimeType;
|
||||
}
|
||||
|
||||
void ASF::Picture::setMimeType(const String &value)
|
||||
{
|
||||
d->mimeType = value;
|
||||
}
|
||||
|
||||
ASF::Picture::Type ASF::Picture::type() const
|
||||
{
|
||||
return d->type;
|
||||
}
|
||||
|
||||
void ASF::Picture::setType(const ASF::Picture::Type& t)
|
||||
{
|
||||
d->type = t;
|
||||
}
|
||||
|
||||
String ASF::Picture::description() const
|
||||
{
|
||||
return d->description;
|
||||
}
|
||||
|
||||
void ASF::Picture::setDescription(const String &desc)
|
||||
{
|
||||
d->description = desc;
|
||||
}
|
||||
|
||||
ByteVector ASF::Picture::picture() const
|
||||
{
|
||||
return d->picture;
|
||||
}
|
||||
|
||||
void ASF::Picture::setPicture(const ByteVector &p)
|
||||
{
|
||||
d->picture = p;
|
||||
}
|
||||
|
||||
int ASF::Picture::dataSize() const
|
||||
{
|
||||
return
|
||||
9 + (d->mimeType.length() + d->description.length()) * 2 +
|
||||
d->picture.size();
|
||||
}
|
||||
|
||||
ASF::Picture& ASF::Picture::operator=(const ASF::Picture& other)
|
||||
{
|
||||
Picture(other).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void ASF::Picture::swap(Picture &other)
|
||||
{
|
||||
using std::swap;
|
||||
|
||||
swap(d, other.d);
|
||||
}
|
||||
|
||||
ByteVector ASF::Picture::render() const
|
||||
{
|
||||
if(!isValid())
|
||||
return ByteVector();
|
||||
|
||||
return
|
||||
ByteVector((char)d->type) +
|
||||
ByteVector::fromUInt(d->picture.size(), false) +
|
||||
renderString(d->mimeType) +
|
||||
renderString(d->description) +
|
||||
d->picture;
|
||||
}
|
||||
|
||||
void ASF::Picture::parse(const ByteVector& bytes)
|
||||
{
|
||||
d->valid = false;
|
||||
if(bytes.size() < 9)
|
||||
return;
|
||||
int pos = 0;
|
||||
d->type = (Type)bytes[0]; ++pos;
|
||||
const unsigned int dataLen = bytes.toUInt(pos, false); pos+=4;
|
||||
|
||||
const ByteVector nullStringTerminator(2, 0);
|
||||
|
||||
int endPos = bytes.find(nullStringTerminator, pos, 2);
|
||||
if(endPos < 0)
|
||||
return;
|
||||
d->mimeType = String(bytes.mid(pos, endPos - pos), String::UTF16LE);
|
||||
pos = endPos+2;
|
||||
|
||||
endPos = bytes.find(nullStringTerminator, pos, 2);
|
||||
if(endPos < 0)
|
||||
return;
|
||||
d->description = String(bytes.mid(pos, endPos - pos), String::UTF16LE);
|
||||
pos = endPos+2;
|
||||
|
||||
if(dataLen + pos != bytes.size())
|
||||
return;
|
||||
|
||||
d->picture = bytes.mid(pos, dataLen);
|
||||
d->valid = true;
|
||||
return;
|
||||
}
|
||||
|
||||
ASF::Picture ASF::Picture::fromInvalid()
|
||||
{
|
||||
Picture ret;
|
||||
ret.d->valid = false;
|
||||
return ret;
|
||||
}
|
|
@ -1,194 +0,0 @@
|
|||
/**************************************************************************
|
||||
copyright : (C) 2005-2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <taglib/toolkit/tstring.h>
|
||||
#include <taglib/asf/asfproperties.h>
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class ASF::Properties::PropertiesPrivate
|
||||
{
|
||||
public:
|
||||
PropertiesPrivate() :
|
||||
length(0),
|
||||
bitrate(0),
|
||||
sampleRate(0),
|
||||
channels(0),
|
||||
bitsPerSample(0),
|
||||
codec(ASF::Properties::Unknown),
|
||||
encrypted(false) {}
|
||||
|
||||
int length;
|
||||
int bitrate;
|
||||
int sampleRate;
|
||||
int channels;
|
||||
int bitsPerSample;
|
||||
ASF::Properties::Codec codec;
|
||||
String codecName;
|
||||
String codecDescription;
|
||||
bool encrypted;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ASF::Properties::Properties() :
|
||||
AudioProperties(AudioProperties::Average),
|
||||
d(new PropertiesPrivate())
|
||||
{
|
||||
}
|
||||
|
||||
ASF::Properties::~Properties()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
int ASF::Properties::length() const
|
||||
{
|
||||
return lengthInSeconds();
|
||||
}
|
||||
|
||||
int ASF::Properties::lengthInSeconds() const
|
||||
{
|
||||
return d->length / 1000;
|
||||
}
|
||||
|
||||
int ASF::Properties::lengthInMilliseconds() const
|
||||
{
|
||||
return d->length;
|
||||
}
|
||||
|
||||
int ASF::Properties::bitrate() const
|
||||
{
|
||||
return d->bitrate;
|
||||
}
|
||||
|
||||
int ASF::Properties::sampleRate() const
|
||||
{
|
||||
return d->sampleRate;
|
||||
}
|
||||
|
||||
int ASF::Properties::channels() const
|
||||
{
|
||||
return d->channels;
|
||||
}
|
||||
|
||||
int ASF::Properties::bitsPerSample() const
|
||||
{
|
||||
return d->bitsPerSample;
|
||||
}
|
||||
|
||||
ASF::Properties::Codec ASF::Properties::codec() const
|
||||
{
|
||||
return d->codec;
|
||||
}
|
||||
|
||||
String ASF::Properties::codecName() const
|
||||
{
|
||||
return d->codecName;
|
||||
}
|
||||
|
||||
String ASF::Properties::codecDescription() const
|
||||
{
|
||||
return d->codecDescription;
|
||||
}
|
||||
|
||||
bool ASF::Properties::isEncrypted() const
|
||||
{
|
||||
return d->encrypted;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ASF::Properties::setLength(int /*length*/)
|
||||
{
|
||||
debug("ASF::Properties::setLength() -- This method is deprecated. Do not use.");
|
||||
}
|
||||
|
||||
void ASF::Properties::setLengthInMilliseconds(int value)
|
||||
{
|
||||
d->length = value;
|
||||
}
|
||||
|
||||
void ASF::Properties::setBitrate(int value)
|
||||
{
|
||||
d->bitrate = value;
|
||||
}
|
||||
|
||||
void ASF::Properties::setSampleRate(int value)
|
||||
{
|
||||
d->sampleRate = value;
|
||||
}
|
||||
|
||||
void ASF::Properties::setChannels(int value)
|
||||
{
|
||||
d->channels = value;
|
||||
}
|
||||
|
||||
void ASF::Properties::setBitsPerSample(int value)
|
||||
{
|
||||
d->bitsPerSample = value;
|
||||
}
|
||||
|
||||
void ASF::Properties::setCodec(int value)
|
||||
{
|
||||
switch(value)
|
||||
{
|
||||
case 0x0160:
|
||||
d->codec = WMA1;
|
||||
break;
|
||||
case 0x0161:
|
||||
d->codec = WMA2;
|
||||
break;
|
||||
case 0x0162:
|
||||
d->codec = WMA9Pro;
|
||||
break;
|
||||
case 0x0163:
|
||||
d->codec = WMA9Lossless;
|
||||
break;
|
||||
default:
|
||||
d->codec = Unknown;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ASF::Properties::setCodecName(const String &value)
|
||||
{
|
||||
d->codecName = value;
|
||||
}
|
||||
|
||||
void ASF::Properties::setCodecDescription(const String &value)
|
||||
{
|
||||
d->codecDescription = value;
|
||||
}
|
||||
|
||||
void ASF::Properties::setEncrypted(bool value)
|
||||
{
|
||||
d->encrypted = value;
|
||||
}
|
|
@ -1,489 +0,0 @@
|
|||
/**************************************************************************
|
||||
copyright : (C) 2005-2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/toolkit/tpropertymap.h>
|
||||
#include <taglib/asf/asftag.h>
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class ASF::Tag::TagPrivate
|
||||
{
|
||||
public:
|
||||
String title;
|
||||
String artist;
|
||||
String copyright;
|
||||
String comment;
|
||||
String rating;
|
||||
AttributeListMap attributeListMap;
|
||||
};
|
||||
|
||||
ASF::Tag::Tag() :
|
||||
TagLib::Tag(),
|
||||
d(new TagPrivate())
|
||||
{
|
||||
}
|
||||
|
||||
ASF::Tag::~Tag()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String ASF::Tag::title() const
|
||||
{
|
||||
return d->title;
|
||||
}
|
||||
|
||||
String ASF::Tag::albumartist() const
|
||||
{
|
||||
if(d->attributeListMap.contains("WM/AlbumArtist"))
|
||||
return d->attributeListMap["WM/AlbumArtist"][0].toString();
|
||||
return String();
|
||||
}
|
||||
|
||||
String ASF::Tag::artist() const
|
||||
{
|
||||
return d->artist;
|
||||
}
|
||||
|
||||
String ASF::Tag::composer() const
|
||||
{
|
||||
if(d->attributeListMap.contains("WM/Composer"))
|
||||
return d->attributeListMap["WM/Composer"][0].toString();
|
||||
return String();
|
||||
}
|
||||
|
||||
String ASF::Tag::album() const
|
||||
{
|
||||
if(d->attributeListMap.contains("WM/AlbumTitle"))
|
||||
return d->attributeListMap["WM/AlbumTitle"][0].toString();
|
||||
return String();
|
||||
}
|
||||
|
||||
String ASF::Tag::unsyncedlyrics() const
|
||||
{
|
||||
if(d->attributeListMap.contains("WM/Lyrics"))
|
||||
return d->attributeListMap["WM/Lyrics"][0].toString();
|
||||
return String();
|
||||
}
|
||||
|
||||
String ASF::Tag::copyright() const
|
||||
{
|
||||
return d->copyright;
|
||||
}
|
||||
|
||||
String ASF::Tag::comment() const
|
||||
{
|
||||
return d->comment;
|
||||
}
|
||||
|
||||
String ASF::Tag::rating() const
|
||||
{
|
||||
return d->rating;
|
||||
}
|
||||
|
||||
unsigned int ASF::Tag::year() const
|
||||
{
|
||||
if(d->attributeListMap.contains("WM/Year"))
|
||||
return d->attributeListMap["WM/Year"][0].toString().toInt();
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int ASF::Tag::track() const
|
||||
{
|
||||
if(d->attributeListMap.contains("WM/TrackNumber")) {
|
||||
const ASF::Attribute attr = d->attributeListMap["WM/TrackNumber"][0];
|
||||
if(attr.type() == ASF::Attribute::DWordType)
|
||||
return attr.toUInt();
|
||||
else
|
||||
return attr.toString().toInt();
|
||||
}
|
||||
if(d->attributeListMap.contains("WM/Track"))
|
||||
return d->attributeListMap["WM/Track"][0].toUInt();
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int ASF::Tag::disc() const
|
||||
{
|
||||
if(d->attributeListMap.contains("WM/DiscNumber")) {
|
||||
const ASF::Attribute attr = d->attributeListMap["WM/DiscNumber"][0];
|
||||
if(attr.type() == ASF::Attribute::DWordType)
|
||||
return attr.toUInt();
|
||||
else
|
||||
return attr.toString().toInt();
|
||||
}
|
||||
if(d->attributeListMap.contains("WM/Disc"))
|
||||
return d->attributeListMap["WM/Disc"][0].toUInt();
|
||||
return 0;
|
||||
}
|
||||
|
||||
String ASF::Tag::genre() const
|
||||
{
|
||||
if(d->attributeListMap.contains("WM/Genre"))
|
||||
return d->attributeListMap["WM/Genre"][0].toString();
|
||||
return String();
|
||||
}
|
||||
|
||||
String ASF::Tag::cuesheet() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
float ASF::Tag::rgAlbumGain() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float ASF::Tag::rgAlbumPeak() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float ASF::Tag::rgTrackGain() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float ASF::Tag::rgTrackPeak() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
String ASF::Tag::soundcheck() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
void ASF::Tag::setTitle(const String &value)
|
||||
{
|
||||
d->title = value;
|
||||
}
|
||||
|
||||
void ASF::Tag::setAlbumArtist(const String &value)
|
||||
{
|
||||
setAttribute("WM/AlbumArtist", value);
|
||||
}
|
||||
|
||||
void ASF::Tag::setArtist(const String &value)
|
||||
{
|
||||
d->artist = value;
|
||||
}
|
||||
|
||||
void ASF::Tag::setComposer(const String &value)
|
||||
{
|
||||
setAttribute("WM/Composer", value);
|
||||
}
|
||||
|
||||
void ASF::Tag::setCopyright(const String &value)
|
||||
{
|
||||
d->copyright = value;
|
||||
}
|
||||
|
||||
void ASF::Tag::setComment(const String &value)
|
||||
{
|
||||
d->comment = value;
|
||||
}
|
||||
|
||||
void ASF::Tag::setRating(const String &value)
|
||||
{
|
||||
d->rating = value;
|
||||
}
|
||||
|
||||
void ASF::Tag::setAlbum(const String &value)
|
||||
{
|
||||
setAttribute("WM/AlbumTitle", value);
|
||||
}
|
||||
|
||||
void ASF::Tag::setUnsyncedlyrics(const String &value)
|
||||
{
|
||||
setAttribute("WM/Lyrics", value);
|
||||
}
|
||||
|
||||
void ASF::Tag::setGenre(const String &value)
|
||||
{
|
||||
setAttribute("WM/Genre", value);
|
||||
}
|
||||
|
||||
void ASF::Tag::setYear(unsigned int value)
|
||||
{
|
||||
setAttribute("WM/Year", String::number(value));
|
||||
}
|
||||
|
||||
void ASF::Tag::setTrack(unsigned int value)
|
||||
{
|
||||
setAttribute("WM/TrackNumber", String::number(value));
|
||||
}
|
||||
|
||||
void ASF::Tag::setDisc(unsigned int value)
|
||||
{
|
||||
setAttribute("WM/DiscNumber", String::number(value));
|
||||
}
|
||||
|
||||
void ASF::Tag::setCuesheet(const String &)
|
||||
{
|
||||
}
|
||||
|
||||
void ASF::Tag::setRGAlbumGain(float)
|
||||
{
|
||||
}
|
||||
|
||||
void ASF::Tag::setRGAlbumPeak(float)
|
||||
{
|
||||
}
|
||||
|
||||
void ASF::Tag::setRGTrackGain(float)
|
||||
{
|
||||
}
|
||||
|
||||
void ASF::Tag::setRGTrackPeak(float)
|
||||
{
|
||||
}
|
||||
|
||||
ASF::AttributeListMap& ASF::Tag::attributeListMap()
|
||||
{
|
||||
return d->attributeListMap;
|
||||
}
|
||||
|
||||
const ASF::AttributeListMap &ASF::Tag::attributeListMap() const
|
||||
{
|
||||
return d->attributeListMap;
|
||||
}
|
||||
|
||||
bool ASF::Tag::contains(const String &key) const
|
||||
{
|
||||
return d->attributeListMap.contains(key);
|
||||
}
|
||||
|
||||
void ASF::Tag::removeItem(const String &key)
|
||||
{
|
||||
d->attributeListMap.erase(key);
|
||||
}
|
||||
|
||||
ASF::AttributeList ASF::Tag::attribute(const String &name) const
|
||||
{
|
||||
return d->attributeListMap[name];
|
||||
}
|
||||
|
||||
void ASF::Tag::setAttribute(const String &name, const Attribute &attribute)
|
||||
{
|
||||
AttributeList value;
|
||||
value.append(attribute);
|
||||
d->attributeListMap.insert(name, value);
|
||||
}
|
||||
|
||||
void ASF::Tag::setAttribute(const String &name, const AttributeList &values)
|
||||
{
|
||||
d->attributeListMap.insert(name, values);
|
||||
}
|
||||
|
||||
void ASF::Tag::addAttribute(const String &name, const Attribute &attribute)
|
||||
{
|
||||
if(d->attributeListMap.contains(name)) {
|
||||
d->attributeListMap[name].append(attribute);
|
||||
}
|
||||
else {
|
||||
setAttribute(name, attribute);
|
||||
}
|
||||
}
|
||||
|
||||
bool ASF::Tag::isEmpty() const
|
||||
{
|
||||
return TagLib::Tag::isEmpty() &&
|
||||
copyright().isEmpty() &&
|
||||
rating().isEmpty() &&
|
||||
d->attributeListMap.isEmpty();
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
const char *keyTranslation[][2] = {
|
||||
{ "WM/AlbumTitle", "ALBUM" },
|
||||
{ "WM/AlbumArtist", "ALBUMARTIST" },
|
||||
{ "WM/Composer", "COMPOSER" },
|
||||
{ "WM/Writer", "LYRICIST" },
|
||||
{ "WM/Conductor", "CONDUCTOR" },
|
||||
{ "WM/ModifiedBy", "REMIXER" },
|
||||
{ "WM/Year", "DATE" },
|
||||
{ "WM/OriginalReleaseYear", "ORIGINALDATE" },
|
||||
{ "WM/Producer", "PRODUCER" },
|
||||
{ "WM/ContentGroupDescription", "GROUPING" },
|
||||
{ "WM/SubTitle", "SUBTITLE" },
|
||||
{ "WM/SetSubTitle", "DISCSUBTITLE" },
|
||||
{ "WM/TrackNumber", "TRACKNUMBER" },
|
||||
{ "WM/PartOfSet", "DISCNUMBER" },
|
||||
{ "WM/Genre", "GENRE" },
|
||||
{ "WM/BeatsPerMinute", "BPM" },
|
||||
{ "WM/Mood", "MOOD" },
|
||||
{ "WM/ISRC", "ISRC" },
|
||||
{ "WM/Lyrics", "LYRICS" },
|
||||
{ "WM/Media", "MEDIA" },
|
||||
{ "WM/Publisher", "LABEL" },
|
||||
{ "WM/CatalogNo", "CATALOGNUMBER" },
|
||||
{ "WM/Barcode", "BARCODE" },
|
||||
{ "WM/EncodedBy", "ENCODEDBY" },
|
||||
{ "WM/AlbumSortOrder", "ALBUMSORT" },
|
||||
{ "WM/AlbumArtistSortOrder", "ALBUMARTISTSORT" },
|
||||
{ "WM/ArtistSortOrder", "ARTISTSORT" },
|
||||
{ "WM/TitleSortOrder", "TITLESORT" },
|
||||
{ "WM/Script", "SCRIPT" },
|
||||
{ "WM/Language", "LANGUAGE" },
|
||||
{ "WM/ARTISTS", "ARTISTS" },
|
||||
{ "ASIN", "ASIN" },
|
||||
{ "MusicBrainz/Track Id", "MUSICBRAINZ_TRACKID" },
|
||||
{ "MusicBrainz/Artist Id", "MUSICBRAINZ_ARTISTID" },
|
||||
{ "MusicBrainz/Album Id", "MUSICBRAINZ_ALBUMID" },
|
||||
{ "MusicBrainz/Album Artist Id", "MUSICBRAINZ_ALBUMARTISTID" },
|
||||
{ "MusicBrainz/Album Release Country", "RELEASECOUNTRY" },
|
||||
{ "MusicBrainz/Album Status", "RELEASESTATUS" },
|
||||
{ "MusicBrainz/Album Type", "RELEASETYPE" },
|
||||
{ "MusicBrainz/Release Group Id", "MUSICBRAINZ_RELEASEGROUPID" },
|
||||
{ "MusicBrainz/Release Track Id", "MUSICBRAINZ_RELEASETRACKID" },
|
||||
{ "MusicBrainz/Work Id", "MUSICBRAINZ_WORKID" },
|
||||
{ "MusicIP/PUID", "MUSICIP_PUID" },
|
||||
{ "Acoustid/Id", "ACOUSTID_ID" },
|
||||
{ "Acoustid/Fingerprint", "ACOUSTID_FINGERPRINT" },
|
||||
};
|
||||
const size_t keyTranslationSize = sizeof(keyTranslation) / sizeof(keyTranslation[0]);
|
||||
|
||||
String translateKey(const String &key)
|
||||
{
|
||||
for(size_t i = 0; i < keyTranslationSize; ++i) {
|
||||
if(key == keyTranslation[i][0])
|
||||
return keyTranslation[i][1];
|
||||
}
|
||||
|
||||
return String();
|
||||
}
|
||||
}
|
||||
|
||||
PropertyMap ASF::Tag::properties() const
|
||||
{
|
||||
PropertyMap props;
|
||||
|
||||
if(!d->title.isEmpty()) {
|
||||
props["TITLE"] = d->title;
|
||||
}
|
||||
if(!d->artist.isEmpty()) {
|
||||
props["ARTIST"] = d->artist;
|
||||
}
|
||||
if(!d->copyright.isEmpty()) {
|
||||
props["COPYRIGHT"] = d->copyright;
|
||||
}
|
||||
if(!d->comment.isEmpty()) {
|
||||
props["COMMENT"] = d->comment;
|
||||
}
|
||||
|
||||
ASF::AttributeListMap::ConstIterator it = d->attributeListMap.begin();
|
||||
for(; it != d->attributeListMap.end(); ++it) {
|
||||
const String key = translateKey(it->first);
|
||||
if(!key.isEmpty()) {
|
||||
AttributeList::ConstIterator it2 = it->second.begin();
|
||||
for(; it2 != it->second.end(); ++it2) {
|
||||
if(key == "TRACKNUMBER") {
|
||||
if(it2->type() == ASF::Attribute::DWordType)
|
||||
props.insert(key, String::number(it2->toUInt()));
|
||||
else
|
||||
props.insert(key, it2->toString());
|
||||
}
|
||||
else {
|
||||
props.insert(key, it2->toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
props.unsupportedData().append(it->first);
|
||||
}
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
void ASF::Tag::removeUnsupportedProperties(const StringList &props)
|
||||
{
|
||||
StringList::ConstIterator it = props.begin();
|
||||
for(; it != props.end(); ++it)
|
||||
d->attributeListMap.erase(*it);
|
||||
}
|
||||
|
||||
PropertyMap ASF::Tag::setProperties(const PropertyMap &props)
|
||||
{
|
||||
static Map<String, String> reverseKeyMap;
|
||||
if(reverseKeyMap.isEmpty()) {
|
||||
int numKeys = sizeof(keyTranslation) / sizeof(keyTranslation[0]);
|
||||
for(int i = 0; i < numKeys; i++) {
|
||||
reverseKeyMap[keyTranslation[i][1]] = keyTranslation[i][0];
|
||||
}
|
||||
}
|
||||
|
||||
PropertyMap origProps = properties();
|
||||
PropertyMap::ConstIterator it = origProps.begin();
|
||||
for(; it != origProps.end(); ++it) {
|
||||
if(!props.contains(it->first) || props[it->first].isEmpty()) {
|
||||
if(it->first == "TITLE") {
|
||||
d->title.clear();
|
||||
}
|
||||
else if(it->first == "ARTIST") {
|
||||
d->artist.clear();
|
||||
}
|
||||
else if(it->first == "COMMENT") {
|
||||
d->comment.clear();
|
||||
}
|
||||
else if(it->first == "COPYRIGHT") {
|
||||
d->copyright.clear();
|
||||
}
|
||||
else {
|
||||
d->attributeListMap.erase(reverseKeyMap[it->first]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PropertyMap ignoredProps;
|
||||
it = props.begin();
|
||||
for(; it != props.end(); ++it) {
|
||||
if(reverseKeyMap.contains(it->first)) {
|
||||
String name = reverseKeyMap[it->first];
|
||||
removeItem(name);
|
||||
StringList::ConstIterator it2 = it->second.begin();
|
||||
for(; it2 != it->second.end(); ++it2) {
|
||||
addAttribute(name, *it2);
|
||||
}
|
||||
}
|
||||
else if(it->first == "TITLE") {
|
||||
d->title = it->second.toString();
|
||||
}
|
||||
else if(it->first == "ARTIST") {
|
||||
d->artist = it->second.toString();
|
||||
}
|
||||
else if(it->first == "COMMENT") {
|
||||
d->comment = it->second.toString();
|
||||
}
|
||||
else if(it->first == "COPYRIGHT") {
|
||||
d->copyright = it->second.toString();
|
||||
}
|
||||
else {
|
||||
ignoredProps.insert(it->first, it->second);
|
||||
}
|
||||
}
|
||||
|
||||
return ignoredProps;
|
||||
}
|
|
@ -1,104 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2015 by Tsuda Kageyu
|
||||
email : tsuda.kageyu@gmail.com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_ASFUTILS_H
|
||||
#define TAGLIB_ASFUTILS_H
|
||||
|
||||
// THIS FILE IS NOT A PART OF THE TAGLIB API
|
||||
|
||||
#ifndef DO_NOT_DOCUMENT // tell Doxygen not to document this header
|
||||
|
||||
namespace TagLib
|
||||
{
|
||||
namespace ASF
|
||||
{
|
||||
namespace
|
||||
{
|
||||
|
||||
inline unsigned short readWORD(File *file, bool *ok = 0)
|
||||
{
|
||||
const ByteVector v = file->readBlock(2);
|
||||
if(v.size() != 2) {
|
||||
if(ok) *ok = false;
|
||||
return 0;
|
||||
}
|
||||
if(ok) *ok = true;
|
||||
return v.toUShort(false);
|
||||
}
|
||||
|
||||
inline unsigned int readDWORD(File *file, bool *ok = 0)
|
||||
{
|
||||
const ByteVector v = file->readBlock(4);
|
||||
if(v.size() != 4) {
|
||||
if(ok) *ok = false;
|
||||
return 0;
|
||||
}
|
||||
if(ok) *ok = true;
|
||||
return v.toUInt(false);
|
||||
}
|
||||
|
||||
inline long long readQWORD(File *file, bool *ok = 0)
|
||||
{
|
||||
const ByteVector v = file->readBlock(8);
|
||||
if(v.size() != 8) {
|
||||
if(ok) *ok = false;
|
||||
return 0;
|
||||
}
|
||||
if(ok) *ok = true;
|
||||
return v.toLongLong(false);
|
||||
}
|
||||
|
||||
inline String readString(File *file, int length)
|
||||
{
|
||||
ByteVector data = file->readBlock(length);
|
||||
unsigned int size = data.size();
|
||||
while (size >= 2) {
|
||||
if(data[size - 1] != '\0' || data[size - 2] != '\0') {
|
||||
break;
|
||||
}
|
||||
size -= 2;
|
||||
}
|
||||
if(size != data.size()) {
|
||||
data.resize(size);
|
||||
}
|
||||
return String(data, String::UTF16LE);
|
||||
}
|
||||
|
||||
inline ByteVector renderString(const String &str, bool includeLength = false)
|
||||
{
|
||||
ByteVector data = str.data(String::UTF16LE) + ByteVector::fromShort(0, false);
|
||||
if(includeLength) {
|
||||
data = ByteVector::fromShort(data.size(), false) + data;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,94 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/toolkit/tbytevector.h>
|
||||
|
||||
#include <taglib/ape/apeproperties.h>
|
||||
#include <taglib/asf/asfproperties.h>
|
||||
#include <taglib/mp4/mp4properties.h>
|
||||
#include <taglib/mpc/mpcproperties.h>
|
||||
#include <taglib/mpeg/mpegproperties.h>
|
||||
#include <taglib/riff/aiff/aiffproperties.h>
|
||||
#include <taglib/riff/wav/wavproperties.h>
|
||||
#include <taglib/wavpack/wavpackproperties.h>
|
||||
|
||||
#include <taglib/audioproperties.h>
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
// This macro is a workaround for the fact that we can't add virtual functions.
|
||||
// Should be true virtual functions in taglib2.
|
||||
|
||||
#define VIRTUAL_FUNCTION_WORKAROUND(function_name, default_value) \
|
||||
if(dynamic_cast<const APE::Properties*>(this)) \
|
||||
return dynamic_cast<const APE::Properties*>(this)->function_name(); \
|
||||
else if(dynamic_cast<const ASF::Properties*>(this)) \
|
||||
return dynamic_cast<const ASF::Properties*>(this)->function_name(); \
|
||||
else if(dynamic_cast<const MPC::Properties*>(this)) \
|
||||
return dynamic_cast<const MPC::Properties*>(this)->function_name(); \
|
||||
else if(dynamic_cast<const MPEG::Properties*>(this)) \
|
||||
return dynamic_cast<const MPEG::Properties*>(this)->function_name(); \
|
||||
else if(dynamic_cast<const RIFF::AIFF::Properties*>(this)) \
|
||||
return dynamic_cast<const RIFF::AIFF::Properties*>(this)->function_name(); \
|
||||
else if(dynamic_cast<const RIFF::WAV::Properties*>(this)) \
|
||||
return dynamic_cast<const RIFF::WAV::Properties*>(this)->function_name(); \
|
||||
else if(dynamic_cast<const WavPack::Properties*>(this)) \
|
||||
return dynamic_cast<const WavPack::Properties*>(this)->function_name(); \
|
||||
else \
|
||||
return (default_value);
|
||||
|
||||
class AudioProperties::AudioPropertiesPrivate
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AudioProperties::~AudioProperties()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int AudioProperties::lengthInSeconds() const
|
||||
{
|
||||
VIRTUAL_FUNCTION_WORKAROUND(lengthInSeconds, 0)
|
||||
}
|
||||
|
||||
int AudioProperties::lengthInMilliseconds() const
|
||||
{
|
||||
VIRTUAL_FUNCTION_WORKAROUND(lengthInMilliseconds, 0)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AudioProperties::AudioProperties(ReadStyle) :
|
||||
d(0)
|
||||
{
|
||||
|
||||
}
|
|
@ -1,415 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
|
||||
copyright : (C) 2010 by Alex Novichkov
|
||||
email : novichko@atnet.ru
|
||||
(added APE file support)
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <taglib/toolkit/tfile.h>
|
||||
#include <taglib/toolkit/tfilestream.h>
|
||||
#include <taglib/toolkit/tstring.h>
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <taglib/toolkit/trefcounter.h>
|
||||
|
||||
#include <taglib/asf/asffile.h>
|
||||
#include <taglib/fileref.h>
|
||||
#include <taglib/it/itfile.h>
|
||||
#include <taglib/mod/modfile.h>
|
||||
#include <taglib/mp4/mp4file.h>
|
||||
#include <taglib/mpc/mpcfile.h>
|
||||
#include <taglib/mpeg/mpegfile.h>
|
||||
#include <taglib/riff/aiff/aifffile.h>
|
||||
#include <taglib/riff/wav/wavfile.h>
|
||||
#include <taglib/s3m/s3mfile.h>
|
||||
#include <taglib/wavpack/wavpackfile.h>
|
||||
#include <taglib/xm/xmfile.h>
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
namespace
|
||||
{
|
||||
typedef List<const FileRef::FileTypeResolver *> ResolverList;
|
||||
ResolverList fileTypeResolvers;
|
||||
|
||||
// Detect the file type by user-defined resolvers.
|
||||
|
||||
File *detectByResolvers(FileName fileName, bool readAudioProperties,
|
||||
AudioProperties::ReadStyle audioPropertiesStyle)
|
||||
{
|
||||
if(::strlen(fileName) == 0)
|
||||
return 0;
|
||||
ResolverList::ConstIterator it = fileTypeResolvers.begin();
|
||||
for(; it != fileTypeResolvers.end(); ++it) {
|
||||
File *file = (*it)->createFile(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(file)
|
||||
return file;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Detect the file type based on the file extension.
|
||||
|
||||
File* detectByExtension(IOStream *stream, bool readAudioProperties,
|
||||
AudioProperties::ReadStyle audioPropertiesStyle)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const String s = stream->name().toString();
|
||||
#else
|
||||
const String s(stream->name());
|
||||
#endif
|
||||
|
||||
String ext;
|
||||
const int pos = s.rfind(".");
|
||||
if(pos != -1)
|
||||
ext = s.substr(pos + 1).upper();
|
||||
|
||||
// If this list is updated, the method defaultFileExtensions() should also be
|
||||
// updated. However at some point that list should be created at the same time
|
||||
// that a default file type resolver is created.
|
||||
|
||||
if(ext.isEmpty()) {
|
||||
// HACK
|
||||
return new MPEG::File(stream, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle);
|
||||
}
|
||||
|
||||
// .oga can be any audio in the Ogg container. So leave it to content-based detection.
|
||||
|
||||
if(ext == "MP3")
|
||||
return new MPEG::File(stream, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "MPC")
|
||||
return new MPC::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "WV")
|
||||
return new WavPack::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "WMA" || ext == "ASF")
|
||||
return new ASF::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "AIF" || ext == "AIFF" || ext == "AFC" || ext == "AIFC")
|
||||
return new RIFF::AIFF::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "WAV")
|
||||
return new RIFF::WAV::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||
// module, nst and wow are possible but uncommon extensions
|
||||
if(ext == "MOD" || ext == "MODULE" || ext == "NST" || ext == "WOW")
|
||||
return new Mod::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "S3M")
|
||||
return new S3M::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "IT")
|
||||
return new IT::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "XM")
|
||||
return new XM::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Detect the file type based on the actual content of the stream.
|
||||
|
||||
File *detectByContent(IOStream *stream, bool readAudioProperties,
|
||||
AudioProperties::ReadStyle audioPropertiesStyle)
|
||||
{
|
||||
File *file = 0;
|
||||
|
||||
if(MPEG::File::isSupported(stream))
|
||||
file = new MPEG::File(stream, ID3v2::FrameFactory::instance(), 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(ASF::File::isSupported(stream))
|
||||
file = new ASF::File(stream, readAudioProperties, audioPropertiesStyle);
|
||||
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);
|
||||
|
||||
// isSupported() only does a quick check, so double check the file here.
|
||||
|
||||
if(file) {
|
||||
if(file->isValid())
|
||||
return file;
|
||||
else
|
||||
delete file;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Internal function that supports FileRef::create().
|
||||
// This looks redundant, but necessary in order not to change the previous
|
||||
// behavior of FileRef::create().
|
||||
|
||||
File* createInternal(FileName fileName, bool readAudioProperties,
|
||||
AudioProperties::ReadStyle audioPropertiesStyle)
|
||||
{
|
||||
File *file = detectByResolvers(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(file)
|
||||
return file;
|
||||
|
||||
#ifdef _WIN32
|
||||
const String s = fileName.toString();
|
||||
#else
|
||||
const String s(fileName);
|
||||
#endif
|
||||
|
||||
String ext;
|
||||
const int pos = s.rfind(".");
|
||||
if(pos != -1)
|
||||
ext = s.substr(pos + 1).upper();
|
||||
|
||||
if(ext.isEmpty())
|
||||
return 0;
|
||||
|
||||
if(ext == "MP3")
|
||||
return new MPEG::File(fileName, ID3v2::FrameFactory::instance(), readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "MPC")
|
||||
return new MPC::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "WV")
|
||||
return new WavPack::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "WMA" || ext == "ASF")
|
||||
return new ASF::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "AIF" || ext == "AIFF" || ext == "AFC" || ext == "AIFC")
|
||||
return new RIFF::AIFF::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "WAV")
|
||||
return new RIFF::WAV::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
// module, nst and wow are possible but uncommon extensions
|
||||
if(ext == "MOD" || ext == "MODULE" || ext == "NST" || ext == "WOW")
|
||||
return new Mod::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "S3M")
|
||||
return new S3M::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "IT")
|
||||
return new IT::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "XM")
|
||||
return new XM::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
class FileRef::FileRefPrivate : public RefCounter
|
||||
{
|
||||
public:
|
||||
FileRefPrivate() :
|
||||
RefCounter(),
|
||||
file(0),
|
||||
stream(0) {}
|
||||
|
||||
~FileRefPrivate() {
|
||||
delete file;
|
||||
delete stream;
|
||||
}
|
||||
|
||||
File *file;
|
||||
IOStream *stream;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FileRef::FileRef() :
|
||||
d(new FileRefPrivate())
|
||||
{
|
||||
}
|
||||
|
||||
FileRef::FileRef(FileName fileName, bool readAudioProperties,
|
||||
AudioProperties::ReadStyle audioPropertiesStyle) :
|
||||
d(new FileRefPrivate())
|
||||
{
|
||||
parse(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
}
|
||||
|
||||
FileRef::FileRef(IOStream* stream, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle) :
|
||||
d(new FileRefPrivate())
|
||||
{
|
||||
parse(stream, readAudioProperties, audioPropertiesStyle);
|
||||
}
|
||||
|
||||
FileRef::FileRef(File *file) :
|
||||
d(new FileRefPrivate())
|
||||
{
|
||||
d->file = file;
|
||||
}
|
||||
|
||||
FileRef::FileRef(const FileRef &ref) :
|
||||
d(ref.d)
|
||||
{
|
||||
d->ref();
|
||||
}
|
||||
|
||||
FileRef::~FileRef()
|
||||
{
|
||||
if(d->deref())
|
||||
delete d;
|
||||
}
|
||||
|
||||
Tag *FileRef::tag() const
|
||||
{
|
||||
if(isNull()) {
|
||||
debug("FileRef::tag() - Called without a valid file.");
|
||||
return 0;
|
||||
}
|
||||
return d->file->tag();
|
||||
}
|
||||
|
||||
AudioProperties *FileRef::audioProperties() const
|
||||
{
|
||||
if(isNull()) {
|
||||
debug("FileRef::audioProperties() - Called without a valid file.");
|
||||
return 0;
|
||||
}
|
||||
return d->file->audioProperties();
|
||||
}
|
||||
|
||||
File *FileRef::file() const
|
||||
{
|
||||
return d->file;
|
||||
}
|
||||
|
||||
bool FileRef::save()
|
||||
{
|
||||
if(isNull()) {
|
||||
debug("FileRef::save() - Called without a valid file.");
|
||||
return false;
|
||||
}
|
||||
return d->file->save();
|
||||
}
|
||||
|
||||
const FileRef::FileTypeResolver *FileRef::addFileTypeResolver(const FileRef::FileTypeResolver *resolver) // static
|
||||
{
|
||||
fileTypeResolvers.prepend(resolver);
|
||||
return resolver;
|
||||
}
|
||||
|
||||
StringList FileRef::defaultFileExtensions()
|
||||
{
|
||||
StringList l;
|
||||
|
||||
l.append("mp3");
|
||||
l.append("mpc");
|
||||
l.append("wv");
|
||||
l.append("3g2");
|
||||
l.append("wma");
|
||||
l.append("asf");
|
||||
l.append("aif");
|
||||
l.append("aiff");
|
||||
l.append("afc");
|
||||
l.append("aifc");
|
||||
l.append("wav");
|
||||
l.append("mod");
|
||||
l.append("module"); // alias for "mod"
|
||||
l.append("nst"); // alias for "mod"
|
||||
l.append("wow"); // alias for "mod"
|
||||
l.append("s3m");
|
||||
l.append("it");
|
||||
l.append("xm");
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
bool FileRef::isNull() const
|
||||
{
|
||||
return (!d->file || !d->file->isValid());
|
||||
}
|
||||
|
||||
FileRef &FileRef::operator=(const FileRef &ref)
|
||||
{
|
||||
FileRef(ref).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void FileRef::swap(FileRef &ref)
|
||||
{
|
||||
using std::swap;
|
||||
|
||||
swap(d, ref.d);
|
||||
}
|
||||
|
||||
bool FileRef::operator==(const FileRef &ref) const
|
||||
{
|
||||
return (ref.d->file == d->file);
|
||||
}
|
||||
|
||||
bool FileRef::operator!=(const FileRef &ref) const
|
||||
{
|
||||
return (ref.d->file != d->file);
|
||||
}
|
||||
|
||||
File *FileRef::create(FileName fileName, bool readAudioProperties,
|
||||
AudioProperties::ReadStyle audioPropertiesStyle) // static
|
||||
{
|
||||
return createInternal(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void FileRef::parse(FileName fileName, bool readAudioProperties,
|
||||
AudioProperties::ReadStyle audioPropertiesStyle)
|
||||
{
|
||||
// Try user-defined resolvers.
|
||||
|
||||
d->file = detectByResolvers(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(d->file)
|
||||
return;
|
||||
|
||||
// Try to resolve file types based on the file extension.
|
||||
|
||||
d->stream = new FileStream(fileName);
|
||||
d->file = detectByExtension(d->stream, readAudioProperties, audioPropertiesStyle);
|
||||
if(d->file)
|
||||
return;
|
||||
|
||||
// At last, try to resolve file types based on the actual content.
|
||||
|
||||
d->file = detectByContent(d->stream, readAudioProperties, audioPropertiesStyle);
|
||||
if(d->file)
|
||||
return;
|
||||
|
||||
// Stream have to be closed here if failed to resolve file types.
|
||||
|
||||
delete d->stream;
|
||||
d->stream = 0;
|
||||
}
|
||||
|
||||
void FileRef::parse(IOStream *stream, bool readAudioProperties,
|
||||
AudioProperties::ReadStyle audioPropertiesStyle)
|
||||
{
|
||||
// Try user-defined resolvers.
|
||||
|
||||
d->file = detectByResolvers(stream->name(), readAudioProperties, audioPropertiesStyle);
|
||||
if(d->file)
|
||||
return;
|
||||
|
||||
// Try to resolve file types based on the file extension.
|
||||
|
||||
d->file = detectByExtension(stream, readAudioProperties, audioPropertiesStyle);
|
||||
if(d->file)
|
||||
return;
|
||||
|
||||
// At last, try to resolve file types based on the actual content of the file.
|
||||
|
||||
d->file = detectByContent(stream, readAudioProperties, audioPropertiesStyle);
|
||||
}
|
|
@ -1,287 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_FILEREF_H
|
||||
#define TAGLIB_FILEREF_H
|
||||
|
||||
#include <taglib/toolkit/tfile.h>
|
||||
#include <taglib/toolkit/tstringlist.h>
|
||||
|
||||
#include <taglib/taglib_export.h>
|
||||
#include <taglib/audioproperties.h>
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
class Tag;
|
||||
|
||||
//! This class provides a simple abstraction for creating and handling files
|
||||
|
||||
/*!
|
||||
* FileRef exists to provide a minimal, generic and value-based wrapper around
|
||||
* a File. It is lightweight and implicitly shared, and as such suitable for
|
||||
* pass-by-value use. This hides some of the uglier details of TagLib::File
|
||||
* and the non-generic portions of the concrete file implementations.
|
||||
*
|
||||
* This class is useful in a "simple usage" situation where it is desirable
|
||||
* to be able to get and set some of the tag information that is similar
|
||||
* across file types.
|
||||
*
|
||||
* Also note that it is probably a good idea to plug this into your mime
|
||||
* type system rather than using the constructor that accepts a file name using
|
||||
* the FileTypeResolver.
|
||||
*
|
||||
* \see FileTypeResolver
|
||||
* \see addFileTypeResolver()
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT FileRef
|
||||
{
|
||||
public:
|
||||
|
||||
//! A class for pluggable file type resolution.
|
||||
|
||||
/*!
|
||||
* This class is used to add extend TagLib's very basic file name based file
|
||||
* type resolution.
|
||||
*
|
||||
* This can be accomplished with:
|
||||
*
|
||||
* \code
|
||||
*
|
||||
* class MyFileTypeResolver : FileTypeResolver
|
||||
* {
|
||||
* TagLib::File *createFile(TagLib::FileName *fileName, bool, AudioProperties::ReadStyle) const
|
||||
* {
|
||||
* if(someCheckForAnMP3File(fileName))
|
||||
* return new TagLib::MPEG::File(fileName);
|
||||
* return 0;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* FileRef::addFileTypeResolver(new MyFileTypeResolver);
|
||||
*
|
||||
* \endcode
|
||||
*
|
||||
* Naturally a less contrived example would be slightly more complex. This
|
||||
* can be used to plug in mime-type detection systems or to add new file types
|
||||
* to TagLib.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT FileTypeResolver
|
||||
{
|
||||
TAGLIB_IGNORE_MISSING_DESTRUCTOR
|
||||
public:
|
||||
/*!
|
||||
* This method must be overridden to provide an additional file type
|
||||
* resolver. If the resolver is able to determine the file type it should
|
||||
* return a valid File object; if not it should return 0.
|
||||
*
|
||||
* \note The created file is then owned by the FileRef and should not be
|
||||
* deleted. Deletion will happen automatically when the FileRef passes
|
||||
* out of scope.
|
||||
*/
|
||||
virtual File *createFile(FileName fileName,
|
||||
bool readAudioProperties = true,
|
||||
AudioProperties::ReadStyle
|
||||
audioPropertiesStyle = AudioProperties::Average) const = 0;
|
||||
};
|
||||
|
||||
/*!
|
||||
* Creates a null FileRef.
|
||||
*/
|
||||
FileRef();
|
||||
|
||||
/*!
|
||||
* Create a FileRef from \a fileName. If \a readAudioProperties is true then
|
||||
* the audio properties will be read using \a audioPropertiesStyle. If
|
||||
* \a readAudioProperties is false then \a audioPropertiesStyle will be
|
||||
* ignored.
|
||||
*
|
||||
* Also see the note in the class documentation about why you may not want to
|
||||
* use this method in your application.
|
||||
*/
|
||||
explicit FileRef(FileName fileName,
|
||||
bool readAudioProperties = true,
|
||||
AudioProperties::ReadStyle
|
||||
audioPropertiesStyle = AudioProperties::Average);
|
||||
|
||||
/*!
|
||||
* Construct a FileRef from an opened \a IOStream. If \a readAudioProperties
|
||||
* is true then the audio properties will be read using \a audioPropertiesStyle.
|
||||
* If \a readAudioProperties is false then \a audioPropertiesStyle will be
|
||||
* ignored.
|
||||
*
|
||||
* Also see the note in the class documentation about why you may not want to
|
||||
* use this method in your application.
|
||||
*
|
||||
* \note TagLib will *not* take ownership of the stream, the caller is
|
||||
* responsible for deleting it after the File object.
|
||||
*/
|
||||
explicit FileRef(IOStream* stream,
|
||||
bool readAudioProperties = true,
|
||||
AudioProperties::ReadStyle
|
||||
audioPropertiesStyle = AudioProperties::Average);
|
||||
|
||||
/*!
|
||||
* Construct a FileRef using \a file. The FileRef now takes ownership of the
|
||||
* pointer and will delete the File when it passes out of scope.
|
||||
*/
|
||||
explicit FileRef(File *file);
|
||||
|
||||
/*!
|
||||
* Make a copy of \a ref.
|
||||
*/
|
||||
FileRef(const FileRef &ref);
|
||||
|
||||
/*!
|
||||
* Destroys this FileRef instance.
|
||||
*/
|
||||
virtual ~FileRef();
|
||||
|
||||
/*!
|
||||
* Returns a pointer to represented file's tag.
|
||||
*
|
||||
* \warning This pointer will become invalid when this FileRef and all
|
||||
* copies pass out of scope.
|
||||
*
|
||||
* \warning Do not cast it to any subclasses of \class Tag.
|
||||
* Use tag returning methods of appropriate subclasses of \class File instead.
|
||||
*
|
||||
* \see File::tag()
|
||||
*/
|
||||
Tag *tag() const;
|
||||
|
||||
/*!
|
||||
* Returns the audio properties for this FileRef. If no audio properties
|
||||
* were read then this will returns a null pointer.
|
||||
*/
|
||||
AudioProperties *audioProperties() const;
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the file represented by this handler class.
|
||||
*
|
||||
* As a general rule this call should be avoided since if you need to work
|
||||
* with file objects directly, you are probably better served instantiating
|
||||
* the File subclasses (i.e. MPEG::File) manually and working with their APIs.
|
||||
*
|
||||
* This <i>handle</i> exists to provide a minimal, generic and value-based
|
||||
* wrapper around a File. Accessing the file directly generally indicates
|
||||
* a moving away from this simplicity (and into things beyond the scope of
|
||||
* FileRef).
|
||||
*
|
||||
* \warning This pointer will become invalid when this FileRef and all
|
||||
* copies pass out of scope.
|
||||
*/
|
||||
File *file() const;
|
||||
|
||||
/*!
|
||||
* Saves the file. Returns true on success.
|
||||
*/
|
||||
bool save();
|
||||
|
||||
/*!
|
||||
* Adds a FileTypeResolver to the list of those used by TagLib. Each
|
||||
* additional FileTypeResolver is added to the front of a list of resolvers
|
||||
* that are tried. If the FileTypeResolver returns zero the next resolver
|
||||
* is tried.
|
||||
*
|
||||
* Returns a pointer to the added resolver (the same one that's passed in --
|
||||
* this is mostly so that static initializers have something to use for
|
||||
* assignment).
|
||||
*
|
||||
* \see FileTypeResolver
|
||||
*/
|
||||
static const FileTypeResolver *addFileTypeResolver(const FileTypeResolver *resolver);
|
||||
|
||||
/*!
|
||||
* As is mentioned elsewhere in this class's documentation, the default file
|
||||
* type resolution code provided by TagLib only works by comparing file
|
||||
* extensions.
|
||||
*
|
||||
* This method returns the list of file extensions that are used by default.
|
||||
*
|
||||
* The extensions are all returned in lowercase, though the comparison used
|
||||
* by TagLib for resolution is case-insensitive.
|
||||
*
|
||||
* \note This does not account for any additional file type resolvers that
|
||||
* are plugged in. Also note that this is not intended to replace a proper
|
||||
* mime-type resolution system, but is just here for reference.
|
||||
*
|
||||
* \see FileTypeResolver
|
||||
*/
|
||||
static StringList defaultFileExtensions();
|
||||
|
||||
/*!
|
||||
* Returns true if the file (and as such other pointers) are null.
|
||||
*/
|
||||
bool isNull() const;
|
||||
|
||||
/*!
|
||||
* Assign the file pointed to by \a ref to this FileRef.
|
||||
*/
|
||||
FileRef &operator=(const FileRef &ref);
|
||||
|
||||
/*!
|
||||
* Exchanges the content of the FileRef by the content of \a ref.
|
||||
*/
|
||||
void swap(FileRef &ref);
|
||||
|
||||
/*!
|
||||
* Returns true if this FileRef and \a ref point to the same File object.
|
||||
*/
|
||||
bool operator==(const FileRef &ref) const;
|
||||
|
||||
/*!
|
||||
* Returns true if this FileRef and \a ref do not point to the same File
|
||||
* object.
|
||||
*/
|
||||
bool operator!=(const FileRef &ref) const;
|
||||
|
||||
/*!
|
||||
* A simple implementation of file type guessing. If \a readAudioProperties
|
||||
* is true then the audio properties will be read using
|
||||
* \a audioPropertiesStyle. If \a readAudioProperties is false then
|
||||
* \a audioPropertiesStyle will be ignored.
|
||||
*
|
||||
* \note You generally shouldn't use this method, but instead the constructor
|
||||
* directly.
|
||||
*
|
||||
* \deprecated
|
||||
*/
|
||||
static File *create(FileName fileName,
|
||||
bool readAudioProperties = true,
|
||||
AudioProperties::ReadStyle audioPropertiesStyle = AudioProperties::Average);
|
||||
|
||||
private:
|
||||
void parse(FileName fileName, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle);
|
||||
void parse(IOStream *stream, bool readAudioProperties, AudioProperties::ReadStyle audioPropertiesStyle);
|
||||
|
||||
class FileRefPrivate;
|
||||
FileRefPrivate *d;
|
||||
};
|
||||
|
||||
} // namespace TagLib
|
||||
|
||||
#endif
|
|
@ -1,583 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2003-2004 by Allan Sandfeld Jensen
|
||||
email : kde@carewolf.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/toolkit/tbytevector.h>
|
||||
#include <taglib/toolkit/tstring.h>
|
||||
#include <taglib/toolkit/tlist.h>
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <taglib/tagunion.h>
|
||||
#include <taglib/toolkit/tpropertymap.h>
|
||||
#include <taglib/tagutils.h>
|
||||
|
||||
#include <taglib/mpeg/id3v2/id3v2header.h>
|
||||
#include <taglib/mpeg/id3v2/id3v2tag.h>
|
||||
#include <taglib/mpeg/id3v1/id3v1tag.h>
|
||||
#include <taglib/ogg/xiphcomment.h>
|
||||
|
||||
#include <taglib/flac/flacpicture.h>
|
||||
#include <taglib/flac/flacfile.h>
|
||||
#include <taglib/flac/flacmetadatablock.h>
|
||||
#include <taglib/flac/flacunknownmetadatablock.h>
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
namespace
|
||||
{
|
||||
typedef List<FLAC::MetadataBlock *> BlockList;
|
||||
typedef BlockList::Iterator BlockIterator;
|
||||
typedef BlockList::Iterator BlockConstIterator;
|
||||
|
||||
enum { FlacXiphIndex = 0, FlacID3v2Index = 1, FlacID3v1Index = 2 };
|
||||
|
||||
const long MinPaddingLength = 4096;
|
||||
const long MaxPaddingLegnth = 1024 * 1024;
|
||||
|
||||
const char LastBlockFlag = '\x80';
|
||||
}
|
||||
|
||||
class FLAC::File::FilePrivate
|
||||
{
|
||||
public:
|
||||
FilePrivate(const ID3v2::FrameFactory *frameFactory = ID3v2::FrameFactory::instance()) :
|
||||
ID3v2FrameFactory(frameFactory),
|
||||
ID3v2Location(-1),
|
||||
ID3v2OriginalSize(0),
|
||||
ID3v1Location(-1),
|
||||
properties(0),
|
||||
flacStart(0),
|
||||
streamStart(0),
|
||||
scanned(false)
|
||||
{
|
||||
blocks.setAutoDelete(true);
|
||||
}
|
||||
|
||||
~FilePrivate()
|
||||
{
|
||||
delete properties;
|
||||
}
|
||||
|
||||
const ID3v2::FrameFactory *ID3v2FrameFactory;
|
||||
long ID3v2Location;
|
||||
long ID3v2OriginalSize;
|
||||
|
||||
long ID3v1Location;
|
||||
|
||||
TagUnion tag;
|
||||
|
||||
Properties *properties;
|
||||
ByteVector xiphCommentData;
|
||||
BlockList blocks;
|
||||
|
||||
long flacStart;
|
||||
long streamStart;
|
||||
bool scanned;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// static members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool FLAC::File::isSupported(IOStream *stream)
|
||||
{
|
||||
// A FLAC file has an ID "fLaC" somewhere. An ID3v2 tag may precede.
|
||||
|
||||
const ByteVector buffer = Utils::readHeader(stream, bufferSize(), true);
|
||||
return (buffer.find("fLaC") >= 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FLAC::File::File(FileName file, bool readProperties, Properties::ReadStyle) :
|
||||
TagLib::File(file),
|
||||
d(new FilePrivate())
|
||||
{
|
||||
if(isOpen())
|
||||
read(readProperties);
|
||||
}
|
||||
|
||||
FLAC::File::File(FileName file, ID3v2::FrameFactory *frameFactory,
|
||||
bool readProperties, Properties::ReadStyle) :
|
||||
TagLib::File(file),
|
||||
d(new FilePrivate(frameFactory))
|
||||
{
|
||||
if(isOpen())
|
||||
read(readProperties);
|
||||
}
|
||||
|
||||
FLAC::File::File(IOStream *stream, ID3v2::FrameFactory *frameFactory,
|
||||
bool readProperties, Properties::ReadStyle) :
|
||||
TagLib::File(stream),
|
||||
d(new FilePrivate(frameFactory))
|
||||
{
|
||||
if(isOpen())
|
||||
read(readProperties);
|
||||
}
|
||||
|
||||
FLAC::File::~File()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
TagLib::Tag *FLAC::File::tag() const
|
||||
{
|
||||
return &d->tag;
|
||||
}
|
||||
|
||||
PropertyMap FLAC::File::properties() const
|
||||
{
|
||||
return d->tag.properties();
|
||||
}
|
||||
|
||||
void FLAC::File::removeUnsupportedProperties(const StringList &unsupported)
|
||||
{
|
||||
d->tag.removeUnsupportedProperties(unsupported);
|
||||
}
|
||||
|
||||
PropertyMap FLAC::File::setProperties(const PropertyMap &properties)
|
||||
{
|
||||
return xiphComment(true)->setProperties(properties);
|
||||
}
|
||||
|
||||
FLAC::Properties *FLAC::File::audioProperties() const
|
||||
{
|
||||
return d->properties;
|
||||
}
|
||||
|
||||
bool FLAC::File::save()
|
||||
{
|
||||
if(readOnly()) {
|
||||
debug("FLAC::File::save() - Cannot save to a read only file.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!isValid()) {
|
||||
debug("FLAC::File::save() -- Trying to save invalid file.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create new vorbis comments
|
||||
if(!hasXiphComment())
|
||||
Tag::duplicate(&d->tag, xiphComment(true), false);
|
||||
|
||||
d->xiphCommentData = xiphComment()->render(false);
|
||||
|
||||
// Replace metadata blocks
|
||||
|
||||
MetadataBlock *commentBlock =
|
||||
new UnknownMetadataBlock(MetadataBlock::VorbisComment, d->xiphCommentData);
|
||||
for(BlockIterator it = d->blocks.begin(); it != d->blocks.end();) {
|
||||
if((*it)->code() == MetadataBlock::VorbisComment) {
|
||||
// Remove the old Vorbis Comment block
|
||||
delete *it;
|
||||
it = d->blocks.erase(it);
|
||||
continue;
|
||||
}
|
||||
if(commentBlock && (*it)->code() == MetadataBlock::Picture) {
|
||||
// Set the new Vorbis Comment block before the first picture block
|
||||
d->blocks.insert(it, commentBlock);
|
||||
commentBlock = 0;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
if(commentBlock)
|
||||
d->blocks.append(commentBlock);
|
||||
|
||||
// Render data for the metadata blocks
|
||||
|
||||
ByteVector data;
|
||||
for(BlockConstIterator it = d->blocks.begin(); it != d->blocks.end(); ++it) {
|
||||
ByteVector blockData = (*it)->render();
|
||||
ByteVector blockHeader = ByteVector::fromUInt(blockData.size());
|
||||
blockHeader[0] = (*it)->code();
|
||||
data.append(blockHeader);
|
||||
data.append(blockData);
|
||||
}
|
||||
|
||||
// Compute the amount of padding, and append that to data.
|
||||
|
||||
long originalLength = d->streamStart - d->flacStart;
|
||||
long paddingLength = originalLength - data.size() - 4;
|
||||
|
||||
if(paddingLength <= 0) {
|
||||
paddingLength = MinPaddingLength;
|
||||
}
|
||||
else {
|
||||
// Padding won't increase beyond 1% of the file size or 1MB.
|
||||
|
||||
long threshold = length() / 100;
|
||||
threshold = std::max(threshold, MinPaddingLength);
|
||||
threshold = std::min(threshold, MaxPaddingLegnth);
|
||||
|
||||
if(paddingLength > threshold)
|
||||
paddingLength = MinPaddingLength;
|
||||
}
|
||||
|
||||
ByteVector paddingHeader = ByteVector::fromUInt(paddingLength);
|
||||
paddingHeader[0] = static_cast<char>(MetadataBlock::Padding | LastBlockFlag);
|
||||
data.append(paddingHeader);
|
||||
data.resize(static_cast<unsigned int>(data.size() + paddingLength));
|
||||
|
||||
// Write the data to the file
|
||||
|
||||
insert(data, d->flacStart, originalLength);
|
||||
|
||||
d->streamStart += (static_cast<long>(data.size()) - originalLength);
|
||||
|
||||
if(d->ID3v1Location >= 0)
|
||||
d->ID3v1Location += (static_cast<long>(data.size()) - originalLength);
|
||||
|
||||
// Update ID3 tags
|
||||
|
||||
if(ID3v2Tag() && !ID3v2Tag()->isEmpty()) {
|
||||
|
||||
// ID3v2 tag is not empty. Update the old one or create a new one.
|
||||
|
||||
if(d->ID3v2Location < 0)
|
||||
d->ID3v2Location = 0;
|
||||
|
||||
data = ID3v2Tag()->render();
|
||||
insert(data, d->ID3v2Location, d->ID3v2OriginalSize);
|
||||
|
||||
d->flacStart += (static_cast<long>(data.size()) - d->ID3v2OriginalSize);
|
||||
d->streamStart += (static_cast<long>(data.size()) - d->ID3v2OriginalSize);
|
||||
|
||||
if(d->ID3v1Location >= 0)
|
||||
d->ID3v1Location += (static_cast<long>(data.size()) - d->ID3v2OriginalSize);
|
||||
|
||||
d->ID3v2OriginalSize = data.size();
|
||||
}
|
||||
else {
|
||||
|
||||
// ID3v2 tag is empty. Remove the old one.
|
||||
|
||||
if(d->ID3v2Location >= 0) {
|
||||
removeBlock(d->ID3v2Location, d->ID3v2OriginalSize);
|
||||
|
||||
d->flacStart -= d->ID3v2OriginalSize;
|
||||
d->streamStart -= d->ID3v2OriginalSize;
|
||||
|
||||
if(d->ID3v1Location >= 0)
|
||||
d->ID3v1Location -= d->ID3v2OriginalSize;
|
||||
|
||||
d->ID3v2Location = -1;
|
||||
d->ID3v2OriginalSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(ID3v1Tag() && !ID3v1Tag()->isEmpty()) {
|
||||
|
||||
// ID3v1 tag is not empty. Update the old one or create a new one.
|
||||
|
||||
if(d->ID3v1Location >= 0) {
|
||||
seek(d->ID3v1Location);
|
||||
}
|
||||
else {
|
||||
seek(0, End);
|
||||
d->ID3v1Location = tell();
|
||||
}
|
||||
|
||||
writeBlock(ID3v1Tag()->render());
|
||||
}
|
||||
else {
|
||||
|
||||
// ID3v1 tag is empty. Remove the old one.
|
||||
|
||||
if(d->ID3v1Location >= 0) {
|
||||
truncate(d->ID3v1Location);
|
||||
d->ID3v1Location = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ID3v2::Tag *FLAC::File::ID3v2Tag(bool create)
|
||||
{
|
||||
return d->tag.access<ID3v2::Tag>(FlacID3v2Index, create);
|
||||
}
|
||||
|
||||
ID3v1::Tag *FLAC::File::ID3v1Tag(bool create)
|
||||
{
|
||||
return d->tag.access<ID3v1::Tag>(FlacID3v1Index, create);
|
||||
}
|
||||
|
||||
Ogg::XiphComment *FLAC::File::xiphComment(bool create)
|
||||
{
|
||||
return d->tag.access<Ogg::XiphComment>(FlacXiphIndex, create);
|
||||
}
|
||||
|
||||
void FLAC::File::setID3v2FrameFactory(const ID3v2::FrameFactory *factory)
|
||||
{
|
||||
d->ID3v2FrameFactory = factory;
|
||||
}
|
||||
|
||||
ByteVector FLAC::File::streamInfoData()
|
||||
{
|
||||
debug("FLAC::File::streamInfoData() -- This function is obsolete. Returning an empty ByteVector.");
|
||||
return ByteVector();
|
||||
}
|
||||
|
||||
long FLAC::File::streamLength()
|
||||
{
|
||||
debug("FLAC::File::streamLength() -- This function is obsolete. Returning zero.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
List<FLAC::Picture *> FLAC::File::pictureList()
|
||||
{
|
||||
List<Picture *> pictures;
|
||||
for(BlockConstIterator it = d->blocks.begin(); it != d->blocks.end(); ++it) {
|
||||
Picture *picture = dynamic_cast<Picture *>(*it);
|
||||
if(picture) {
|
||||
pictures.append(picture);
|
||||
}
|
||||
}
|
||||
return pictures;
|
||||
}
|
||||
|
||||
void FLAC::File::addPicture(Picture *picture)
|
||||
{
|
||||
d->blocks.append(picture);
|
||||
}
|
||||
|
||||
void FLAC::File::removePicture(Picture *picture, bool del)
|
||||
{
|
||||
BlockIterator it = d->blocks.find(picture);
|
||||
if(it != d->blocks.end())
|
||||
d->blocks.erase(it);
|
||||
|
||||
if(del)
|
||||
delete picture;
|
||||
}
|
||||
|
||||
void FLAC::File::removePictures()
|
||||
{
|
||||
for(BlockIterator it = d->blocks.begin(); it != d->blocks.end(); ) {
|
||||
if(dynamic_cast<Picture *>(*it)) {
|
||||
delete *it;
|
||||
it = d->blocks.erase(it);
|
||||
}
|
||||
else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FLAC::File::strip(int tags)
|
||||
{
|
||||
if(tags & ID3v1)
|
||||
d->tag.set(FlacID3v1Index, 0);
|
||||
|
||||
if(tags & ID3v2)
|
||||
d->tag.set(FlacID3v2Index, 0);
|
||||
|
||||
if(tags & XiphComment) {
|
||||
xiphComment()->removeAllFields();
|
||||
xiphComment()->removeAllPictures();
|
||||
}
|
||||
}
|
||||
|
||||
bool FLAC::File::hasXiphComment() const
|
||||
{
|
||||
return !d->xiphCommentData.isEmpty();
|
||||
}
|
||||
|
||||
bool FLAC::File::hasID3v1Tag() const
|
||||
{
|
||||
return (d->ID3v1Location >= 0);
|
||||
}
|
||||
|
||||
bool FLAC::File::hasID3v2Tag() const
|
||||
{
|
||||
return (d->ID3v2Location >= 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void FLAC::File::read(bool readProperties)
|
||||
{
|
||||
// Look for an ID3v2 tag
|
||||
|
||||
d->ID3v2Location = Utils::findID3v2(this);
|
||||
|
||||
if(d->ID3v2Location >= 0) {
|
||||
d->tag.set(FlacID3v2Index, new ID3v2::Tag(this, d->ID3v2Location, d->ID3v2FrameFactory));
|
||||
d->ID3v2OriginalSize = ID3v2Tag()->header()->completeTagSize();
|
||||
}
|
||||
|
||||
// Look for an ID3v1 tag
|
||||
|
||||
d->ID3v1Location = Utils::findID3v1(this);
|
||||
|
||||
if(d->ID3v1Location >= 0)
|
||||
d->tag.set(FlacID3v1Index, new ID3v1::Tag(this, d->ID3v1Location));
|
||||
|
||||
// Look for FLAC metadata, including vorbis comments
|
||||
|
||||
scan();
|
||||
|
||||
if(!isValid())
|
||||
return;
|
||||
|
||||
if(!d->xiphCommentData.isEmpty())
|
||||
d->tag.set(FlacXiphIndex, new Ogg::XiphComment(d->xiphCommentData));
|
||||
else
|
||||
d->tag.set(FlacXiphIndex, new Ogg::XiphComment());
|
||||
|
||||
if(readProperties) {
|
||||
|
||||
// First block should be the stream_info metadata
|
||||
|
||||
const ByteVector infoData = d->blocks.front()->render();
|
||||
|
||||
long streamLength;
|
||||
|
||||
if(d->ID3v1Location >= 0)
|
||||
streamLength = d->ID3v1Location - d->streamStart;
|
||||
else
|
||||
streamLength = length() - d->streamStart;
|
||||
|
||||
d->properties = new Properties(infoData, streamLength);
|
||||
}
|
||||
}
|
||||
|
||||
void FLAC::File::scan()
|
||||
{
|
||||
// Scan the metadata pages
|
||||
|
||||
if(d->scanned)
|
||||
return;
|
||||
|
||||
if(!isValid())
|
||||
return;
|
||||
|
||||
long nextBlockOffset;
|
||||
|
||||
if(d->ID3v2Location >= 0)
|
||||
nextBlockOffset = find("fLaC", d->ID3v2Location + d->ID3v2OriginalSize);
|
||||
else
|
||||
nextBlockOffset = find("fLaC");
|
||||
|
||||
if(nextBlockOffset < 0) {
|
||||
debug("FLAC::File::scan() -- FLAC stream not found");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
nextBlockOffset += 4;
|
||||
d->flacStart = nextBlockOffset;
|
||||
|
||||
while(true) {
|
||||
|
||||
seek(nextBlockOffset);
|
||||
const ByteVector header = readBlock(4);
|
||||
|
||||
// Header format (from spec):
|
||||
// <1> Last-metadata-block flag
|
||||
// <7> BLOCK_TYPE
|
||||
// 0 : STREAMINFO
|
||||
// 1 : PADDING
|
||||
// ..
|
||||
// 4 : VORBIS_COMMENT
|
||||
// ..
|
||||
// 6 : PICTURE
|
||||
// ..
|
||||
// <24> Length of metadata to follow
|
||||
|
||||
const char blockType = header[0] & ~LastBlockFlag;
|
||||
const bool isLastBlock = (header[0] & LastBlockFlag) != 0;
|
||||
const unsigned int blockLength = header.toUInt(1U, 3U);
|
||||
|
||||
// First block should be the stream_info metadata
|
||||
|
||||
if(d->blocks.isEmpty() && blockType != MetadataBlock::StreamInfo) {
|
||||
debug("FLAC::File::scan() -- First block should be the stream_info metadata");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if(blockLength == 0
|
||||
&& blockType != MetadataBlock::Padding && blockType != MetadataBlock::SeekTable)
|
||||
{
|
||||
debug("FLAC::File::scan() -- Zero-sized metadata block found");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const ByteVector data = readBlock(blockLength);
|
||||
if(data.size() != blockLength) {
|
||||
debug("FLAC::File::scan() -- Failed to read a metadata block");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
MetadataBlock *block = 0;
|
||||
|
||||
// Found the vorbis-comment
|
||||
if(blockType == MetadataBlock::VorbisComment) {
|
||||
if(d->xiphCommentData.isEmpty()) {
|
||||
d->xiphCommentData = data;
|
||||
block = new UnknownMetadataBlock(MetadataBlock::VorbisComment, data);
|
||||
}
|
||||
else {
|
||||
debug("FLAC::File::scan() -- multiple Vorbis Comment blocks found, discarding");
|
||||
}
|
||||
}
|
||||
else if(blockType == MetadataBlock::Picture) {
|
||||
FLAC::Picture *picture = new FLAC::Picture();
|
||||
if(picture->parse(data)) {
|
||||
block = picture;
|
||||
}
|
||||
else {
|
||||
debug("FLAC::File::scan() -- invalid picture found, discarding");
|
||||
delete picture;
|
||||
}
|
||||
}
|
||||
else if(blockType == MetadataBlock::Padding) {
|
||||
// Skip all padding blocks.
|
||||
}
|
||||
else {
|
||||
block = new UnknownMetadataBlock(blockType, data);
|
||||
}
|
||||
|
||||
if(block)
|
||||
d->blocks.append(block);
|
||||
|
||||
nextBlockOffset += blockLength + 4;
|
||||
|
||||
if(isLastBlock)
|
||||
break;
|
||||
}
|
||||
|
||||
// End of metadata, now comes the datastream
|
||||
|
||||
d->streamStart = nextBlockOffset;
|
||||
|
||||
d->scanned = true;
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
/**************************************************************************
|
||||
copyright : (C) 2010 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/toolkit/taglib.h>
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <taglib/flac/flacmetadatablock.h>
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class FLAC::MetadataBlock::MetadataBlockPrivate
|
||||
{
|
||||
public:
|
||||
MetadataBlockPrivate() {}
|
||||
|
||||
};
|
||||
|
||||
FLAC::MetadataBlock::MetadataBlock()
|
||||
{
|
||||
d = 0;
|
||||
}
|
||||
|
||||
FLAC::MetadataBlock::~MetadataBlock()
|
||||
{
|
||||
}
|
||||
|
|
@ -1,217 +0,0 @@
|
|||
/**************************************************************************
|
||||
copyright : (C) 2010 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/toolkit/taglib.h>
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <taglib/flac/flacpicture.h>
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class FLAC::Picture::PicturePrivate
|
||||
{
|
||||
public:
|
||||
PicturePrivate() :
|
||||
type(FLAC::Picture::Other),
|
||||
width(0),
|
||||
height(0),
|
||||
colorDepth(0),
|
||||
numColors(0)
|
||||
{}
|
||||
|
||||
Type type;
|
||||
String mimeType;
|
||||
String description;
|
||||
int width;
|
||||
int height;
|
||||
int colorDepth;
|
||||
int numColors;
|
||||
ByteVector data;
|
||||
};
|
||||
|
||||
FLAC::Picture::Picture() :
|
||||
d(new PicturePrivate())
|
||||
{
|
||||
}
|
||||
|
||||
FLAC::Picture::Picture(const ByteVector &data) :
|
||||
d(new PicturePrivate())
|
||||
{
|
||||
parse(data);
|
||||
}
|
||||
|
||||
FLAC::Picture::~Picture()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
int FLAC::Picture::code() const
|
||||
{
|
||||
return FLAC::MetadataBlock::Picture;
|
||||
}
|
||||
|
||||
bool FLAC::Picture::parse(const ByteVector &data)
|
||||
{
|
||||
if(data.size() < 32) {
|
||||
debug("A picture block must contain at least 5 bytes.");
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int pos = 0;
|
||||
d->type = FLAC::Picture::Type(data.toUInt(pos));
|
||||
pos += 4;
|
||||
unsigned int mimeTypeLength = data.toUInt(pos);
|
||||
pos += 4;
|
||||
if(pos + mimeTypeLength + 24 > data.size()) {
|
||||
debug("Invalid picture block.");
|
||||
return false;
|
||||
}
|
||||
d->mimeType = String(data.mid(pos, mimeTypeLength), String::UTF8);
|
||||
pos += mimeTypeLength;
|
||||
unsigned int descriptionLength = data.toUInt(pos);
|
||||
pos += 4;
|
||||
if(pos + descriptionLength + 20 > data.size()) {
|
||||
debug("Invalid picture block.");
|
||||
return false;
|
||||
}
|
||||
d->description = String(data.mid(pos, descriptionLength), String::UTF8);
|
||||
pos += descriptionLength;
|
||||
d->width = data.toUInt(pos);
|
||||
pos += 4;
|
||||
d->height = data.toUInt(pos);
|
||||
pos += 4;
|
||||
d->colorDepth = data.toUInt(pos);
|
||||
pos += 4;
|
||||
d->numColors = data.toUInt(pos);
|
||||
pos += 4;
|
||||
unsigned int dataLength = data.toUInt(pos);
|
||||
pos += 4;
|
||||
if(pos + dataLength > data.size()) {
|
||||
debug("Invalid picture block.");
|
||||
return false;
|
||||
}
|
||||
d->data = data.mid(pos, dataLength);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ByteVector FLAC::Picture::render() const
|
||||
{
|
||||
ByteVector result;
|
||||
result.append(ByteVector::fromUInt(d->type));
|
||||
ByteVector mimeTypeData = d->mimeType.data(String::UTF8);
|
||||
result.append(ByteVector::fromUInt(mimeTypeData.size()));
|
||||
result.append(mimeTypeData);
|
||||
ByteVector descriptionData = d->description.data(String::UTF8);
|
||||
result.append(ByteVector::fromUInt(descriptionData.size()));
|
||||
result.append(descriptionData);
|
||||
result.append(ByteVector::fromUInt(d->width));
|
||||
result.append(ByteVector::fromUInt(d->height));
|
||||
result.append(ByteVector::fromUInt(d->colorDepth));
|
||||
result.append(ByteVector::fromUInt(d->numColors));
|
||||
result.append(ByteVector::fromUInt(d->data.size()));
|
||||
result.append(d->data);
|
||||
return result;
|
||||
}
|
||||
|
||||
FLAC::Picture::Type FLAC::Picture::type() const
|
||||
{
|
||||
return d->type;
|
||||
}
|
||||
|
||||
void FLAC::Picture::setType(FLAC::Picture::Type type)
|
||||
{
|
||||
d->type = type;
|
||||
}
|
||||
|
||||
String FLAC::Picture::mimeType() const
|
||||
{
|
||||
return d->mimeType;
|
||||
}
|
||||
|
||||
void FLAC::Picture::setMimeType(const String &mimeType)
|
||||
{
|
||||
d->mimeType = mimeType;
|
||||
}
|
||||
|
||||
String FLAC::Picture::description() const
|
||||
{
|
||||
return d->description;
|
||||
}
|
||||
|
||||
void FLAC::Picture::setDescription(const String &description)
|
||||
{
|
||||
d->description = description;
|
||||
}
|
||||
|
||||
int FLAC::Picture::width() const
|
||||
{
|
||||
return d->width;
|
||||
}
|
||||
|
||||
void FLAC::Picture::setWidth(int width)
|
||||
{
|
||||
d->width = width;
|
||||
}
|
||||
|
||||
int FLAC::Picture::height() const
|
||||
{
|
||||
return d->height;
|
||||
}
|
||||
|
||||
void FLAC::Picture::setHeight(int height)
|
||||
{
|
||||
d->height = height;
|
||||
}
|
||||
|
||||
int FLAC::Picture::colorDepth() const
|
||||
{
|
||||
return d->colorDepth;
|
||||
}
|
||||
|
||||
void FLAC::Picture::setColorDepth(int colorDepth)
|
||||
{
|
||||
d->colorDepth = colorDepth;
|
||||
}
|
||||
|
||||
int FLAC::Picture::numColors() const
|
||||
{
|
||||
return d->numColors;
|
||||
}
|
||||
|
||||
void FLAC::Picture::setNumColors(int numColors)
|
||||
{
|
||||
d->numColors = numColors;
|
||||
}
|
||||
|
||||
ByteVector FLAC::Picture::data() const
|
||||
{
|
||||
return d->data;
|
||||
}
|
||||
|
||||
void FLAC::Picture::setData(const ByteVector &data)
|
||||
{
|
||||
d->data = data;
|
||||
}
|
||||
|
|
@ -1,176 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2003 by Allan Sandfeld Jensen
|
||||
email : kde@carewolf.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/toolkit/tstring.h>
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
|
||||
#include <taglib/flac/flacproperties.h>
|
||||
#include <taglib/flac/flacfile.h>
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class FLAC::Properties::PropertiesPrivate
|
||||
{
|
||||
public:
|
||||
PropertiesPrivate() :
|
||||
length(0),
|
||||
bitrate(0),
|
||||
sampleRate(0),
|
||||
bitsPerSample(0),
|
||||
channels(0),
|
||||
sampleFrames(0) {}
|
||||
|
||||
int length;
|
||||
int bitrate;
|
||||
int sampleRate;
|
||||
int bitsPerSample;
|
||||
int channels;
|
||||
unsigned long long sampleFrames;
|
||||
ByteVector signature;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FLAC::Properties::Properties(ByteVector data, long streamLength, ReadStyle style) :
|
||||
AudioProperties(style),
|
||||
d(new PropertiesPrivate())
|
||||
{
|
||||
read(data, streamLength);
|
||||
}
|
||||
|
||||
FLAC::Properties::Properties(File *, ReadStyle style) :
|
||||
AudioProperties(style),
|
||||
d(new PropertiesPrivate())
|
||||
{
|
||||
debug("FLAC::Properties::Properties() - This constructor is no longer used.");
|
||||
}
|
||||
|
||||
FLAC::Properties::~Properties()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
int FLAC::Properties::length() const
|
||||
{
|
||||
return lengthInSeconds();
|
||||
}
|
||||
|
||||
int FLAC::Properties::lengthInSeconds() const
|
||||
{
|
||||
return d->length / 1000;
|
||||
}
|
||||
|
||||
int FLAC::Properties::lengthInMilliseconds() const
|
||||
{
|
||||
return d->length;
|
||||
}
|
||||
|
||||
int FLAC::Properties::bitrate() const
|
||||
{
|
||||
return d->bitrate;
|
||||
}
|
||||
|
||||
int FLAC::Properties::sampleRate() const
|
||||
{
|
||||
return d->sampleRate;
|
||||
}
|
||||
|
||||
int FLAC::Properties::bitsPerSample() const
|
||||
{
|
||||
return d->bitsPerSample;
|
||||
}
|
||||
|
||||
int FLAC::Properties::sampleWidth() const
|
||||
{
|
||||
return bitsPerSample();
|
||||
}
|
||||
|
||||
int FLAC::Properties::channels() const
|
||||
{
|
||||
return d->channels;
|
||||
}
|
||||
|
||||
unsigned long long FLAC::Properties::sampleFrames() const
|
||||
{
|
||||
return d->sampleFrames;
|
||||
}
|
||||
|
||||
ByteVector FLAC::Properties::signature() const
|
||||
{
|
||||
return d->signature;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void FLAC::Properties::read(const ByteVector &data, long streamLength)
|
||||
{
|
||||
if(data.size() < 18) {
|
||||
debug("FLAC::Properties::read() - FLAC properties must contain at least 18 bytes.");
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int pos = 0;
|
||||
|
||||
// Minimum block size (in samples)
|
||||
pos += 2;
|
||||
|
||||
// Maximum block size (in samples)
|
||||
pos += 2;
|
||||
|
||||
// Minimum frame size (in bytes)
|
||||
pos += 3;
|
||||
|
||||
// Maximum frame size (in bytes)
|
||||
pos += 3;
|
||||
|
||||
const unsigned int flags = data.toUInt(pos, true);
|
||||
pos += 4;
|
||||
|
||||
d->sampleRate = flags >> 12;
|
||||
d->channels = ((flags >> 9) & 7) + 1;
|
||||
d->bitsPerSample = ((flags >> 4) & 31) + 1;
|
||||
|
||||
// The last 4 bits are the most significant 4 bits for the 36 bit
|
||||
// stream length in samples. (Audio files measured in days)
|
||||
|
||||
const unsigned long long hi = flags & 0xf;
|
||||
const unsigned long long lo = data.toUInt(pos, true);
|
||||
pos += 4;
|
||||
|
||||
d->sampleFrames = (hi << 32) | lo;
|
||||
|
||||
if(d->sampleFrames > 0 && d->sampleRate > 0) {
|
||||
const double length = d->sampleFrames * 1000.0 / d->sampleRate;
|
||||
d->length = static_cast<int>(length + 0.5);
|
||||
d->bitrate = static_cast<int>(streamLength * 8.0 / length + 0.5);
|
||||
}
|
||||
|
||||
if(data.size() >= pos + 16)
|
||||
d->signature = data.mid(pos, 16);
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
/**************************************************************************
|
||||
copyright : (C) 2010 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/toolkit/taglib.h>
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <taglib/toolkit/tstring.h>
|
||||
#include <taglib/flac/flacunknownmetadatablock.h>
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class FLAC::UnknownMetadataBlock::UnknownMetadataBlockPrivate
|
||||
{
|
||||
public:
|
||||
UnknownMetadataBlockPrivate() : code(0) {}
|
||||
|
||||
int code;
|
||||
ByteVector data;
|
||||
};
|
||||
|
||||
FLAC::UnknownMetadataBlock::UnknownMetadataBlock(int code, const ByteVector &data) :
|
||||
d(new UnknownMetadataBlockPrivate())
|
||||
{
|
||||
d->code = code;
|
||||
d->data = data;
|
||||
}
|
||||
|
||||
FLAC::UnknownMetadataBlock::~UnknownMetadataBlock()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
int FLAC::UnknownMetadataBlock::code() const
|
||||
{
|
||||
return d->code;
|
||||
}
|
||||
|
||||
void FLAC::UnknownMetadataBlock::setCode(int code)
|
||||
{
|
||||
d->code = code;
|
||||
}
|
||||
|
||||
ByteVector FLAC::UnknownMetadataBlock::data() const
|
||||
{
|
||||
return d->data;
|
||||
}
|
||||
|
||||
void FLAC::UnknownMetadataBlock::setData(const ByteVector &data)
|
||||
{
|
||||
d->data = data;
|
||||
}
|
||||
|
||||
ByteVector FLAC::UnknownMetadataBlock::render() const
|
||||
{
|
||||
return d->data;
|
||||
}
|
||||
|
|
@ -1,335 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2011 by Mathias Panzenböck
|
||||
email : grosser.meister.morti@gmx.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include <taglib/toolkit/tstringlist.h>
|
||||
#include <taglib/it/itfile.h>
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <taglib/mod/modfileprivate.h>
|
||||
#include <taglib/toolkit/tpropertymap.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace IT;
|
||||
|
||||
class IT::File::FilePrivate
|
||||
{
|
||||
public:
|
||||
FilePrivate(AudioProperties::ReadStyle propertiesStyle)
|
||||
: tag(), properties(propertiesStyle)
|
||||
{
|
||||
}
|
||||
|
||||
Mod::Tag tag;
|
||||
IT::Properties properties;
|
||||
};
|
||||
|
||||
IT::File::File(FileName file, bool readProperties,
|
||||
AudioProperties::ReadStyle propertiesStyle) :
|
||||
Mod::FileBase(file),
|
||||
d(new FilePrivate(propertiesStyle))
|
||||
{
|
||||
if(isOpen())
|
||||
read(readProperties);
|
||||
}
|
||||
|
||||
IT::File::File(IOStream *stream, bool readProperties,
|
||||
AudioProperties::ReadStyle propertiesStyle) :
|
||||
Mod::FileBase(stream),
|
||||
d(new FilePrivate(propertiesStyle))
|
||||
{
|
||||
if(isOpen())
|
||||
read(readProperties);
|
||||
}
|
||||
|
||||
IT::File::~File()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
Mod::Tag *IT::File::tag() const
|
||||
{
|
||||
return &d->tag;
|
||||
}
|
||||
|
||||
PropertyMap IT::File::properties() const
|
||||
{
|
||||
return d->tag.properties();
|
||||
}
|
||||
|
||||
PropertyMap IT::File::setProperties(const PropertyMap &properties)
|
||||
{
|
||||
return d->tag.setProperties(properties);
|
||||
}
|
||||
|
||||
IT::Properties *IT::File::audioProperties() const
|
||||
{
|
||||
return &d->properties;
|
||||
}
|
||||
|
||||
bool IT::File::save()
|
||||
{
|
||||
if(readOnly())
|
||||
{
|
||||
debug("IT::File::save() - Cannot save to a read only file.");
|
||||
return false;
|
||||
}
|
||||
seek(4);
|
||||
writeString(d->tag.title(), 25);
|
||||
writeByte(0);
|
||||
|
||||
seek(2, Current);
|
||||
|
||||
unsigned short length = 0;
|
||||
unsigned short instrumentCount = 0;
|
||||
unsigned short sampleCount = 0;
|
||||
|
||||
if(!readU16L(length) || !readU16L(instrumentCount) || !readU16L(sampleCount))
|
||||
return false;
|
||||
|
||||
seek(15, Current);
|
||||
|
||||
// write comment as instrument and sample names:
|
||||
StringList lines = d->tag.comment().split("\n");
|
||||
for(unsigned short i = 0; i < instrumentCount; ++ i) {
|
||||
seek(192L + length + ((long)i << 2));
|
||||
unsigned long instrumentOffset = 0;
|
||||
if(!readU32L(instrumentOffset))
|
||||
return false;
|
||||
|
||||
seek(instrumentOffset + 32);
|
||||
|
||||
if(i < lines.size())
|
||||
writeString(lines[i], 25);
|
||||
else
|
||||
writeString(String(), 25);
|
||||
writeByte(0);
|
||||
}
|
||||
|
||||
for(unsigned short i = 0; i < sampleCount; ++ i) {
|
||||
seek(192L + length + ((long)instrumentCount << 2) + ((long)i << 2));
|
||||
unsigned long sampleOffset = 0;
|
||||
if(!readU32L(sampleOffset))
|
||||
return false;
|
||||
|
||||
seek(sampleOffset + 20);
|
||||
|
||||
if((unsigned int)(i + instrumentCount) < lines.size())
|
||||
writeString(lines[i + instrumentCount], 25);
|
||||
else
|
||||
writeString(String(), 25);
|
||||
writeByte(0);
|
||||
}
|
||||
|
||||
// write rest as message:
|
||||
StringList messageLines;
|
||||
for(unsigned int i = instrumentCount + sampleCount; i < lines.size(); ++ i)
|
||||
messageLines.append(lines[i]);
|
||||
ByteVector message = messageLines.toString("\r").data(String::Latin1);
|
||||
|
||||
// it's actually not really stated if the message needs a
|
||||
// terminating NUL but it does not hurt to add one:
|
||||
if(message.size() > 7999)
|
||||
message.resize(7999);
|
||||
message.append((char)0);
|
||||
|
||||
unsigned short special = 0;
|
||||
unsigned short messageLength = 0;
|
||||
unsigned long messageOffset = 0;
|
||||
|
||||
seek(46);
|
||||
if(!readU16L(special))
|
||||
return false;
|
||||
|
||||
unsigned long fileSize = File::length();
|
||||
if(special & Properties::MessageAttached) {
|
||||
seek(54);
|
||||
if(!readU16L(messageLength) || !readU32L(messageOffset))
|
||||
return false;
|
||||
|
||||
if(messageLength == 0)
|
||||
messageOffset = fileSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
messageOffset = fileSize;
|
||||
seek(46);
|
||||
writeU16L(special | 0x1);
|
||||
}
|
||||
|
||||
if(messageOffset + messageLength >= fileSize) {
|
||||
// append new message
|
||||
seek(54);
|
||||
writeU16L(message.size());
|
||||
writeU32L(messageOffset);
|
||||
seek(messageOffset);
|
||||
writeBlock(message);
|
||||
truncate(messageOffset + message.size());
|
||||
}
|
||||
else {
|
||||
// Only overwrite existing message.
|
||||
// I'd need to parse (understand!) the whole file for more.
|
||||
// Although I could just move the message to the end of file
|
||||
// and let the existing one be, but that would waste space.
|
||||
message.resize(messageLength, 0);
|
||||
seek(messageOffset);
|
||||
writeBlock(message);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void IT::File::read(bool)
|
||||
{
|
||||
if(!isOpen())
|
||||
return;
|
||||
|
||||
seek(0);
|
||||
READ_ASSERT(readBlock(4) == "IMPM");
|
||||
READ_STRING(d->tag.setTitle, 26);
|
||||
|
||||
seek(2, Current);
|
||||
|
||||
READ_U16L_AS(length);
|
||||
READ_U16L_AS(instrumentCount);
|
||||
READ_U16L_AS(sampleCount);
|
||||
|
||||
d->properties.setInstrumentCount(instrumentCount);
|
||||
d->properties.setSampleCount(sampleCount);
|
||||
READ_U16L(d->properties.setPatternCount);
|
||||
READ_U16L(d->properties.setVersion);
|
||||
READ_U16L(d->properties.setCompatibleVersion);
|
||||
READ_U16L(d->properties.setFlags);
|
||||
READ_U16L_AS(special);
|
||||
d->properties.setSpecial(special);
|
||||
READ_BYTE(d->properties.setGlobalVolume);
|
||||
READ_BYTE(d->properties.setMixVolume);
|
||||
READ_BYTE(d->properties.setBpmSpeed);
|
||||
READ_BYTE(d->properties.setTempo);
|
||||
READ_BYTE(d->properties.setPanningSeparation);
|
||||
READ_BYTE(d->properties.setPitchWheelDepth);
|
||||
|
||||
// IT supports some kind of comment tag. Still, the
|
||||
// sample/instrument names are abused as comments so
|
||||
// I just add all together.
|
||||
String message;
|
||||
if(special & Properties::MessageAttached) {
|
||||
READ_U16L_AS(messageLength);
|
||||
READ_U32L_AS(messageOffset);
|
||||
seek(messageOffset);
|
||||
ByteVector messageBytes = readBlock(messageLength);
|
||||
READ_ASSERT(messageBytes.size() == messageLength);
|
||||
int index = messageBytes.find((char) 0);
|
||||
if(index > -1)
|
||||
messageBytes.resize(index, 0);
|
||||
messageBytes.replace('\r', '\n');
|
||||
message = messageBytes;
|
||||
}
|
||||
|
||||
seek(64);
|
||||
|
||||
ByteVector pannings = readBlock(64);
|
||||
ByteVector volumes = readBlock(64);
|
||||
READ_ASSERT(pannings.size() == 64 && volumes.size() == 64);
|
||||
int channels = 0;
|
||||
for(int i = 0; i < 64; ++ i) {
|
||||
// Strictly speaking an IT file has always 64 channels, but
|
||||
// I don't count disabled and muted channels.
|
||||
// But this always gives 64 channels for all my files anyway.
|
||||
// Strangely VLC does report other values. I wonder how VLC
|
||||
// gets it's values.
|
||||
if((unsigned char) pannings[i] < 128 && volumes[i] > 0)
|
||||
++channels;
|
||||
}
|
||||
d->properties.setChannels(channels);
|
||||
|
||||
// real length might be shorter because of skips and terminator
|
||||
unsigned short realLength = 0;
|
||||
for(unsigned short i = 0; i < length; ++ i) {
|
||||
READ_BYTE_AS(order);
|
||||
if(order == 255) break;
|
||||
if(order != 254) ++ realLength;
|
||||
}
|
||||
d->properties.setLengthInPatterns(realLength);
|
||||
|
||||
StringList comment;
|
||||
// Note: I found files that have nil characters somewhere
|
||||
// in the instrument/sample names and more characters
|
||||
// afterwards. The spec does not mention such a case.
|
||||
// Currently I just discard anything after a nil, but
|
||||
// e.g. VLC seems to interpret a nil as a space. I
|
||||
// don't know what is the proper behaviour.
|
||||
for(unsigned short i = 0; i < instrumentCount; ++ i) {
|
||||
seek(192L + length + ((long)i << 2));
|
||||
READ_U32L_AS(instrumentOffset);
|
||||
seek(instrumentOffset);
|
||||
|
||||
ByteVector instrumentMagic = readBlock(4);
|
||||
READ_ASSERT(instrumentMagic == "IMPI");
|
||||
|
||||
READ_STRING_AS(dosFileName, 13);
|
||||
|
||||
seek(15, Current);
|
||||
|
||||
READ_STRING_AS(instrumentName, 26);
|
||||
comment.append(instrumentName);
|
||||
}
|
||||
|
||||
for(unsigned short i = 0; i < sampleCount; ++ i) {
|
||||
seek(192L + length + ((long)instrumentCount << 2) + ((long)i << 2));
|
||||
READ_U32L_AS(sampleOffset);
|
||||
|
||||
seek(sampleOffset);
|
||||
|
||||
ByteVector sampleMagic = readBlock(4);
|
||||
READ_ASSERT(sampleMagic == "IMPS");
|
||||
|
||||
READ_STRING_AS(dosFileName, 13);
|
||||
READ_BYTE_AS(globalVolume);
|
||||
READ_BYTE_AS(sampleFlags);
|
||||
READ_BYTE_AS(sampleVolume);
|
||||
READ_STRING_AS(sampleName, 26);
|
||||
/*
|
||||
READ_BYTE_AS(sampleCvt);
|
||||
READ_BYTE_AS(samplePanning);
|
||||
READ_U32L_AS(sampleLength);
|
||||
READ_U32L_AS(loopStart);
|
||||
READ_U32L_AS(loopStop);
|
||||
READ_U32L_AS(c5speed);
|
||||
READ_U32L_AS(sustainLoopStart);
|
||||
READ_U32L_AS(sustainLoopEnd);
|
||||
READ_U32L_AS(sampleDataOffset);
|
||||
READ_BYTE_AS(vibratoSpeed);
|
||||
READ_BYTE_AS(vibratoDepth);
|
||||
READ_BYTE_AS(vibratoRate);
|
||||
READ_BYTE_AS(vibratoType);
|
||||
*/
|
||||
|
||||
comment.append(sampleName);
|
||||
}
|
||||
|
||||
if(message.size() > 0)
|
||||
comment.append(message);
|
||||
d->tag.setComment(comment.toString("\n"));
|
||||
d->tag.setTrackerName("Impulse Tracker");
|
||||
}
|
|
@ -1,260 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright :(C) 2011 by Mathias Panzenböck
|
||||
email : grosser.meister.morti@gmx.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include <taglib/it/itproperties.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace IT;
|
||||
|
||||
class IT::Properties::PropertiesPrivate
|
||||
{
|
||||
public:
|
||||
PropertiesPrivate() :
|
||||
channels(0),
|
||||
lengthInPatterns(0),
|
||||
instrumentCount(0),
|
||||
sampleCount(0),
|
||||
patternCount(0),
|
||||
version(0),
|
||||
compatibleVersion(0),
|
||||
flags(0),
|
||||
special(0),
|
||||
globalVolume(0),
|
||||
mixVolume(0),
|
||||
tempo(0),
|
||||
bpmSpeed(0),
|
||||
panningSeparation(0),
|
||||
pitchWheelDepth(0)
|
||||
{
|
||||
}
|
||||
|
||||
int channels;
|
||||
unsigned short lengthInPatterns;
|
||||
unsigned short instrumentCount;
|
||||
unsigned short sampleCount;
|
||||
unsigned short patternCount;
|
||||
unsigned short version;
|
||||
unsigned short compatibleVersion;
|
||||
unsigned short flags;
|
||||
unsigned short special;
|
||||
unsigned char globalVolume;
|
||||
unsigned char mixVolume;
|
||||
unsigned char tempo;
|
||||
unsigned char bpmSpeed;
|
||||
unsigned char panningSeparation;
|
||||
unsigned char pitchWheelDepth;
|
||||
};
|
||||
|
||||
IT::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) :
|
||||
AudioProperties(propertiesStyle),
|
||||
d(new PropertiesPrivate())
|
||||
{
|
||||
}
|
||||
|
||||
IT::Properties::~Properties()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
int IT::Properties::length() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IT::Properties::lengthInSeconds() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IT::Properties::lengthInMilliseconds() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IT::Properties::bitrate() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IT::Properties::sampleRate() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IT::Properties::channels() const
|
||||
{
|
||||
return d->channels;
|
||||
}
|
||||
|
||||
unsigned short IT::Properties::lengthInPatterns() const
|
||||
{
|
||||
return d->lengthInPatterns;
|
||||
}
|
||||
|
||||
bool IT::Properties::stereo() const
|
||||
{
|
||||
return d->flags & Stereo;
|
||||
}
|
||||
|
||||
unsigned short IT::Properties::instrumentCount() const
|
||||
{
|
||||
return d->instrumentCount;
|
||||
}
|
||||
|
||||
unsigned short IT::Properties::sampleCount() const
|
||||
{
|
||||
return d->sampleCount;
|
||||
}
|
||||
|
||||
unsigned short IT::Properties::patternCount() const
|
||||
{
|
||||
return d->patternCount;
|
||||
}
|
||||
|
||||
unsigned short IT::Properties::version() const
|
||||
{
|
||||
return d->version;
|
||||
}
|
||||
|
||||
unsigned short IT::Properties::compatibleVersion() const
|
||||
{
|
||||
return d->compatibleVersion;
|
||||
}
|
||||
|
||||
unsigned short IT::Properties::flags() const
|
||||
{
|
||||
return d->flags;
|
||||
}
|
||||
|
||||
unsigned short IT::Properties::special() const
|
||||
{
|
||||
return d->special;
|
||||
}
|
||||
|
||||
unsigned char IT::Properties::globalVolume() const
|
||||
{
|
||||
return d->globalVolume;
|
||||
}
|
||||
|
||||
unsigned char IT::Properties::mixVolume() const
|
||||
{
|
||||
return d->mixVolume;
|
||||
}
|
||||
|
||||
unsigned char IT::Properties::tempo() const
|
||||
{
|
||||
return d->tempo;
|
||||
}
|
||||
|
||||
unsigned char IT::Properties::bpmSpeed() const
|
||||
{
|
||||
return d->bpmSpeed;
|
||||
}
|
||||
|
||||
unsigned char IT::Properties::panningSeparation() const
|
||||
{
|
||||
return d->panningSeparation;
|
||||
}
|
||||
|
||||
unsigned char IT::Properties::pitchWheelDepth() const
|
||||
{
|
||||
return d->pitchWheelDepth;
|
||||
}
|
||||
|
||||
void IT::Properties::setChannels(int channels)
|
||||
{
|
||||
d->channels = channels;
|
||||
}
|
||||
|
||||
void IT::Properties::setLengthInPatterns(unsigned short lengthInPatterns)
|
||||
{
|
||||
d->lengthInPatterns = lengthInPatterns;
|
||||
}
|
||||
|
||||
void IT::Properties::setInstrumentCount(unsigned short instrumentCount)
|
||||
{
|
||||
d->instrumentCount = instrumentCount;
|
||||
}
|
||||
|
||||
void IT::Properties::setSampleCount(unsigned short sampleCount)
|
||||
{
|
||||
d->sampleCount = sampleCount;
|
||||
}
|
||||
|
||||
void IT::Properties::setPatternCount(unsigned short patternCount)
|
||||
{
|
||||
d->patternCount = patternCount;
|
||||
}
|
||||
|
||||
void IT::Properties::setFlags(unsigned short flags)
|
||||
{
|
||||
d->flags = flags;
|
||||
}
|
||||
|
||||
void IT::Properties::setSpecial(unsigned short special)
|
||||
{
|
||||
d->special = special;
|
||||
}
|
||||
|
||||
void IT::Properties::setCompatibleVersion(unsigned short compatibleVersion)
|
||||
{
|
||||
d->compatibleVersion = compatibleVersion;
|
||||
}
|
||||
|
||||
void IT::Properties::setVersion(unsigned short version)
|
||||
{
|
||||
d->version = version;
|
||||
}
|
||||
|
||||
void IT::Properties::setGlobalVolume(unsigned char globalVolume)
|
||||
{
|
||||
d->globalVolume = globalVolume;
|
||||
}
|
||||
|
||||
void IT::Properties::setMixVolume(unsigned char mixVolume)
|
||||
{
|
||||
d->mixVolume = mixVolume;
|
||||
}
|
||||
|
||||
void IT::Properties::setTempo(unsigned char tempo)
|
||||
{
|
||||
d->tempo = tempo;
|
||||
}
|
||||
|
||||
void IT::Properties::setBpmSpeed(unsigned char bpmSpeed)
|
||||
{
|
||||
d->bpmSpeed = bpmSpeed;
|
||||
}
|
||||
|
||||
void IT::Properties::setPanningSeparation(unsigned char panningSeparation)
|
||||
{
|
||||
d->panningSeparation = panningSeparation;
|
||||
}
|
||||
|
||||
void IT::Properties::setPitchWheelDepth(unsigned char pitchWheelDepth)
|
||||
{
|
||||
d->pitchWheelDepth = pitchWheelDepth;
|
||||
}
|
|
@ -1,192 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2011 by Mathias Panzenböck
|
||||
email : grosser.meister.morti@gmx.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include <taglib/mod/modfile.h>
|
||||
#include <taglib/toolkit/tstringlist.h>
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <taglib/mod/modfileprivate.h>
|
||||
#include <taglib/toolkit/tpropertymap.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace Mod;
|
||||
|
||||
class Mod::File::FilePrivate
|
||||
{
|
||||
public:
|
||||
FilePrivate(AudioProperties::ReadStyle propertiesStyle)
|
||||
: properties(propertiesStyle)
|
||||
{
|
||||
}
|
||||
|
||||
Mod::Tag tag;
|
||||
Mod::Properties properties;
|
||||
};
|
||||
|
||||
Mod::File::File(FileName file, bool readProperties,
|
||||
AudioProperties::ReadStyle propertiesStyle) :
|
||||
Mod::FileBase(file),
|
||||
d(new FilePrivate(propertiesStyle))
|
||||
{
|
||||
if(isOpen())
|
||||
read(readProperties);
|
||||
}
|
||||
|
||||
Mod::File::File(IOStream *stream, bool readProperties,
|
||||
AudioProperties::ReadStyle propertiesStyle) :
|
||||
Mod::FileBase(stream),
|
||||
d(new FilePrivate(propertiesStyle))
|
||||
{
|
||||
if(isOpen())
|
||||
read(readProperties);
|
||||
}
|
||||
|
||||
Mod::File::~File()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
Mod::Tag *Mod::File::tag() const
|
||||
{
|
||||
return &d->tag;
|
||||
}
|
||||
|
||||
Mod::Properties *Mod::File::audioProperties() const
|
||||
{
|
||||
return &d->properties;
|
||||
}
|
||||
|
||||
PropertyMap Mod::File::properties() const
|
||||
{
|
||||
return d->tag.properties();
|
||||
}
|
||||
|
||||
PropertyMap Mod::File::setProperties(const PropertyMap &properties)
|
||||
{
|
||||
return d->tag.setProperties(properties);
|
||||
}
|
||||
|
||||
bool Mod::File::save()
|
||||
{
|
||||
if(readOnly()) {
|
||||
debug("Mod::File::save() - Cannot save to a read only file.");
|
||||
return false;
|
||||
}
|
||||
seek(0);
|
||||
writeString(d->tag.title(), 20);
|
||||
StringList lines = d->tag.comment().split("\n");
|
||||
unsigned int n = std::min(lines.size(), d->properties.instrumentCount());
|
||||
for(unsigned int i = 0; i < n; ++ i) {
|
||||
writeString(lines[i], 22);
|
||||
seek(8, Current);
|
||||
}
|
||||
|
||||
for(unsigned int i = n; i < d->properties.instrumentCount(); ++ i) {
|
||||
writeString(String(), 22);
|
||||
seek(8, Current);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Mod::File::read(bool)
|
||||
{
|
||||
if(!isOpen())
|
||||
return;
|
||||
|
||||
seek(1080);
|
||||
ByteVector modId = readBlock(4);
|
||||
READ_ASSERT(modId.size() == 4);
|
||||
|
||||
int channels = 4;
|
||||
unsigned int instruments = 31;
|
||||
if(modId == "M.K." || modId == "M!K!" || modId == "M&K!" || modId == "N.T.") {
|
||||
d->tag.setTrackerName("ProTracker");
|
||||
channels = 4;
|
||||
}
|
||||
else if(modId.startsWith("FLT") || modId.startsWith("TDZ")) {
|
||||
d->tag.setTrackerName("StarTrekker");
|
||||
char digit = modId[3];
|
||||
READ_ASSERT(digit >= '0' && digit <= '9');
|
||||
channels = digit - '0';
|
||||
}
|
||||
else if(modId.endsWith("CHN")) {
|
||||
d->tag.setTrackerName("StarTrekker");
|
||||
char digit = modId[0];
|
||||
READ_ASSERT(digit >= '0' && digit <= '9');
|
||||
channels = digit - '0';
|
||||
}
|
||||
else if(modId == "CD81" || modId == "OKTA") {
|
||||
d->tag.setTrackerName("Atari Oktalyzer");
|
||||
channels = 8;
|
||||
}
|
||||
else if(modId.endsWith("CH") || modId.endsWith("CN")) {
|
||||
d->tag.setTrackerName("TakeTracker");
|
||||
char digit = modId[0];
|
||||
READ_ASSERT(digit >= '0' && digit <= '9');
|
||||
channels = (digit - '0') * 10;
|
||||
digit = modId[1];
|
||||
READ_ASSERT(digit >= '0' && digit <= '9');
|
||||
channels += digit - '0';
|
||||
}
|
||||
else {
|
||||
// Not sure if this is correct. I'd need a file
|
||||
// created with NoiseTracker to check this.
|
||||
d->tag.setTrackerName("NoiseTracker"); // probably
|
||||
channels = 4;
|
||||
instruments = 15;
|
||||
}
|
||||
d->properties.setChannels(channels);
|
||||
d->properties.setInstrumentCount(instruments);
|
||||
|
||||
seek(0);
|
||||
READ_STRING(d->tag.setTitle, 20);
|
||||
|
||||
StringList comment;
|
||||
for(unsigned int i = 0; i < instruments; ++ i) {
|
||||
READ_STRING_AS(instrumentName, 22);
|
||||
// value in words, * 2 (<< 1) for bytes:
|
||||
READ_U16B_AS(sampleLength);
|
||||
|
||||
READ_BYTE_AS(fineTuneByte);
|
||||
int fineTune = fineTuneByte & 0xF;
|
||||
// > 7 means negative value
|
||||
if(fineTune > 7) fineTune -= 16;
|
||||
|
||||
READ_BYTE_AS(volume);
|
||||
if(volume > 64) volume = 64;
|
||||
// volume in decibels: 20 * log10(volume / 64)
|
||||
|
||||
// value in words, * 2 (<< 1) for bytes:
|
||||
READ_U16B_AS(repeatStart);
|
||||
// value in words, * 2 (<< 1) for bytes:
|
||||
READ_U16B_AS(repatLength);
|
||||
|
||||
comment.append(instrumentName);
|
||||
}
|
||||
|
||||
READ_BYTE(d->properties.setLengthInPatterns);
|
||||
|
||||
d->tag.setComment(comment.toString("\n"));
|
||||
}
|
|
@ -1,125 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2011 by Mathias Panzenböck
|
||||
email : grosser.meister.morti@gmx.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <taglib/mod/modfilebase.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace Mod;
|
||||
|
||||
Mod::FileBase::FileBase(FileName file) : TagLib::File(file)
|
||||
{
|
||||
}
|
||||
|
||||
Mod::FileBase::FileBase(IOStream *stream) : TagLib::File(stream)
|
||||
{
|
||||
}
|
||||
|
||||
void Mod::FileBase::writeString(const String &s, unsigned long size, char padding)
|
||||
{
|
||||
ByteVector data(s.data(String::Latin1));
|
||||
data.resize(size, padding);
|
||||
writeBlock(data);
|
||||
}
|
||||
|
||||
bool Mod::FileBase::readString(String &s, unsigned long size)
|
||||
{
|
||||
ByteVector data(readBlock(size));
|
||||
if(data.size() < size) return false;
|
||||
int index = data.find((char) 0);
|
||||
if(index > -1)
|
||||
{
|
||||
data.resize(index);
|
||||
}
|
||||
data.replace('\xff', ' ');
|
||||
|
||||
s = data;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Mod::FileBase::writeByte(unsigned char byte)
|
||||
{
|
||||
ByteVector data(1, byte);
|
||||
writeBlock(data);
|
||||
}
|
||||
|
||||
void Mod::FileBase::writeU16L(unsigned short number)
|
||||
{
|
||||
writeBlock(ByteVector::fromShort(number, false));
|
||||
}
|
||||
|
||||
void Mod::FileBase::writeU32L(unsigned long number)
|
||||
{
|
||||
writeBlock(ByteVector::fromUInt(number, false));
|
||||
}
|
||||
|
||||
void Mod::FileBase::writeU16B(unsigned short number)
|
||||
{
|
||||
writeBlock(ByteVector::fromShort(number, true));
|
||||
}
|
||||
|
||||
void Mod::FileBase::writeU32B(unsigned long number)
|
||||
{
|
||||
writeBlock(ByteVector::fromUInt(number, true));
|
||||
}
|
||||
|
||||
bool Mod::FileBase::readByte(unsigned char &byte)
|
||||
{
|
||||
ByteVector data(readBlock(1));
|
||||
if(data.size() < 1) return false;
|
||||
byte = data[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Mod::FileBase::readU16L(unsigned short &number)
|
||||
{
|
||||
ByteVector data(readBlock(2));
|
||||
if(data.size() < 2) return false;
|
||||
number = data.toUShort(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Mod::FileBase::readU32L(unsigned long &number) {
|
||||
ByteVector data(readBlock(4));
|
||||
if(data.size() < 4) return false;
|
||||
number = data.toUInt(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Mod::FileBase::readU16B(unsigned short &number)
|
||||
{
|
||||
ByteVector data(readBlock(2));
|
||||
if(data.size() < 2) return false;
|
||||
number = data.toUShort(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Mod::FileBase::readU32B(unsigned long &number) {
|
||||
ByteVector data(readBlock(4));
|
||||
if(data.size() < 4) return false;
|
||||
number = data.toUInt(true);
|
||||
return true;
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2011 by Mathias Panzenböck
|
||||
email : grosser.meister.morti@gmx.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
|
||||
* MA 02110-1301 USA *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_MODFILEPRIVATE_H
|
||||
#define TAGLIB_MODFILEPRIVATE_H
|
||||
|
||||
// some helper-macros only used internally by (s3m|it|xm)file.cpp
|
||||
#define READ_ASSERT(cond) \
|
||||
if(!(cond)) \
|
||||
{ \
|
||||
setValid(false); \
|
||||
return; \
|
||||
}
|
||||
|
||||
#define READ(setter,type,read) \
|
||||
{ \
|
||||
type number; \
|
||||
READ_ASSERT(read(number)); \
|
||||
setter(number); \
|
||||
}
|
||||
|
||||
#define READ_BYTE(setter) READ(setter,unsigned char,readByte)
|
||||
#define READ_U16L(setter) READ(setter,unsigned short,readU16L)
|
||||
#define READ_U32L(setter) READ(setter,unsigned long,readU32L)
|
||||
#define READ_U16B(setter) READ(setter,unsigned short,readU16B)
|
||||
#define READ_U32B(setter) READ(setter,unsigned long,readU32B)
|
||||
|
||||
#define READ_STRING(setter,size) \
|
||||
{ \
|
||||
String s; \
|
||||
READ_ASSERT(readString(s, size)); \
|
||||
setter(s); \
|
||||
}
|
||||
|
||||
#define READ_AS(type,name,read) \
|
||||
type name = 0; \
|
||||
READ_ASSERT(read(name));
|
||||
|
||||
#define READ_BYTE_AS(name) READ_AS(unsigned char,name,readByte)
|
||||
#define READ_U16L_AS(name) READ_AS(unsigned short,name,readU16L)
|
||||
#define READ_U32L_AS(name) READ_AS(unsigned long,name,readU32L)
|
||||
#define READ_U16B_AS(name) READ_AS(unsigned short,name,readU16B)
|
||||
#define READ_U32B_AS(name) READ_AS(unsigned long,name,readU32B)
|
||||
|
||||
#define READ_STRING_AS(name,size) \
|
||||
String name; \
|
||||
READ_ASSERT(readString(name, size));
|
||||
|
||||
#endif
|
|
@ -1,111 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2011 by Mathias Panzenböck
|
||||
email : grosser.meister.morti@gmx.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include <taglib/mod/modproperties.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace Mod;
|
||||
|
||||
class Mod::Properties::PropertiesPrivate
|
||||
{
|
||||
public:
|
||||
PropertiesPrivate() :
|
||||
channels(0),
|
||||
instrumentCount(0),
|
||||
lengthInPatterns(0)
|
||||
{
|
||||
}
|
||||
|
||||
int channels;
|
||||
unsigned int instrumentCount;
|
||||
unsigned char lengthInPatterns;
|
||||
};
|
||||
|
||||
Mod::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) :
|
||||
AudioProperties(propertiesStyle),
|
||||
d(new PropertiesPrivate())
|
||||
{
|
||||
}
|
||||
|
||||
Mod::Properties::~Properties()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
int Mod::Properties::length() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Mod::Properties::lengthInSeconds() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Mod::Properties::lengthInMilliseconds() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Mod::Properties::bitrate() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Mod::Properties::sampleRate() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Mod::Properties::channels() const
|
||||
{
|
||||
return d->channels;
|
||||
}
|
||||
|
||||
unsigned int Mod::Properties::instrumentCount() const
|
||||
{
|
||||
return d->instrumentCount;
|
||||
}
|
||||
|
||||
unsigned char Mod::Properties::lengthInPatterns() const
|
||||
{
|
||||
return d->lengthInPatterns;
|
||||
}
|
||||
|
||||
void Mod::Properties::setChannels(int channels)
|
||||
{
|
||||
d->channels = channels;
|
||||
}
|
||||
|
||||
void Mod::Properties::setInstrumentCount(unsigned int instrumentCount)
|
||||
{
|
||||
d->instrumentCount = instrumentCount;
|
||||
}
|
||||
|
||||
void Mod::Properties::setLengthInPatterns(unsigned char lengthInPatterns)
|
||||
{
|
||||
d->lengthInPatterns = lengthInPatterns;
|
||||
}
|
|
@ -1,260 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2011 by Mathias Panzenböck
|
||||
email : grosser.meister.morti@gmx.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include <taglib/mod/modtag.h>
|
||||
#include <taglib/toolkit/tstringlist.h>
|
||||
#include <taglib/toolkit/tpropertymap.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace Mod;
|
||||
|
||||
class Mod::Tag::TagPrivate
|
||||
{
|
||||
public:
|
||||
TagPrivate()
|
||||
{
|
||||
}
|
||||
|
||||
String title;
|
||||
String comment;
|
||||
String trackerName;
|
||||
};
|
||||
|
||||
Mod::Tag::Tag() :
|
||||
TagLib::Tag(),
|
||||
d(new TagPrivate())
|
||||
{
|
||||
}
|
||||
|
||||
Mod::Tag::~Tag()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String Mod::Tag::title() const
|
||||
{
|
||||
return d->title;
|
||||
}
|
||||
|
||||
String Mod::Tag::albumartist() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
String Mod::Tag::artist() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
String Mod::Tag::composer() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
String Mod::Tag::album() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
String Mod::Tag::unsyncedlyrics() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
String Mod::Tag::comment() const
|
||||
{
|
||||
return d->comment;
|
||||
}
|
||||
|
||||
String Mod::Tag::genre() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
unsigned int Mod::Tag::year() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int Mod::Tag::track() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int Mod::Tag::disc() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
String Mod::Tag::cuesheet() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
float Mod::Tag::rgAlbumGain() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float Mod::Tag::rgAlbumPeak() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float Mod::Tag::rgTrackGain() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float Mod::Tag::rgTrackPeak() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
String Mod::Tag::soundcheck() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
String Mod::Tag::trackerName() const
|
||||
{
|
||||
return d->trackerName;
|
||||
}
|
||||
|
||||
void Mod::Tag::setTitle(const String &title)
|
||||
{
|
||||
d->title = title;
|
||||
}
|
||||
|
||||
void Mod::Tag::setAlbumArtist(const String &)
|
||||
{
|
||||
}
|
||||
|
||||
void Mod::Tag::setArtist(const String &)
|
||||
{
|
||||
}
|
||||
|
||||
void Mod::Tag::setComposer(const String &)
|
||||
{
|
||||
}
|
||||
|
||||
void Mod::Tag::setAlbum(const String &)
|
||||
{
|
||||
}
|
||||
|
||||
void Mod::Tag::setUnsyncedlyrics(const String &)
|
||||
{
|
||||
}
|
||||
|
||||
void Mod::Tag::setComment(const String &comment)
|
||||
{
|
||||
d->comment = comment;
|
||||
}
|
||||
|
||||
void Mod::Tag::setGenre(const String &)
|
||||
{
|
||||
}
|
||||
|
||||
void Mod::Tag::setYear(unsigned int)
|
||||
{
|
||||
}
|
||||
|
||||
void Mod::Tag::setTrack(unsigned int)
|
||||
{
|
||||
}
|
||||
|
||||
void Mod::Tag::setDisc(unsigned int)
|
||||
{
|
||||
}
|
||||
|
||||
void Mod::Tag::setCuesheet(const String &)
|
||||
{
|
||||
}
|
||||
|
||||
void Mod::Tag::setRGAlbumGain(float)
|
||||
{
|
||||
}
|
||||
|
||||
void Mod::Tag::setRGAlbumPeak(float)
|
||||
{
|
||||
}
|
||||
|
||||
void Mod::Tag::setRGTrackGain(float)
|
||||
{
|
||||
}
|
||||
|
||||
void Mod::Tag::setRGTrackPeak(float)
|
||||
{
|
||||
}
|
||||
|
||||
void Mod::Tag::setTrackerName(const String &trackerName)
|
||||
{
|
||||
d->trackerName = trackerName;
|
||||
}
|
||||
|
||||
PropertyMap Mod::Tag::properties() const
|
||||
{
|
||||
PropertyMap properties;
|
||||
properties["TITLE"] = d->title;
|
||||
properties["COMMENT"] = d->comment;
|
||||
if(!(d->trackerName.isEmpty()))
|
||||
properties["TRACKERNAME"] = d->trackerName;
|
||||
return properties;
|
||||
}
|
||||
|
||||
PropertyMap Mod::Tag::setProperties(const PropertyMap &origProps)
|
||||
{
|
||||
PropertyMap properties(origProps);
|
||||
properties.removeEmpty();
|
||||
StringList oneValueSet;
|
||||
if(properties.contains("TITLE")) {
|
||||
d->title = properties["TITLE"].front();
|
||||
oneValueSet.append("TITLE");
|
||||
} else
|
||||
d->title.clear();
|
||||
|
||||
if(properties.contains("COMMENT")) {
|
||||
d->comment = properties["COMMENT"].front();
|
||||
oneValueSet.append("COMMENT");
|
||||
} else
|
||||
d->comment.clear();
|
||||
|
||||
if(properties.contains("TRACKERNAME")) {
|
||||
d->trackerName = properties["TRACKERNAME"].front();
|
||||
oneValueSet.append("TRACKERNAME");
|
||||
} else
|
||||
d->trackerName.clear();
|
||||
|
||||
// for each tag that has been set above, remove the first entry in the corresponding
|
||||
// value list. The others will be returned as unsupported by this format.
|
||||
for(StringList::ConstIterator it = oneValueSet.begin(); it != oneValueSet.end(); ++it) {
|
||||
if(properties[*it].size() == 1)
|
||||
properties.erase(*it);
|
||||
else
|
||||
properties[*it].erase( properties[*it].begin() );
|
||||
}
|
||||
return properties;
|
||||
}
|
|
@ -1,197 +0,0 @@
|
|||
/**************************************************************************
|
||||
copyright : (C) 2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <climits>
|
||||
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <taglib/toolkit/tstring.h>
|
||||
#include <taglib/mp4/mp4atom.h>
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
const char *MP4::Atom::containers[11] = {
|
||||
"moov", "udta", "mdia", "meta", "ilst",
|
||||
"stbl", "minf", "moof", "traf", "trak",
|
||||
"stsd"
|
||||
};
|
||||
|
||||
MP4::Atom::Atom(File *file)
|
||||
{
|
||||
children.setAutoDelete(true);
|
||||
|
||||
offset = file->tell();
|
||||
ByteVector header = file->readBlock(8);
|
||||
if(header.size() != 8) {
|
||||
// The atom header must be 8 bytes long, otherwise there is either
|
||||
// trailing garbage or the file is truncated
|
||||
debug("MP4: Couldn't read 8 bytes of data for atom header");
|
||||
length = 0;
|
||||
file->seek(0, File::End);
|
||||
return;
|
||||
}
|
||||
|
||||
length = header.toUInt();
|
||||
|
||||
if(length == 0) {
|
||||
// The last atom which extends to the end of the file.
|
||||
length = file->length() - offset;
|
||||
}
|
||||
else if(length == 1) {
|
||||
// The atom has a 64-bit length.
|
||||
const long long longLength = file->readBlock(8).toLongLong();
|
||||
if(longLength <= LONG_MAX) {
|
||||
// The actual length fits in long. That's always the case if long is 64-bit.
|
||||
length = static_cast<long>(longLength);
|
||||
}
|
||||
else {
|
||||
debug("MP4: 64-bit atoms are not supported");
|
||||
length = 0;
|
||||
file->seek(0, File::End);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(length < 8) {
|
||||
debug("MP4: Invalid atom size");
|
||||
length = 0;
|
||||
file->seek(0, File::End);
|
||||
return;
|
||||
}
|
||||
|
||||
name = header.mid(4, 4);
|
||||
|
||||
for(int i = 0; i < numContainers; i++) {
|
||||
if(name == containers[i]) {
|
||||
if(name == "meta") {
|
||||
file->seek(4, File::Current);
|
||||
}
|
||||
else if(name == "stsd") {
|
||||
file->seek(8, File::Current);
|
||||
}
|
||||
while(file->tell() < offset + length) {
|
||||
MP4::Atom *child = new MP4::Atom(file);
|
||||
children.append(child);
|
||||
if(child->length == 0)
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
file->seek(offset + length);
|
||||
}
|
||||
|
||||
MP4::Atom::~Atom()
|
||||
{
|
||||
}
|
||||
|
||||
MP4::Atom *
|
||||
MP4::Atom::find(const char *name1, const char *name2, const char *name3, const char *name4)
|
||||
{
|
||||
if(name1 == 0) {
|
||||
return this;
|
||||
}
|
||||
for(AtomList::ConstIterator it = children.begin(); it != children.end(); ++it) {
|
||||
if((*it)->name == name1) {
|
||||
return (*it)->find(name2, name3, name4);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MP4::AtomList
|
||||
MP4::Atom::findall(const char *name, bool recursive)
|
||||
{
|
||||
MP4::AtomList result;
|
||||
for(AtomList::ConstIterator it = children.begin(); it != children.end(); ++it) {
|
||||
if((*it)->name == name) {
|
||||
result.append(*it);
|
||||
}
|
||||
if(recursive) {
|
||||
result.append((*it)->findall(name, recursive));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
MP4::Atom::path(MP4::AtomList &path, const char *name1, const char *name2, const char *name3)
|
||||
{
|
||||
path.append(this);
|
||||
if(name1 == 0) {
|
||||
return true;
|
||||
}
|
||||
for(AtomList::ConstIterator it = children.begin(); it != children.end(); ++it) {
|
||||
if((*it)->name == name1) {
|
||||
return (*it)->path(path, name2, name3);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
MP4::Atoms::Atoms(File *file)
|
||||
{
|
||||
atoms.setAutoDelete(true);
|
||||
|
||||
file->seek(0, File::End);
|
||||
long end = file->tell();
|
||||
file->seek(0);
|
||||
while(file->tell() + 8 <= end) {
|
||||
MP4::Atom *atom = new MP4::Atom(file);
|
||||
atoms.append(atom);
|
||||
if (atom->length == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MP4::Atoms::~Atoms()
|
||||
{
|
||||
}
|
||||
|
||||
MP4::Atom *
|
||||
MP4::Atoms::find(const char *name1, const char *name2, const char *name3, const char *name4)
|
||||
{
|
||||
for(AtomList::ConstIterator it = atoms.begin(); it != atoms.end(); ++it) {
|
||||
if((*it)->name == name1) {
|
||||
return (*it)->find(name2, name3, name4);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MP4::AtomList
|
||||
MP4::Atoms::path(const char *name1, const char *name2, const char *name3, const char *name4)
|
||||
{
|
||||
MP4::AtomList path;
|
||||
for(AtomList::ConstIterator it = atoms.begin(); it != atoms.end(); ++it) {
|
||||
if((*it)->name == name1) {
|
||||
if(!(*it)->path(path, name2, name3, name4)) {
|
||||
path.clear();
|
||||
}
|
||||
return path;
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
|
@ -1,182 +0,0 @@
|
|||
/**************************************************************************
|
||||
copyright : (C) 2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <taglib/toolkit/tstring.h>
|
||||
#include <taglib/toolkit/tpropertymap.h>
|
||||
#include <taglib/tagutils.h>
|
||||
|
||||
#include <taglib/mp4/mp4atom.h>
|
||||
#include <taglib/mp4/mp4tag.h>
|
||||
#include <taglib/mp4/mp4file.h>
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
namespace
|
||||
{
|
||||
bool checkValid(const MP4::AtomList &list)
|
||||
{
|
||||
for(MP4::AtomList::ConstIterator it = list.begin(); it != list.end(); ++it) {
|
||||
|
||||
if((*it)->length == 0)
|
||||
return false;
|
||||
|
||||
if(!checkValid((*it)->children))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class MP4::File::FilePrivate
|
||||
{
|
||||
public:
|
||||
FilePrivate() :
|
||||
tag(0),
|
||||
atoms(0),
|
||||
properties(0) {}
|
||||
|
||||
~FilePrivate()
|
||||
{
|
||||
delete atoms;
|
||||
delete tag;
|
||||
delete properties;
|
||||
}
|
||||
|
||||
MP4::Tag *tag;
|
||||
MP4::Atoms *atoms;
|
||||
MP4::Properties *properties;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// static members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool MP4::File::isSupported(IOStream *stream)
|
||||
{
|
||||
// An MP4 file has to have an "ftyp" box first.
|
||||
|
||||
const ByteVector id = Utils::readHeader(stream, 8, false);
|
||||
return id.containsAt("ftyp", 4);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MP4::File::File(FileName file, bool readProperties, AudioProperties::ReadStyle) :
|
||||
TagLib::File(file),
|
||||
d(new FilePrivate())
|
||||
{
|
||||
if(isOpen())
|
||||
read(readProperties);
|
||||
}
|
||||
|
||||
MP4::File::File(IOStream *stream, bool readProperties, AudioProperties::ReadStyle) :
|
||||
TagLib::File(stream),
|
||||
d(new FilePrivate())
|
||||
{
|
||||
if(isOpen())
|
||||
read(readProperties);
|
||||
}
|
||||
|
||||
MP4::File::~File()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
MP4::Tag *
|
||||
MP4::File::tag() const
|
||||
{
|
||||
return d->tag;
|
||||
}
|
||||
|
||||
PropertyMap MP4::File::properties() const
|
||||
{
|
||||
return d->tag->properties();
|
||||
}
|
||||
|
||||
void MP4::File::removeUnsupportedProperties(const StringList &properties)
|
||||
{
|
||||
d->tag->removeUnsupportedProperties(properties);
|
||||
}
|
||||
|
||||
PropertyMap MP4::File::setProperties(const PropertyMap &properties)
|
||||
{
|
||||
return d->tag->setProperties(properties);
|
||||
}
|
||||
|
||||
MP4::Properties *
|
||||
MP4::File::audioProperties() const
|
||||
{
|
||||
return d->properties;
|
||||
}
|
||||
|
||||
void
|
||||
MP4::File::read(bool readProperties)
|
||||
{
|
||||
if(!isValid())
|
||||
return;
|
||||
|
||||
d->atoms = new Atoms(this);
|
||||
if(!checkValid(d->atoms->atoms)) {
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// must have a moov atom, otherwise consider it invalid
|
||||
if(!d->atoms->find("moov")) {
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
d->tag = new Tag(this, d->atoms);
|
||||
if(readProperties) {
|
||||
d->properties = new Properties(this, d->atoms);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
MP4::File::save()
|
||||
{
|
||||
if(readOnly()) {
|
||||
debug("MP4::File::save() -- File is read only.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!isValid()) {
|
||||
debug("MP4::File::save() -- Trying to save invalid file.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return d->tag->save();
|
||||
}
|
||||
|
||||
bool
|
||||
MP4::File::hasMP4Tag() const
|
||||
{
|
||||
return (d->atoms->find("moov", "udta", "meta", "ilst") != 0);
|
||||
}
|
|
@ -1,212 +0,0 @@
|
|||
/**************************************************************************
|
||||
copyright : (C) 2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/toolkit/taglib.h>
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <taglib/toolkit/trefcounter.h>
|
||||
#include <taglib/mp4/mp4item.h>
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class MP4::Item::ItemPrivate : public RefCounter
|
||||
{
|
||||
public:
|
||||
ItemPrivate() :
|
||||
RefCounter(),
|
||||
valid(true),
|
||||
atomDataType(TypeUndefined) {}
|
||||
|
||||
bool valid;
|
||||
AtomDataType atomDataType;
|
||||
union {
|
||||
bool m_bool;
|
||||
int m_int;
|
||||
IntPair m_intPair;
|
||||
unsigned char m_byte;
|
||||
unsigned int m_uint;
|
||||
long long m_longlong;
|
||||
};
|
||||
StringList m_stringList;
|
||||
ByteVectorList m_byteVectorList;
|
||||
MP4::CoverArtList m_coverArtList;
|
||||
};
|
||||
|
||||
MP4::Item::Item() :
|
||||
d(new ItemPrivate())
|
||||
{
|
||||
d->valid = false;
|
||||
}
|
||||
|
||||
MP4::Item::Item(const Item &item) :
|
||||
d(item.d)
|
||||
{
|
||||
d->ref();
|
||||
}
|
||||
|
||||
MP4::Item &
|
||||
MP4::Item::operator=(const Item &item)
|
||||
{
|
||||
Item(item).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Item::swap(Item &item)
|
||||
{
|
||||
using std::swap;
|
||||
|
||||
swap(d, item.d);
|
||||
}
|
||||
|
||||
MP4::Item::~Item()
|
||||
{
|
||||
if(d->deref())
|
||||
delete d;
|
||||
}
|
||||
|
||||
MP4::Item::Item(bool value) :
|
||||
d(new ItemPrivate())
|
||||
{
|
||||
d->m_bool = value;
|
||||
}
|
||||
|
||||
MP4::Item::Item(int value) :
|
||||
d(new ItemPrivate())
|
||||
{
|
||||
d->m_int = value;
|
||||
}
|
||||
|
||||
MP4::Item::Item(unsigned char value) :
|
||||
d(new ItemPrivate())
|
||||
{
|
||||
d->m_byte = value;
|
||||
}
|
||||
|
||||
MP4::Item::Item(unsigned int value) :
|
||||
d(new ItemPrivate())
|
||||
{
|
||||
d->m_uint = value;
|
||||
}
|
||||
|
||||
MP4::Item::Item(long long value) :
|
||||
d(new ItemPrivate())
|
||||
{
|
||||
d->m_longlong = value;
|
||||
}
|
||||
|
||||
MP4::Item::Item(int value1, int value2) :
|
||||
d(new ItemPrivate())
|
||||
{
|
||||
d->m_intPair.first = value1;
|
||||
d->m_intPair.second = value2;
|
||||
}
|
||||
|
||||
MP4::Item::Item(const ByteVectorList &value) :
|
||||
d(new ItemPrivate())
|
||||
{
|
||||
d->m_byteVectorList = value;
|
||||
}
|
||||
|
||||
MP4::Item::Item(const StringList &value) :
|
||||
d(new ItemPrivate())
|
||||
{
|
||||
d->m_stringList = value;
|
||||
}
|
||||
|
||||
MP4::Item::Item(const MP4::CoverArtList &value) :
|
||||
d(new ItemPrivate())
|
||||
{
|
||||
d->m_coverArtList = value;
|
||||
}
|
||||
|
||||
void MP4::Item::setAtomDataType(MP4::AtomDataType type)
|
||||
{
|
||||
d->atomDataType = type;
|
||||
}
|
||||
|
||||
MP4::AtomDataType MP4::Item::atomDataType() const
|
||||
{
|
||||
return d->atomDataType;
|
||||
}
|
||||
|
||||
bool
|
||||
MP4::Item::toBool() const
|
||||
{
|
||||
return d->m_bool;
|
||||
}
|
||||
|
||||
int
|
||||
MP4::Item::toInt() const
|
||||
{
|
||||
return d->m_int;
|
||||
}
|
||||
|
||||
unsigned char
|
||||
MP4::Item::toByte() const
|
||||
{
|
||||
return d->m_byte;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
MP4::Item::toUInt() const
|
||||
{
|
||||
return d->m_uint;
|
||||
}
|
||||
|
||||
long long
|
||||
MP4::Item::toLongLong() const
|
||||
{
|
||||
return d->m_longlong;
|
||||
}
|
||||
|
||||
MP4::Item::IntPair
|
||||
MP4::Item::toIntPair() const
|
||||
{
|
||||
return d->m_intPair;
|
||||
}
|
||||
|
||||
StringList
|
||||
MP4::Item::toStringList() const
|
||||
{
|
||||
return d->m_stringList;
|
||||
}
|
||||
|
||||
ByteVectorList
|
||||
MP4::Item::toByteVectorList() const
|
||||
{
|
||||
return d->m_byteVectorList;
|
||||
}
|
||||
|
||||
MP4::CoverArtList
|
||||
MP4::Item::toCoverArtList() const
|
||||
{
|
||||
return d->m_coverArtList;
|
||||
}
|
||||
|
||||
bool
|
||||
MP4::Item::isValid() const
|
||||
{
|
||||
return d->valid;
|
||||
}
|
|
@ -1,269 +0,0 @@
|
|||
/**************************************************************************
|
||||
copyright : (C) 2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <taglib/toolkit/tstring.h>
|
||||
#include <taglib/mp4/mp4file.h>
|
||||
#include <taglib/mp4/mp4atom.h>
|
||||
#include <taglib/mp4/mp4properties.h>
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
namespace
|
||||
{
|
||||
// Calculate the total bytes used by audio data, used to calculate the bitrate
|
||||
long long calculateMdatLength(const MP4::AtomList &list)
|
||||
{
|
||||
long long totalLength = 0;
|
||||
for(MP4::AtomList::ConstIterator it = list.begin(); it != list.end(); ++it) {
|
||||
long length = (*it)->length;
|
||||
if(length == 0)
|
||||
return 0; // for safety, see checkValid() in mp4file.cpp
|
||||
|
||||
if((*it)->name == "mdat")
|
||||
totalLength += length;
|
||||
|
||||
totalLength += calculateMdatLength((*it)->children);
|
||||
}
|
||||
|
||||
return totalLength;
|
||||
}
|
||||
}
|
||||
|
||||
class MP4::Properties::PropertiesPrivate
|
||||
{
|
||||
public:
|
||||
PropertiesPrivate() :
|
||||
length(0),
|
||||
bitrate(0),
|
||||
sampleRate(0),
|
||||
channels(0),
|
||||
bitsPerSample(0),
|
||||
encrypted(false),
|
||||
codec(MP4::Properties::Unknown) {}
|
||||
|
||||
int length;
|
||||
int bitrate;
|
||||
int sampleRate;
|
||||
int channels;
|
||||
int bitsPerSample;
|
||||
bool encrypted;
|
||||
Codec codec;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MP4::Properties::Properties(File *file, MP4::Atoms *atoms, ReadStyle style) :
|
||||
AudioProperties(style),
|
||||
d(new PropertiesPrivate())
|
||||
{
|
||||
read(file, atoms);
|
||||
}
|
||||
|
||||
MP4::Properties::~Properties()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
int
|
||||
MP4::Properties::channels() const
|
||||
{
|
||||
return d->channels;
|
||||
}
|
||||
|
||||
int
|
||||
MP4::Properties::sampleRate() const
|
||||
{
|
||||
return d->sampleRate;
|
||||
}
|
||||
|
||||
int
|
||||
MP4::Properties::length() const
|
||||
{
|
||||
return lengthInSeconds();
|
||||
}
|
||||
|
||||
int
|
||||
MP4::Properties::lengthInSeconds() const
|
||||
{
|
||||
return d->length / 1000;
|
||||
}
|
||||
|
||||
int
|
||||
MP4::Properties::lengthInMilliseconds() const
|
||||
{
|
||||
return d->length;
|
||||
}
|
||||
|
||||
int
|
||||
MP4::Properties::bitrate() const
|
||||
{
|
||||
return d->bitrate;
|
||||
}
|
||||
|
||||
int
|
||||
MP4::Properties::bitsPerSample() const
|
||||
{
|
||||
return d->bitsPerSample;
|
||||
}
|
||||
|
||||
bool
|
||||
MP4::Properties::isEncrypted() const
|
||||
{
|
||||
return d->encrypted;
|
||||
}
|
||||
|
||||
MP4::Properties::Codec
|
||||
MP4::Properties::codec() const
|
||||
{
|
||||
return d->codec;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
MP4::Properties::read(File *file, Atoms *atoms)
|
||||
{
|
||||
MP4::Atom *moov = atoms->find("moov");
|
||||
if(!moov) {
|
||||
debug("MP4: Atom 'moov' not found");
|
||||
return;
|
||||
}
|
||||
|
||||
MP4::Atom *trak = 0;
|
||||
ByteVector data;
|
||||
|
||||
const MP4::AtomList trakList = moov->findall("trak");
|
||||
for(MP4::AtomList::ConstIterator it = trakList.begin(); it != trakList.end(); ++it) {
|
||||
trak = *it;
|
||||
MP4::Atom *hdlr = trak->find("mdia", "hdlr");
|
||||
if(!hdlr) {
|
||||
debug("MP4: Atom 'trak.mdia.hdlr' not found");
|
||||
return;
|
||||
}
|
||||
file->seek(hdlr->offset);
|
||||
data = file->readBlock(hdlr->length);
|
||||
if(data.containsAt("soun", 16)) {
|
||||
break;
|
||||
}
|
||||
trak = 0;
|
||||
}
|
||||
if(!trak) {
|
||||
debug("MP4: No audio tracks");
|
||||
return;
|
||||
}
|
||||
|
||||
MP4::Atom *mdhd = trak->find("mdia", "mdhd");
|
||||
if(!mdhd) {
|
||||
debug("MP4: Atom 'trak.mdia.mdhd' not found");
|
||||
return;
|
||||
}
|
||||
|
||||
file->seek(mdhd->offset);
|
||||
data = file->readBlock(mdhd->length);
|
||||
|
||||
const unsigned int version = data[8];
|
||||
long long unit;
|
||||
long long length;
|
||||
if(version == 1) {
|
||||
if(data.size() < 36 + 8) {
|
||||
debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected");
|
||||
return;
|
||||
}
|
||||
unit = data.toUInt(28U);
|
||||
length = data.toLongLong(32U);
|
||||
}
|
||||
else {
|
||||
if(data.size() < 24 + 8) {
|
||||
debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected");
|
||||
return;
|
||||
}
|
||||
unit = data.toUInt(20U);
|
||||
length = data.toUInt(24U);
|
||||
}
|
||||
if(unit > 0 && length > 0)
|
||||
d->length = static_cast<int>(length * 1000.0 / unit + 0.5);
|
||||
|
||||
MP4::Atom *atom = trak->find("mdia", "minf", "stbl", "stsd");
|
||||
if(!atom) {
|
||||
return;
|
||||
}
|
||||
|
||||
file->seek(atom->offset);
|
||||
data = file->readBlock(atom->length);
|
||||
if(data.containsAt("mp4a", 20)) {
|
||||
d->codec = AAC;
|
||||
d->channels = data.toShort(40U);
|
||||
d->bitsPerSample = data.toShort(42U);
|
||||
d->sampleRate = data.toUInt(46U);
|
||||
if(data.containsAt("esds", 56) && data[64] == 0x03) {
|
||||
unsigned int pos = 65;
|
||||
if(data.containsAt("\x80\x80\x80", pos)) {
|
||||
pos += 3;
|
||||
}
|
||||
pos += 4;
|
||||
if(data[pos] == 0x04) {
|
||||
pos += 1;
|
||||
if(data.containsAt("\x80\x80\x80", pos)) {
|
||||
pos += 3;
|
||||
}
|
||||
pos += 10;
|
||||
const unsigned int bitrateValue = data.toUInt(pos);
|
||||
if(bitrateValue != 0 || d->length <= 0) {
|
||||
d->bitrate = static_cast<int>((bitrateValue + 500) / 1000.0 + 0.5);
|
||||
}
|
||||
else {
|
||||
d->bitrate = static_cast<int>(
|
||||
(calculateMdatLength(atoms->atoms) * 8) / d->length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(data.containsAt("alac", 20)) {
|
||||
if(atom->length == 88 && data.containsAt("alac", 56)) {
|
||||
d->codec = ALAC;
|
||||
d->bitsPerSample = data.at(69);
|
||||
d->channels = data.at(73);
|
||||
d->bitrate = static_cast<int>(data.toUInt(80U) / 1000.0 + 0.5);
|
||||
d->sampleRate = data.toUInt(84U);
|
||||
|
||||
if(d->bitrate == 0 && d->length > 0) {
|
||||
// There are files which do not contain a nominal bitrate, e.g. those
|
||||
// generated by refalac64.exe. Calculate the bitrate from the audio
|
||||
// data size (mdat atoms) and the duration.
|
||||
d->bitrate = (calculateMdatLength(atoms->atoms) * 8) / d->length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MP4::Atom *drms = atom->find("drms");
|
||||
if(drms) {
|
||||
d->encrypted = true;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,179 +0,0 @@
|
|||
/**************************************************************************
|
||||
copyright : (C) 2007,2011 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_MP4TAG_H
|
||||
#define TAGLIB_MP4TAG_H
|
||||
|
||||
#include <taglib/tag.h>
|
||||
#include <taglib/toolkit/tbytevectorlist.h>
|
||||
#include <taglib/toolkit/tfile.h>
|
||||
#include <taglib/toolkit/tmap.h>
|
||||
#include <taglib/toolkit/tstringlist.h>
|
||||
#include <taglib/taglib_export.h>
|
||||
#include <taglib/mp4/mp4atom.h>
|
||||
#include <taglib/mp4/mp4item.h>
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace MP4 {
|
||||
|
||||
/*!
|
||||
* \deprecated
|
||||
*/
|
||||
TAGLIB_DEPRECATED typedef TagLib::Map<String, Item> ItemListMap;
|
||||
typedef TagLib::Map<String, Item> ItemMap;
|
||||
|
||||
class TAGLIB_EXPORT Tag: public TagLib::Tag
|
||||
{
|
||||
public:
|
||||
Tag();
|
||||
Tag(TagLib::File *file, Atoms *atoms);
|
||||
virtual ~Tag();
|
||||
bool save();
|
||||
|
||||
virtual String title() const;
|
||||
virtual String albumartist() const;
|
||||
virtual String artist() const;
|
||||
virtual String album() const;
|
||||
virtual String comment() const;
|
||||
virtual String genre() const;
|
||||
virtual unsigned int year() const;
|
||||
virtual unsigned int track() const;
|
||||
virtual unsigned int disc() const;
|
||||
virtual String cuesheet() const;
|
||||
virtual float rgAlbumGain() const;
|
||||
virtual float rgAlbumPeak() const;
|
||||
virtual float rgTrackGain() const;
|
||||
virtual float rgTrackPeak() const;
|
||||
virtual String soundcheck() const;
|
||||
|
||||
virtual void setTitle(const String &value);
|
||||
virtual void setAlbumArtist(const String &value);
|
||||
virtual void setArtist(const String &value);
|
||||
virtual void setAlbum(const String &value);
|
||||
virtual void setComment(const String &value);
|
||||
virtual void setGenre(const String &value);
|
||||
virtual void setYear(unsigned int value);
|
||||
virtual void setTrack(unsigned int value);
|
||||
virtual void setDisc(unsigned int value);
|
||||
virtual void setCuesheet(const String &value);
|
||||
virtual void setRGAlbumGain(float);
|
||||
virtual void setRGAlbumPeak(float);
|
||||
virtual void setRGTrackGain(float);
|
||||
virtual void setRGTrackPeak(float);
|
||||
|
||||
virtual bool isEmpty() const;
|
||||
|
||||
/*!
|
||||
* \deprecated Use the item() and setItem() API instead
|
||||
*/
|
||||
TAGLIB_DEPRECATED ItemMap &itemListMap();
|
||||
|
||||
/*!
|
||||
* Returns a string-keyed map of the MP4::Items for this tag.
|
||||
*/
|
||||
const ItemMap &itemMap() const;
|
||||
|
||||
/*!
|
||||
* \return The item, if any, corresponding to \a key.
|
||||
*/
|
||||
Item item(const String &key) const;
|
||||
|
||||
/*!
|
||||
* Sets the value of \a key to \a value, overwriting any previous value.
|
||||
*/
|
||||
void setItem(const String &key, const Item &value);
|
||||
|
||||
/*!
|
||||
* Removes the entry with \a key from the tag, or does nothing if it does
|
||||
* not exist.
|
||||
*/
|
||||
void removeItem(const String &key);
|
||||
|
||||
/*!
|
||||
* \return True if the tag contains an entry for \a key.
|
||||
*/
|
||||
bool contains(const String &key) const;
|
||||
|
||||
PropertyMap properties() const;
|
||||
void removeUnsupportedProperties(const StringList& properties);
|
||||
PropertyMap setProperties(const PropertyMap &properties);
|
||||
|
||||
protected:
|
||||
/*!
|
||||
* Sets the value of \a key to \a value, overwriting any previous value.
|
||||
* If \a value is empty, the item is removed.
|
||||
*/
|
||||
void setTextItem(const String &key, const String &value);
|
||||
|
||||
private:
|
||||
AtomDataList parseData2(const Atom *atom, int expectedFlags = -1,
|
||||
bool freeForm = false);
|
||||
ByteVectorList parseData(const Atom *atom, int expectedFlags = -1,
|
||||
bool freeForm = false);
|
||||
void parseText(const Atom *atom, int expectedFlags = 1);
|
||||
void parseFreeForm(const Atom *atom);
|
||||
void parseInt(const Atom *atom);
|
||||
void parseByte(const Atom *atom);
|
||||
void parseUInt(const Atom *atom);
|
||||
void parseLongLong(const Atom *atom);
|
||||
void parseGnre(const Atom *atom);
|
||||
void parseIntPair(const Atom *atom);
|
||||
void parseBool(const Atom *atom);
|
||||
void parseCovr(const Atom *atom);
|
||||
|
||||
ByteVector padIlst(const ByteVector &data, int length = -1) const;
|
||||
ByteVector renderAtom(const ByteVector &name, const ByteVector &data) const;
|
||||
ByteVector renderData(const ByteVector &name, int flags,
|
||||
const ByteVectorList &data) const;
|
||||
ByteVector renderText(const ByteVector &name, const Item &item,
|
||||
int flags = TypeUTF8) const;
|
||||
ByteVector renderFreeForm(const String &name, const Item &item) const;
|
||||
ByteVector renderBool(const ByteVector &name, const Item &item) const;
|
||||
ByteVector renderInt(const ByteVector &name, const Item &item) const;
|
||||
ByteVector renderByte(const ByteVector &name, const Item &item) const;
|
||||
ByteVector renderUInt(const ByteVector &name, const Item &item) const;
|
||||
ByteVector renderLongLong(const ByteVector &name, const Item &item) const;
|
||||
ByteVector renderIntPair(const ByteVector &name, const Item &item) const;
|
||||
ByteVector renderIntPairNoTrailing(const ByteVector &name, const Item &item) const;
|
||||
ByteVector renderCovr(const ByteVector &name, const Item &item) const;
|
||||
|
||||
void updateParents(const AtomList &path, long delta, int ignore = 0);
|
||||
void updateOffsets(long delta, long offset);
|
||||
|
||||
void saveNew(ByteVector data);
|
||||
void saveExisting(ByteVector data, const AtomList &path);
|
||||
|
||||
void addItem(const String &name, const Item &value);
|
||||
|
||||
class TagPrivate;
|
||||
TagPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,332 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||
email : kde@carewolf.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/toolkit/tbytevector.h>
|
||||
#include <taglib/toolkit/tstring.h>
|
||||
#include <taglib/tagunion.h>
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <taglib/toolkit/tpropertymap.h>
|
||||
#include <taglib/tagutils.h>
|
||||
|
||||
#include <taglib/mpc/mpcfile.h>
|
||||
#include <taglib/mpeg/id3v1/id3v1tag.h>
|
||||
#include <taglib/mpeg/id3v2/id3v2header.h>
|
||||
#include <taglib/ape/apetag.h>
|
||||
#include <taglib/ape/apefooter.h>
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
namespace
|
||||
{
|
||||
enum { MPCAPEIndex = 0, MPCID3v1Index = 1 };
|
||||
}
|
||||
|
||||
class MPC::File::FilePrivate
|
||||
{
|
||||
public:
|
||||
FilePrivate() :
|
||||
APELocation(-1),
|
||||
APESize(0),
|
||||
ID3v1Location(-1),
|
||||
ID3v2Header(0),
|
||||
ID3v2Location(-1),
|
||||
ID3v2Size(0),
|
||||
properties(0) {}
|
||||
|
||||
~FilePrivate()
|
||||
{
|
||||
delete ID3v2Header;
|
||||
delete properties;
|
||||
}
|
||||
|
||||
long APELocation;
|
||||
long APESize;
|
||||
|
||||
long ID3v1Location;
|
||||
|
||||
ID3v2::Header *ID3v2Header;
|
||||
long ID3v2Location;
|
||||
long ID3v2Size;
|
||||
|
||||
TagUnion tag;
|
||||
|
||||
Properties *properties;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// static members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool MPC::File::isSupported(IOStream *stream)
|
||||
{
|
||||
// A newer MPC file has to start with "MPCK" or "MP+", but older files don't
|
||||
// have keys to do a quick check.
|
||||
|
||||
const ByteVector id = Utils::readHeader(stream, 4, false);
|
||||
return (id == "MPCK" || id.startsWith("MP+"));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MPC::File::File(FileName file, bool readProperties, Properties::ReadStyle) :
|
||||
TagLib::File(file),
|
||||
d(new FilePrivate())
|
||||
{
|
||||
if(isOpen())
|
||||
read(readProperties);
|
||||
}
|
||||
|
||||
MPC::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle) :
|
||||
TagLib::File(stream),
|
||||
d(new FilePrivate())
|
||||
{
|
||||
if(isOpen())
|
||||
read(readProperties);
|
||||
}
|
||||
|
||||
MPC::File::~File()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
TagLib::Tag *MPC::File::tag() const
|
||||
{
|
||||
return &d->tag;
|
||||
}
|
||||
|
||||
PropertyMap MPC::File::properties() const
|
||||
{
|
||||
return d->tag.properties();
|
||||
}
|
||||
|
||||
void MPC::File::removeUnsupportedProperties(const StringList &properties)
|
||||
{
|
||||
d->tag.removeUnsupportedProperties(properties);
|
||||
}
|
||||
|
||||
PropertyMap MPC::File::setProperties(const PropertyMap &properties)
|
||||
{
|
||||
if(ID3v1Tag())
|
||||
ID3v1Tag()->setProperties(properties);
|
||||
|
||||
return APETag(true)->setProperties(properties);
|
||||
}
|
||||
|
||||
MPC::Properties *MPC::File::audioProperties() const
|
||||
{
|
||||
return d->properties;
|
||||
}
|
||||
|
||||
bool MPC::File::save()
|
||||
{
|
||||
if(readOnly()) {
|
||||
debug("MPC::File::save() -- File is read only.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Possibly strip ID3v2 tag
|
||||
|
||||
if(!d->ID3v2Header && d->ID3v2Location >= 0) {
|
||||
removeBlock(d->ID3v2Location, d->ID3v2Size);
|
||||
|
||||
if(d->APELocation >= 0)
|
||||
d->APELocation -= d->ID3v2Size;
|
||||
|
||||
if(d->ID3v1Location >= 0)
|
||||
d->ID3v1Location -= d->ID3v2Size;
|
||||
|
||||
d->ID3v2Location = -1;
|
||||
d->ID3v2Size = 0;
|
||||
}
|
||||
|
||||
// Update ID3v1 tag
|
||||
|
||||
if(ID3v1Tag() && !ID3v1Tag()->isEmpty()) {
|
||||
|
||||
// ID3v1 tag is not empty. Update the old one or create a new one.
|
||||
|
||||
if(d->ID3v1Location >= 0) {
|
||||
seek(d->ID3v1Location);
|
||||
}
|
||||
else {
|
||||
seek(0, End);
|
||||
d->ID3v1Location = tell();
|
||||
}
|
||||
|
||||
writeBlock(ID3v1Tag()->render());
|
||||
}
|
||||
else {
|
||||
|
||||
// ID3v1 tag is empty. Remove the old one.
|
||||
|
||||
if(d->ID3v1Location >= 0) {
|
||||
truncate(d->ID3v1Location);
|
||||
d->ID3v1Location = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Update APE tag
|
||||
|
||||
if(APETag() && !APETag()->isEmpty()) {
|
||||
|
||||
// APE tag is not empty. Update the old one or create a new one.
|
||||
|
||||
if(d->APELocation < 0) {
|
||||
if(d->ID3v1Location >= 0)
|
||||
d->APELocation = d->ID3v1Location;
|
||||
else
|
||||
d->APELocation = length();
|
||||
}
|
||||
|
||||
const ByteVector data = APETag()->render();
|
||||
insert(data, d->APELocation, d->APESize);
|
||||
|
||||
if(d->ID3v1Location >= 0)
|
||||
d->ID3v1Location += (static_cast<long>(data.size()) - d->APESize);
|
||||
|
||||
d->APESize = data.size();
|
||||
}
|
||||
else {
|
||||
|
||||
// APE tag is empty. Remove the old one.
|
||||
|
||||
if(d->APELocation >= 0) {
|
||||
removeBlock(d->APELocation, d->APESize);
|
||||
|
||||
if(d->ID3v1Location >= 0)
|
||||
d->ID3v1Location -= d->APESize;
|
||||
|
||||
d->APELocation = -1;
|
||||
d->APESize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ID3v1::Tag *MPC::File::ID3v1Tag(bool create)
|
||||
{
|
||||
return d->tag.access<ID3v1::Tag>(MPCID3v1Index, create);
|
||||
}
|
||||
|
||||
APE::Tag *MPC::File::APETag(bool create)
|
||||
{
|
||||
return d->tag.access<APE::Tag>(MPCAPEIndex, create);
|
||||
}
|
||||
|
||||
void MPC::File::strip(int tags)
|
||||
{
|
||||
if(tags & ID3v1)
|
||||
d->tag.set(MPCID3v1Index, 0);
|
||||
|
||||
if(tags & APE)
|
||||
d->tag.set(MPCAPEIndex, 0);
|
||||
|
||||
if(!ID3v1Tag())
|
||||
APETag(true);
|
||||
|
||||
if(tags & ID3v2) {
|
||||
delete d->ID3v2Header;
|
||||
d->ID3v2Header = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void MPC::File::remove(int tags)
|
||||
{
|
||||
strip(tags);
|
||||
}
|
||||
|
||||
bool MPC::File::hasID3v1Tag() const
|
||||
{
|
||||
return (d->ID3v1Location >= 0);
|
||||
}
|
||||
|
||||
bool MPC::File::hasAPETag() const
|
||||
{
|
||||
return (d->APELocation >= 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void MPC::File::read(bool readProperties)
|
||||
{
|
||||
// Look for an ID3v2 tag
|
||||
|
||||
d->ID3v2Location = Utils::findID3v2(this);
|
||||
|
||||
if(d->ID3v2Location >= 0) {
|
||||
seek(d->ID3v2Location);
|
||||
d->ID3v2Header = new ID3v2::Header(readBlock(ID3v2::Header::size()));
|
||||
d->ID3v2Size = d->ID3v2Header->completeTagSize();
|
||||
}
|
||||
|
||||
// Look for an ID3v1 tag
|
||||
|
||||
d->ID3v1Location = Utils::findID3v1(this);
|
||||
|
||||
if(d->ID3v1Location >= 0)
|
||||
d->tag.set(MPCID3v1Index, new ID3v1::Tag(this, d->ID3v1Location));
|
||||
|
||||
// Look for an APE tag
|
||||
|
||||
d->APELocation = Utils::findAPE(this, d->ID3v1Location);
|
||||
|
||||
if(d->APELocation >= 0) {
|
||||
d->tag.set(MPCAPEIndex, new APE::Tag(this, d->APELocation));
|
||||
d->APESize = APETag()->footer()->completeTagSize();
|
||||
d->APELocation = d->APELocation + APE::Footer::size() - d->APESize;
|
||||
}
|
||||
|
||||
if(d->ID3v1Location < 0)
|
||||
APETag(true);
|
||||
|
||||
// Look for MPC metadata
|
||||
|
||||
if(readProperties) {
|
||||
|
||||
long streamLength;
|
||||
|
||||
if(d->APELocation >= 0)
|
||||
streamLength = d->APELocation;
|
||||
else if(d->ID3v1Location >= 0)
|
||||
streamLength = d->ID3v1Location;
|
||||
else
|
||||
streamLength = length();
|
||||
|
||||
if(d->ID3v2Location >= 0) {
|
||||
seek(d->ID3v2Location + d->ID3v2Size);
|
||||
streamLength -= (d->ID3v2Location + d->ID3v2Size);
|
||||
}
|
||||
else {
|
||||
seek(0);
|
||||
}
|
||||
|
||||
d->properties = new Properties(this, streamLength);
|
||||
}
|
||||
}
|
|
@ -1,368 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||
email : kde@carewolf.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/toolkit/tstring.h>
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <bitset>
|
||||
#include <math.h>
|
||||
|
||||
#include <taglib/mpc/mpcproperties.h>
|
||||
#include <taglib/mpc/mpcfile.h>
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class MPC::Properties::PropertiesPrivate
|
||||
{
|
||||
public:
|
||||
PropertiesPrivate() :
|
||||
version(0),
|
||||
length(0),
|
||||
bitrate(0),
|
||||
sampleRate(0),
|
||||
channels(0),
|
||||
totalFrames(0),
|
||||
sampleFrames(0),
|
||||
trackGain(0),
|
||||
trackPeak(0),
|
||||
albumGain(0),
|
||||
albumPeak(0) {}
|
||||
|
||||
int version;
|
||||
int length;
|
||||
int bitrate;
|
||||
int sampleRate;
|
||||
int channels;
|
||||
unsigned int totalFrames;
|
||||
unsigned int sampleFrames;
|
||||
int trackGain;
|
||||
int trackPeak;
|
||||
int albumGain;
|
||||
int albumPeak;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MPC::Properties::Properties(const ByteVector &data, long streamLength, ReadStyle style) :
|
||||
AudioProperties(style),
|
||||
d(new PropertiesPrivate())
|
||||
{
|
||||
readSV7(data, streamLength);
|
||||
}
|
||||
|
||||
MPC::Properties::Properties(File *file, long streamLength, ReadStyle style) :
|
||||
AudioProperties(style),
|
||||
d(new PropertiesPrivate())
|
||||
{
|
||||
ByteVector magic = file->readBlock(4);
|
||||
if(magic == "MPCK") {
|
||||
// Musepack version 8
|
||||
readSV8(file, streamLength);
|
||||
}
|
||||
else {
|
||||
// Musepack version 7 or older, fixed size header
|
||||
readSV7(magic + file->readBlock(MPC::HeaderSize - 4), streamLength);
|
||||
}
|
||||
}
|
||||
|
||||
MPC::Properties::~Properties()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
int MPC::Properties::length() const
|
||||
{
|
||||
return lengthInSeconds();
|
||||
}
|
||||
|
||||
int MPC::Properties::lengthInSeconds() const
|
||||
{
|
||||
return d->length / 1000;
|
||||
}
|
||||
|
||||
int MPC::Properties::lengthInMilliseconds() const
|
||||
{
|
||||
return d->length;
|
||||
}
|
||||
|
||||
int MPC::Properties::bitrate() const
|
||||
{
|
||||
return d->bitrate;
|
||||
}
|
||||
|
||||
int MPC::Properties::sampleRate() const
|
||||
{
|
||||
return d->sampleRate;
|
||||
}
|
||||
|
||||
int MPC::Properties::channels() const
|
||||
{
|
||||
return d->channels;
|
||||
}
|
||||
|
||||
int MPC::Properties::mpcVersion() const
|
||||
{
|
||||
return d->version;
|
||||
}
|
||||
|
||||
unsigned int MPC::Properties::totalFrames() const
|
||||
{
|
||||
return d->totalFrames;
|
||||
}
|
||||
|
||||
unsigned int MPC::Properties::sampleFrames() const
|
||||
{
|
||||
return d->sampleFrames;
|
||||
}
|
||||
|
||||
int MPC::Properties::trackGain() const
|
||||
{
|
||||
return d->trackGain;
|
||||
}
|
||||
|
||||
int MPC::Properties::trackPeak() const
|
||||
{
|
||||
return d->trackPeak;
|
||||
}
|
||||
|
||||
int MPC::Properties::albumGain() const
|
||||
{
|
||||
return d->albumGain;
|
||||
}
|
||||
|
||||
int MPC::Properties::albumPeak() const
|
||||
{
|
||||
return d->albumPeak;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace
|
||||
{
|
||||
unsigned long readSize(File *file, unsigned int &sizeLength, bool &eof)
|
||||
{
|
||||
sizeLength = 0;
|
||||
eof = false;
|
||||
|
||||
unsigned char tmp;
|
||||
unsigned long size = 0;
|
||||
|
||||
do {
|
||||
const ByteVector b = file->readBlock(1);
|
||||
if(b.isEmpty()) {
|
||||
eof = true;
|
||||
break;
|
||||
}
|
||||
|
||||
tmp = b[0];
|
||||
size = (size << 7) | (tmp & 0x7F);
|
||||
sizeLength++;
|
||||
} while((tmp & 0x80));
|
||||
return size;
|
||||
}
|
||||
|
||||
unsigned long readSize(const ByteVector &data, unsigned int &pos)
|
||||
{
|
||||
unsigned char tmp;
|
||||
unsigned long size = 0;
|
||||
|
||||
do {
|
||||
tmp = data[pos++];
|
||||
size = (size << 7) | (tmp & 0x7F);
|
||||
} while((tmp & 0x80) && (pos < data.size()));
|
||||
return size;
|
||||
}
|
||||
|
||||
// This array looks weird, but the same as original MusePack code found at:
|
||||
// https://www.musepack.net/index.php?pg=src
|
||||
const unsigned short sftable [8] = { 44100, 48000, 37800, 32000, 0, 0, 0, 0 };
|
||||
}
|
||||
|
||||
void MPC::Properties::readSV8(File *file, long streamLength)
|
||||
{
|
||||
bool readSH = false, readRG = false;
|
||||
|
||||
while(!readSH && !readRG) {
|
||||
const ByteVector packetType = file->readBlock(2);
|
||||
|
||||
unsigned int packetSizeLength;
|
||||
bool eof;
|
||||
const unsigned long packetSize = readSize(file, packetSizeLength, eof);
|
||||
if(eof) {
|
||||
debug("MPC::Properties::readSV8() - Reached to EOF.");
|
||||
break;
|
||||
}
|
||||
|
||||
const unsigned long dataSize = packetSize - 2 - packetSizeLength;
|
||||
|
||||
const ByteVector data = file->readBlock(dataSize);
|
||||
if(data.size() != dataSize) {
|
||||
debug("MPC::Properties::readSV8() - dataSize doesn't match the actual data size.");
|
||||
break;
|
||||
}
|
||||
|
||||
if(packetType == "SH") {
|
||||
// Stream Header
|
||||
// http://trac.musepack.net/wiki/SV8Specification#StreamHeaderPacket
|
||||
|
||||
if(dataSize <= 5) {
|
||||
debug("MPC::Properties::readSV8() - \"SH\" packet is too short to parse.");
|
||||
break;
|
||||
}
|
||||
|
||||
readSH = true;
|
||||
|
||||
unsigned int pos = 4;
|
||||
d->version = data[pos];
|
||||
pos += 1;
|
||||
d->sampleFrames = readSize(data, pos);
|
||||
if(pos > dataSize - 3) {
|
||||
debug("MPC::Properties::readSV8() - \"SH\" packet is corrupt.");
|
||||
break;
|
||||
}
|
||||
|
||||
const unsigned long begSilence = readSize(data, pos);
|
||||
if(pos > dataSize - 2) {
|
||||
debug("MPC::Properties::readSV8() - \"SH\" packet is corrupt.");
|
||||
break;
|
||||
}
|
||||
|
||||
const unsigned short flags = data.toUShort(pos, true);
|
||||
pos += 2;
|
||||
|
||||
d->sampleRate = sftable[(flags >> 13) & 0x07];
|
||||
d->channels = ((flags >> 4) & 0x0F) + 1;
|
||||
|
||||
const unsigned int frameCount = d->sampleFrames - begSilence;
|
||||
if(frameCount > 0 && d->sampleRate > 0) {
|
||||
const double length = frameCount * 1000.0 / d->sampleRate;
|
||||
d->length = static_cast<int>(length + 0.5);
|
||||
d->bitrate = static_cast<int>(streamLength * 8.0 / length + 0.5);
|
||||
}
|
||||
}
|
||||
else if (packetType == "RG") {
|
||||
// Replay Gain
|
||||
// http://trac.musepack.net/wiki/SV8Specification#ReplaygainPacket
|
||||
|
||||
if(dataSize <= 9) {
|
||||
debug("MPC::Properties::readSV8() - \"RG\" packet is too short to parse.");
|
||||
break;
|
||||
}
|
||||
|
||||
readRG = true;
|
||||
|
||||
const int replayGainVersion = data[0];
|
||||
if(replayGainVersion == 1) {
|
||||
d->trackGain = data.toShort(1, true);
|
||||
d->trackPeak = data.toShort(3, true);
|
||||
d->albumGain = data.toShort(5, true);
|
||||
d->albumPeak = data.toShort(7, true);
|
||||
}
|
||||
}
|
||||
|
||||
else if(packetType == "SE") {
|
||||
break;
|
||||
}
|
||||
|
||||
else {
|
||||
file->seek(dataSize, File::Current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MPC::Properties::readSV7(const ByteVector &data, long streamLength)
|
||||
{
|
||||
if(data.startsWith("MP+")) {
|
||||
d->version = data[3] & 15;
|
||||
if(d->version < 7)
|
||||
return;
|
||||
|
||||
d->totalFrames = data.toUInt(4, false);
|
||||
|
||||
const unsigned int flags = data.toUInt(8, false);
|
||||
d->sampleRate = sftable[(flags >> 16) & 0x03];
|
||||
d->channels = 2;
|
||||
|
||||
const unsigned int gapless = data.toUInt(5, false);
|
||||
|
||||
d->trackGain = data.toShort(14, false);
|
||||
d->trackPeak = data.toUShort(12, false);
|
||||
d->albumGain = data.toShort(18, false);
|
||||
d->albumPeak = data.toUShort(16, false);
|
||||
|
||||
// convert gain info
|
||||
if(d->trackGain != 0) {
|
||||
int tmp = (int)((64.82 - (short)d->trackGain / 100.) * 256. + .5);
|
||||
if(tmp >= (1 << 16) || tmp < 0) tmp = 0;
|
||||
d->trackGain = tmp;
|
||||
}
|
||||
|
||||
if(d->albumGain != 0) {
|
||||
int tmp = (int)((64.82 - d->albumGain / 100.) * 256. + .5);
|
||||
if(tmp >= (1 << 16) || tmp < 0) tmp = 0;
|
||||
d->albumGain = tmp;
|
||||
}
|
||||
|
||||
if (d->trackPeak != 0)
|
||||
d->trackPeak = (int)(log10((double)d->trackPeak) * 20 * 256 + .5);
|
||||
|
||||
if (d->albumPeak != 0)
|
||||
d->albumPeak = (int)(log10((double)d->albumPeak) * 20 * 256 + .5);
|
||||
|
||||
bool trueGapless = (gapless >> 31) & 0x0001;
|
||||
if(trueGapless) {
|
||||
unsigned int lastFrameSamples = (gapless >> 20) & 0x07FF;
|
||||
d->sampleFrames = d->totalFrames * 1152 - lastFrameSamples;
|
||||
}
|
||||
else
|
||||
d->sampleFrames = d->totalFrames * 1152 - 576;
|
||||
}
|
||||
else {
|
||||
const unsigned int headerData = data.toUInt(0, false);
|
||||
|
||||
d->bitrate = (headerData >> 23) & 0x01ff;
|
||||
d->version = (headerData >> 11) & 0x03ff;
|
||||
d->sampleRate = 44100;
|
||||
d->channels = 2;
|
||||
|
||||
if(d->version >= 5)
|
||||
d->totalFrames = data.toUInt(4, false);
|
||||
else
|
||||
d->totalFrames = data.toUShort(6, false);
|
||||
|
||||
d->sampleFrames = d->totalFrames * 1152 - 576;
|
||||
}
|
||||
|
||||
if(d->sampleFrames > 0 && d->sampleRate > 0) {
|
||||
const double length = d->sampleFrames * 1000.0 / d->sampleRate;
|
||||
d->length = static_cast<int>(length + 0.5);
|
||||
|
||||
if(d->bitrate == 0)
|
||||
d->bitrate = static_cast<int>(streamLength * 8.0 / length + 0.5);
|
||||
}
|
||||
}
|
|
@ -1,286 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/mpeg/id3v1/id3v1genres.h>
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
namespace
|
||||
{
|
||||
const wchar_t *genres[] = {
|
||||
L"Blues",
|
||||
L"Classic Rock",
|
||||
L"Country",
|
||||
L"Dance",
|
||||
L"Disco",
|
||||
L"Funk",
|
||||
L"Grunge",
|
||||
L"Hip-Hop",
|
||||
L"Jazz",
|
||||
L"Metal",
|
||||
L"New Age",
|
||||
L"Oldies",
|
||||
L"Other",
|
||||
L"Pop",
|
||||
L"R&B",
|
||||
L"Rap",
|
||||
L"Reggae",
|
||||
L"Rock",
|
||||
L"Techno",
|
||||
L"Industrial",
|
||||
L"Alternative",
|
||||
L"Ska",
|
||||
L"Death Metal",
|
||||
L"Pranks",
|
||||
L"Soundtrack",
|
||||
L"Euro-Techno",
|
||||
L"Ambient",
|
||||
L"Trip-Hop",
|
||||
L"Vocal",
|
||||
L"Jazz-Funk",
|
||||
L"Fusion",
|
||||
L"Trance",
|
||||
L"Classical",
|
||||
L"Instrumental",
|
||||
L"Acid",
|
||||
L"House",
|
||||
L"Game",
|
||||
L"Sound Clip",
|
||||
L"Gospel",
|
||||
L"Noise",
|
||||
L"Alternative Rock",
|
||||
L"Bass",
|
||||
L"Soul",
|
||||
L"Punk",
|
||||
L"Space",
|
||||
L"Meditative",
|
||||
L"Instrumental Pop",
|
||||
L"Instrumental Rock",
|
||||
L"Ethnic",
|
||||
L"Gothic",
|
||||
L"Darkwave",
|
||||
L"Techno-Industrial",
|
||||
L"Electronic",
|
||||
L"Pop-Folk",
|
||||
L"Eurodance",
|
||||
L"Dream",
|
||||
L"Southern Rock",
|
||||
L"Comedy",
|
||||
L"Cult",
|
||||
L"Gangsta",
|
||||
L"Top 40",
|
||||
L"Christian Rap",
|
||||
L"Pop/Funk",
|
||||
L"Jungle",
|
||||
L"Native American",
|
||||
L"Cabaret",
|
||||
L"New Wave",
|
||||
L"Psychedelic",
|
||||
L"Rave",
|
||||
L"Showtunes",
|
||||
L"Trailer",
|
||||
L"Lo-Fi",
|
||||
L"Tribal",
|
||||
L"Acid Punk",
|
||||
L"Acid Jazz",
|
||||
L"Polka",
|
||||
L"Retro",
|
||||
L"Musical",
|
||||
L"Rock & Roll",
|
||||
L"Hard Rock",
|
||||
L"Folk",
|
||||
L"Folk Rock",
|
||||
L"National Folk",
|
||||
L"Swing",
|
||||
L"Fast Fusion",
|
||||
L"Bebop",
|
||||
L"Latin",
|
||||
L"Revival",
|
||||
L"Celtic",
|
||||
L"Bluegrass",
|
||||
L"Avant-garde",
|
||||
L"Gothic Rock",
|
||||
L"Progressive Rock",
|
||||
L"Psychedelic Rock",
|
||||
L"Symphonic Rock",
|
||||
L"Slow Rock",
|
||||
L"Big Band",
|
||||
L"Chorus",
|
||||
L"Easy Listening",
|
||||
L"Acoustic",
|
||||
L"Humour",
|
||||
L"Speech",
|
||||
L"Chanson",
|
||||
L"Opera",
|
||||
L"Chamber Music",
|
||||
L"Sonata",
|
||||
L"Symphony",
|
||||
L"Booty Bass",
|
||||
L"Primus",
|
||||
L"Porn Groove",
|
||||
L"Satire",
|
||||
L"Slow Jam",
|
||||
L"Club",
|
||||
L"Tango",
|
||||
L"Samba",
|
||||
L"Folklore",
|
||||
L"Ballad",
|
||||
L"Power Ballad",
|
||||
L"Rhythmic Soul",
|
||||
L"Freestyle",
|
||||
L"Duet",
|
||||
L"Punk Rock",
|
||||
L"Drum Solo",
|
||||
L"A Cappella",
|
||||
L"Euro-House",
|
||||
L"Dancehall",
|
||||
L"Goa",
|
||||
L"Drum & Bass",
|
||||
L"Club-House",
|
||||
L"Hardcore Techno",
|
||||
L"Terror",
|
||||
L"Indie",
|
||||
L"Britpop",
|
||||
L"Worldbeat",
|
||||
L"Polsk Punk",
|
||||
L"Beat",
|
||||
L"Christian Gangsta Rap",
|
||||
L"Heavy Metal",
|
||||
L"Black Metal",
|
||||
L"Crossover",
|
||||
L"Contemporary Christian",
|
||||
L"Christian Rock",
|
||||
L"Merengue",
|
||||
L"Salsa",
|
||||
L"Thrash Metal",
|
||||
L"Anime",
|
||||
L"Jpop",
|
||||
L"Synthpop",
|
||||
L"Abstract",
|
||||
L"Art Rock",
|
||||
L"Baroque",
|
||||
L"Bhangra",
|
||||
L"Big Beat",
|
||||
L"Breakbeat",
|
||||
L"Chillout",
|
||||
L"Downtempo",
|
||||
L"Dub",
|
||||
L"EBM",
|
||||
L"Eclectic",
|
||||
L"Electro",
|
||||
L"Electroclash",
|
||||
L"Emo",
|
||||
L"Experimental",
|
||||
L"Garage",
|
||||
L"Global",
|
||||
L"IDM",
|
||||
L"Illbient",
|
||||
L"Industro-Goth",
|
||||
L"Jam Band",
|
||||
L"Krautrock",
|
||||
L"Leftfield",
|
||||
L"Lounge",
|
||||
L"Math Rock",
|
||||
L"New Romantic",
|
||||
L"Nu-Breakz",
|
||||
L"Post-Punk",
|
||||
L"Post-Rock",
|
||||
L"Psytrance",
|
||||
L"Shoegaze",
|
||||
L"Space Rock",
|
||||
L"Trop Rock",
|
||||
L"World Music",
|
||||
L"Neoclassical",
|
||||
L"Audiobook",
|
||||
L"Audio Theatre",
|
||||
L"Neue Deutsche Welle",
|
||||
L"Podcast",
|
||||
L"Indie Rock",
|
||||
L"G-Funk",
|
||||
L"Dubstep",
|
||||
L"Garage Rock",
|
||||
L"Psybient"
|
||||
};
|
||||
const int genresSize = sizeof(genres) / sizeof(genres[0]);
|
||||
}
|
||||
|
||||
StringList ID3v1::genreList()
|
||||
{
|
||||
StringList l;
|
||||
for(int i = 0; i < genresSize; i++) {
|
||||
l.append(genres[i]);
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
ID3v1::GenreMap ID3v1::genreMap()
|
||||
{
|
||||
GenreMap m;
|
||||
for(int i = 0; i < genresSize; i++) {
|
||||
m.insert(genres[i], i);
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
String ID3v1::genre(int i)
|
||||
{
|
||||
if(i >= 0 && i < genresSize)
|
||||
return String(genres[i]); // always make a copy
|
||||
else
|
||||
return String();
|
||||
}
|
||||
|
||||
int ID3v1::genreIndex(const String &name)
|
||||
{
|
||||
for(int i = 0; i < genresSize; ++i) {
|
||||
if(name == genres[i])
|
||||
return i;
|
||||
}
|
||||
|
||||
// If the name was not found, try the names which have been changed
|
||||
static const struct {
|
||||
const wchar_t *genre;
|
||||
int code;
|
||||
} fixUpGenres[] = {
|
||||
{ L"Jazz+Funk", 29 },
|
||||
{ L"Folk/Rock", 81 },
|
||||
{ L"Bebob", 85 },
|
||||
{ L"Avantgarde", 90 },
|
||||
{ L"Dance Hall", 125 },
|
||||
{ L"Hardcore", 129 },
|
||||
{ L"BritPop", 132 },
|
||||
{ L"Negerpunk", 133 }
|
||||
};
|
||||
static const int fixUpGenresSize =
|
||||
sizeof(fixUpGenres) / sizeof(fixUpGenres[0]);
|
||||
for(int i = 0; i < fixUpGenresSize; ++i) {
|
||||
if(name == fixUpGenres[i].genre)
|
||||
return fixUpGenres[i].code;
|
||||
}
|
||||
|
||||
return 255;
|
||||
}
|
|
@ -1,356 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <taglib/toolkit/tfile.h>
|
||||
|
||||
#include <taglib/mpeg/id3v1/id3v1tag.h>
|
||||
#include <taglib/mpeg/id3v1/id3v1genres.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v1;
|
||||
|
||||
namespace
|
||||
{
|
||||
const ID3v1::StringHandler defaultStringHandler;
|
||||
const ID3v1::StringHandler *stringHandler = &defaultStringHandler;
|
||||
}
|
||||
|
||||
class ID3v1::Tag::TagPrivate
|
||||
{
|
||||
public:
|
||||
TagPrivate() :
|
||||
file(0),
|
||||
tagOffset(0),
|
||||
track(0),
|
||||
genre(255) {}
|
||||
|
||||
File *file;
|
||||
long tagOffset;
|
||||
|
||||
String title;
|
||||
String artist;
|
||||
String album;
|
||||
String year;
|
||||
String comment;
|
||||
unsigned char track;
|
||||
unsigned char genre;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// StringHandler implementation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
StringHandler::StringHandler()
|
||||
{
|
||||
}
|
||||
|
||||
String ID3v1::StringHandler::parse(const ByteVector &data) const
|
||||
{
|
||||
return String(data, String::Latin1).stripWhiteSpace();
|
||||
}
|
||||
|
||||
ByteVector ID3v1::StringHandler::render(const String &s) const
|
||||
{
|
||||
if(s.isLatin1())
|
||||
return s.data(String::Latin1);
|
||||
else
|
||||
return ByteVector();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ID3v1::Tag::Tag() :
|
||||
TagLib::Tag(),
|
||||
d(new TagPrivate())
|
||||
{
|
||||
}
|
||||
|
||||
ID3v1::Tag::Tag(File *file, long tagOffset) :
|
||||
TagLib::Tag(),
|
||||
d(new TagPrivate())
|
||||
{
|
||||
d->file = file;
|
||||
d->tagOffset = tagOffset;
|
||||
|
||||
read();
|
||||
}
|
||||
|
||||
ID3v1::Tag::~Tag()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
ByteVector ID3v1::Tag::render() const
|
||||
{
|
||||
ByteVector data;
|
||||
|
||||
data.append(fileIdentifier());
|
||||
data.append(stringHandler->render(d->title).resize(30));
|
||||
data.append(stringHandler->render(d->artist).resize(30));
|
||||
data.append(stringHandler->render(d->album).resize(30));
|
||||
data.append(stringHandler->render(d->year).resize(4));
|
||||
data.append(stringHandler->render(d->comment).resize(28));
|
||||
data.append(char(0));
|
||||
data.append(char(d->track));
|
||||
data.append(char(d->genre));
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
ByteVector ID3v1::Tag::fileIdentifier()
|
||||
{
|
||||
return ByteVector::fromCString("TAG");
|
||||
}
|
||||
|
||||
String ID3v1::Tag::title() const
|
||||
{
|
||||
return d->title;
|
||||
}
|
||||
|
||||
String ID3v1::Tag::albumartist() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
String ID3v1::Tag::artist() const
|
||||
{
|
||||
return d->artist;
|
||||
}
|
||||
|
||||
String ID3v1::Tag::composer() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
String ID3v1::Tag::album() const
|
||||
{
|
||||
return d->album;
|
||||
}
|
||||
|
||||
String ID3v1::Tag::unsyncedlyrics() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
String ID3v1::Tag::comment() const
|
||||
{
|
||||
return d->comment;
|
||||
}
|
||||
|
||||
String ID3v1::Tag::genre() const
|
||||
{
|
||||
return ID3v1::genre(d->genre);
|
||||
}
|
||||
|
||||
unsigned int ID3v1::Tag::year() const
|
||||
{
|
||||
return d->year.toInt();
|
||||
}
|
||||
|
||||
unsigned int ID3v1::Tag::track() const
|
||||
{
|
||||
return d->track;
|
||||
}
|
||||
|
||||
unsigned int ID3v1::Tag::disc() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
String ID3v1::Tag::cuesheet() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
float ID3v1::Tag::rgAlbumGain() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float ID3v1::Tag::rgAlbumPeak() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float ID3v1::Tag::rgTrackGain() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
float ID3v1::Tag::rgTrackPeak() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
String ID3v1::Tag::soundcheck() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setTitle(const String &s)
|
||||
{
|
||||
d->title = s;
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setAlbumArtist(const String &)
|
||||
{
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setArtist(const String &s)
|
||||
{
|
||||
d->artist = s;
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setComposer(const String &s)
|
||||
{
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setAlbum(const String &s)
|
||||
{
|
||||
d->album = s;
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setUnsyncedlyrics(const String &s)
|
||||
{
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setComment(const String &s)
|
||||
{
|
||||
d->comment = s;
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setGenre(const String &s)
|
||||
{
|
||||
d->genre = ID3v1::genreIndex(s);
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setYear(unsigned int i)
|
||||
{
|
||||
d->year = i > 0 ? String::number(i) : String();
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setTrack(unsigned int i)
|
||||
{
|
||||
d->track = i < 256 ? i : 0;
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setDisc(unsigned int i)
|
||||
{
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setCuesheet(const String &)
|
||||
{
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setRGAlbumGain(float)
|
||||
{
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setRGAlbumPeak(float)
|
||||
{
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setRGTrackGain(float)
|
||||
{
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setRGTrackPeak(float)
|
||||
{
|
||||
}
|
||||
|
||||
unsigned int ID3v1::Tag::genreNumber() const
|
||||
{
|
||||
return d->genre;
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setGenreNumber(unsigned int i)
|
||||
{
|
||||
d->genre = i < 256 ? i : 255;
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setStringHandler(const StringHandler *handler)
|
||||
{
|
||||
if(handler)
|
||||
stringHandler = handler;
|
||||
else
|
||||
stringHandler = &defaultStringHandler;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ID3v1::Tag::read()
|
||||
{
|
||||
if(d->file && d->file->isValid()) {
|
||||
d->file->seek(d->tagOffset);
|
||||
// read the tag -- always 128 bytes
|
||||
const ByteVector data = d->file->readBlock(128);
|
||||
|
||||
// some initial sanity checking
|
||||
if(data.size() == 128 && data.startsWith("TAG"))
|
||||
parse(data);
|
||||
else
|
||||
debug("ID3v1 tag is not valid or could not be read at the specified offset.");
|
||||
}
|
||||
}
|
||||
|
||||
void ID3v1::Tag::parse(const ByteVector &data)
|
||||
{
|
||||
int offset = 3;
|
||||
|
||||
d->title = stringHandler->parse(data.mid(offset, 30));
|
||||
offset += 30;
|
||||
|
||||
d->artist = stringHandler->parse(data.mid(offset, 30));
|
||||
offset += 30;
|
||||
|
||||
d->album = stringHandler->parse(data.mid(offset, 30));
|
||||
offset += 30;
|
||||
|
||||
d->year = stringHandler->parse(data.mid(offset, 4));
|
||||
offset += 4;
|
||||
|
||||
// Check for ID3v1.1 -- Note that ID3v1 *does not* support "track zero" -- this
|
||||
// is not a bug in TagLib. Since a zeroed byte is what we would expect to
|
||||
// indicate the end of a C-String, specifically the comment string, a value of
|
||||
// zero must be assumed to be just that.
|
||||
|
||||
if(data[offset + 28] == 0 && data[offset + 29] != 0) {
|
||||
// ID3v1.1 detected
|
||||
|
||||
d->comment = stringHandler->parse(data.mid(offset, 28));
|
||||
d->track = static_cast<unsigned char>(data[offset + 29]);
|
||||
}
|
||||
else
|
||||
d->comment = data.mid(offset, 30);
|
||||
|
||||
offset += 30;
|
||||
|
||||
d->genre = static_cast<unsigned char>(data[offset]);
|
||||
}
|
|
@ -1,225 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/mpeg/id3v2/frames/attachedpictureframe.h>
|
||||
|
||||
#include <taglib/toolkit/tstringlist.h>
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class AttachedPictureFrame::AttachedPictureFramePrivate
|
||||
{
|
||||
public:
|
||||
AttachedPictureFramePrivate() : textEncoding(String::Latin1),
|
||||
type(AttachedPictureFrame::Other) {}
|
||||
|
||||
String::Type textEncoding;
|
||||
String mimeType;
|
||||
AttachedPictureFrame::Type type;
|
||||
String description;
|
||||
ByteVector data;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AttachedPictureFrame::AttachedPictureFrame() :
|
||||
Frame("APIC"),
|
||||
d(new AttachedPictureFramePrivate())
|
||||
{
|
||||
}
|
||||
|
||||
AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data) :
|
||||
Frame(data),
|
||||
d(new AttachedPictureFramePrivate())
|
||||
{
|
||||
setData(data);
|
||||
}
|
||||
|
||||
AttachedPictureFrame::~AttachedPictureFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String AttachedPictureFrame::toString() const
|
||||
{
|
||||
String s = "[" + d->mimeType + "]";
|
||||
return d->description.isEmpty() ? s : d->description + " " + s;
|
||||
}
|
||||
|
||||
String::Type AttachedPictureFrame::textEncoding() const
|
||||
{
|
||||
return d->textEncoding;
|
||||
}
|
||||
|
||||
void AttachedPictureFrame::setTextEncoding(String::Type t)
|
||||
{
|
||||
d->textEncoding = t;
|
||||
}
|
||||
|
||||
String AttachedPictureFrame::mimeType() const
|
||||
{
|
||||
return d->mimeType;
|
||||
}
|
||||
|
||||
void AttachedPictureFrame::setMimeType(const String &m)
|
||||
{
|
||||
d->mimeType = m;
|
||||
}
|
||||
|
||||
AttachedPictureFrame::Type AttachedPictureFrame::type() const
|
||||
{
|
||||
return d->type;
|
||||
}
|
||||
|
||||
void AttachedPictureFrame::setType(Type t)
|
||||
{
|
||||
d->type = t;
|
||||
}
|
||||
|
||||
String AttachedPictureFrame::description() const
|
||||
{
|
||||
return d->description;
|
||||
}
|
||||
|
||||
void AttachedPictureFrame::setDescription(const String &desc)
|
||||
{
|
||||
d->description = desc;
|
||||
}
|
||||
|
||||
ByteVector AttachedPictureFrame::picture() const
|
||||
{
|
||||
return d->data;
|
||||
}
|
||||
|
||||
void AttachedPictureFrame::setPicture(const ByteVector &p)
|
||||
{
|
||||
d->data = p;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void AttachedPictureFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
if(data.size() < 5) {
|
||||
debug("A picture frame must contain at least 5 bytes.");
|
||||
return;
|
||||
}
|
||||
|
||||
d->textEncoding = String::Type(data[0]);
|
||||
|
||||
int pos = 1;
|
||||
|
||||
d->mimeType = readStringField(data, String::Latin1, &pos);
|
||||
/* Now we need at least two more bytes available */
|
||||
if(static_cast<unsigned int>(pos) + 1 >= data.size()) {
|
||||
debug("Truncated picture frame.");
|
||||
return;
|
||||
}
|
||||
|
||||
d->type = (TagLib::ID3v2::AttachedPictureFrame::Type)data[pos++];
|
||||
d->description = readStringField(data, d->textEncoding, &pos);
|
||||
|
||||
d->data = data.mid(pos);
|
||||
}
|
||||
|
||||
ByteVector AttachedPictureFrame::renderFields() const
|
||||
{
|
||||
ByteVector data;
|
||||
|
||||
String::Type encoding = checkTextEncoding(d->description, d->textEncoding);
|
||||
|
||||
data.append(char(encoding));
|
||||
data.append(d->mimeType.data(String::Latin1));
|
||||
data.append(textDelimiter(String::Latin1));
|
||||
data.append(char(d->type));
|
||||
data.append(d->description.data(encoding));
|
||||
data.append(textDelimiter(encoding));
|
||||
data.append(d->data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new AttachedPictureFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// support for ID3v2.2 PIC frames
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void AttachedPictureFrameV22::parseFields(const ByteVector &data)
|
||||
{
|
||||
if(data.size() < 5) {
|
||||
debug("A picture frame must contain at least 5 bytes.");
|
||||
return;
|
||||
}
|
||||
|
||||
d->textEncoding = String::Type(data[0]);
|
||||
|
||||
int pos = 1;
|
||||
|
||||
String fixedString = String(data.mid(pos, 3), String::Latin1);
|
||||
pos += 3;
|
||||
// convert fixed string image type to mime string
|
||||
if (fixedString.upper() == "JPG") {
|
||||
d->mimeType = "image/jpeg";
|
||||
} else if (fixedString.upper() == "PNG") {
|
||||
d->mimeType = "image/png";
|
||||
} else {
|
||||
debug("probably unsupported image type");
|
||||
d->mimeType = "image/" + fixedString;
|
||||
}
|
||||
|
||||
d->type = (TagLib::ID3v2::AttachedPictureFrame::Type)data[pos++];
|
||||
d->description = readStringField(data, d->textEncoding, &pos);
|
||||
|
||||
d->data = data.mid(pos);
|
||||
}
|
||||
|
||||
AttachedPictureFrameV22::AttachedPictureFrameV22(const ByteVector &data, Header *h)
|
||||
{
|
||||
// set v2.2 header to make fieldData work correctly
|
||||
setHeader(h, true);
|
||||
|
||||
parseFields(fieldData(data));
|
||||
|
||||
// now set the v2.4 header
|
||||
Frame::Header *newHeader = new Frame::Header("APIC");
|
||||
newHeader->setFrameSize(h->frameSize());
|
||||
setHeader(newHeader, true);
|
||||
}
|
|
@ -1,309 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2013 by Lukas Krejci
|
||||
email : krejclu6@fel.cvut.cz
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/toolkit/tbytevectorlist.h>
|
||||
#include <taglib/toolkit/tpropertymap.h>
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <taglib/mpeg/id3v2/frames/chapterframe.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class ChapterFrame::ChapterFramePrivate
|
||||
{
|
||||
public:
|
||||
ChapterFramePrivate() :
|
||||
tagHeader(0),
|
||||
startTime(0),
|
||||
endTime(0),
|
||||
startOffset(0),
|
||||
endOffset(0)
|
||||
{
|
||||
embeddedFrameList.setAutoDelete(true);
|
||||
}
|
||||
|
||||
const ID3v2::Header *tagHeader;
|
||||
ByteVector elementID;
|
||||
unsigned int startTime;
|
||||
unsigned int endTime;
|
||||
unsigned int startOffset;
|
||||
unsigned int endOffset;
|
||||
FrameListMap embeddedFrameListMap;
|
||||
FrameList embeddedFrameList;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ChapterFrame::ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data) :
|
||||
ID3v2::Frame(data),
|
||||
d(new ChapterFramePrivate())
|
||||
{
|
||||
d->tagHeader = tagHeader;
|
||||
setData(data);
|
||||
}
|
||||
|
||||
ChapterFrame::ChapterFrame(const ByteVector &elementID,
|
||||
unsigned int startTime, unsigned int endTime,
|
||||
unsigned int startOffset, unsigned int endOffset,
|
||||
const FrameList &embeddedFrames) :
|
||||
ID3v2::Frame("CHAP"),
|
||||
d(new ChapterFramePrivate())
|
||||
{
|
||||
// setElementID has a workaround for a previously silly API where you had to
|
||||
// specifically include the null byte.
|
||||
|
||||
setElementID(elementID);
|
||||
|
||||
d->startTime = startTime;
|
||||
d->endTime = endTime;
|
||||
d->startOffset = startOffset;
|
||||
d->endOffset = endOffset;
|
||||
|
||||
for(FrameList::ConstIterator it = embeddedFrames.begin();
|
||||
it != embeddedFrames.end(); ++it)
|
||||
addEmbeddedFrame(*it);
|
||||
}
|
||||
|
||||
ChapterFrame::~ChapterFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
ByteVector ChapterFrame::elementID() const
|
||||
{
|
||||
return d->elementID;
|
||||
}
|
||||
|
||||
unsigned int ChapterFrame::startTime() const
|
||||
{
|
||||
return d->startTime;
|
||||
}
|
||||
|
||||
unsigned int ChapterFrame::endTime() const
|
||||
{
|
||||
return d->endTime;
|
||||
}
|
||||
|
||||
unsigned int ChapterFrame::startOffset() const
|
||||
{
|
||||
return d->startOffset;
|
||||
}
|
||||
|
||||
unsigned int ChapterFrame::endOffset() const
|
||||
{
|
||||
return d->endOffset;
|
||||
}
|
||||
|
||||
void ChapterFrame::setElementID(const ByteVector &eID)
|
||||
{
|
||||
d->elementID = eID;
|
||||
|
||||
if(d->elementID.endsWith(char(0)))
|
||||
d->elementID = d->elementID.mid(0, d->elementID.size() - 1);
|
||||
}
|
||||
|
||||
void ChapterFrame::setStartTime(const unsigned int &sT)
|
||||
{
|
||||
d->startTime = sT;
|
||||
}
|
||||
|
||||
void ChapterFrame::setEndTime(const unsigned int &eT)
|
||||
{
|
||||
d->endTime = eT;
|
||||
}
|
||||
|
||||
void ChapterFrame::setStartOffset(const unsigned int &sO)
|
||||
{
|
||||
d->startOffset = sO;
|
||||
}
|
||||
|
||||
void ChapterFrame::setEndOffset(const unsigned int &eO)
|
||||
{
|
||||
d->endOffset = eO;
|
||||
}
|
||||
|
||||
const FrameListMap &ChapterFrame::embeddedFrameListMap() const
|
||||
{
|
||||
return d->embeddedFrameListMap;
|
||||
}
|
||||
|
||||
const FrameList &ChapterFrame::embeddedFrameList() const
|
||||
{
|
||||
return d->embeddedFrameList;
|
||||
}
|
||||
|
||||
const FrameList &ChapterFrame::embeddedFrameList(const ByteVector &frameID) const
|
||||
{
|
||||
return d->embeddedFrameListMap[frameID];
|
||||
}
|
||||
|
||||
void ChapterFrame::addEmbeddedFrame(Frame *frame)
|
||||
{
|
||||
d->embeddedFrameList.append(frame);
|
||||
d->embeddedFrameListMap[frame->frameID()].append(frame);
|
||||
}
|
||||
|
||||
void ChapterFrame::removeEmbeddedFrame(Frame *frame, bool del)
|
||||
{
|
||||
// remove the frame from the frame list
|
||||
FrameList::Iterator it = d->embeddedFrameList.find(frame);
|
||||
d->embeddedFrameList.erase(it);
|
||||
|
||||
// ...and from the frame list map
|
||||
it = d->embeddedFrameListMap[frame->frameID()].find(frame);
|
||||
d->embeddedFrameListMap[frame->frameID()].erase(it);
|
||||
|
||||
// ...and delete as desired
|
||||
if(del)
|
||||
delete frame;
|
||||
}
|
||||
|
||||
void ChapterFrame::removeEmbeddedFrames(const ByteVector &id)
|
||||
{
|
||||
FrameList l = d->embeddedFrameListMap[id];
|
||||
for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it)
|
||||
removeEmbeddedFrame(*it, true);
|
||||
}
|
||||
|
||||
String ChapterFrame::toString() const
|
||||
{
|
||||
String s = String(d->elementID) +
|
||||
": start time: " + String::number(d->startTime) +
|
||||
", end time: " + String::number(d->endTime);
|
||||
|
||||
if(d->startOffset != 0xFFFFFFFF)
|
||||
s += ", start offset: " + String::number(d->startOffset);
|
||||
|
||||
if(d->endOffset != 0xFFFFFFFF)
|
||||
s += ", end offset: " + String::number(d->endOffset);
|
||||
|
||||
if(!d->embeddedFrameList.isEmpty()) {
|
||||
StringList frameIDs;
|
||||
for(FrameList::ConstIterator it = d->embeddedFrameList.begin();
|
||||
it != d->embeddedFrameList.end(); ++it)
|
||||
frameIDs.append((*it)->frameID());
|
||||
s += ", sub-frames: [ " + frameIDs.toString(", ") + " ]";
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
PropertyMap ChapterFrame::asProperties() const
|
||||
{
|
||||
PropertyMap map;
|
||||
|
||||
map.unsupportedData().append(frameID() + String("/") + d->elementID);
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
ChapterFrame *ChapterFrame::findByElementID(const ID3v2::Tag *tag, const ByteVector &eID) // static
|
||||
{
|
||||
ID3v2::FrameList comments = tag->frameList("CHAP");
|
||||
|
||||
for(ID3v2::FrameList::ConstIterator it = comments.begin();
|
||||
it != comments.end();
|
||||
++it)
|
||||
{
|
||||
ChapterFrame *frame = dynamic_cast<ChapterFrame *>(*it);
|
||||
if(frame && frame->elementID() == eID)
|
||||
return frame;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ChapterFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
unsigned int size = data.size();
|
||||
if(size < 18) {
|
||||
debug("A CHAP frame must contain at least 18 bytes (1 byte element ID "
|
||||
"terminated by null and 4x4 bytes for start and end time and offset).");
|
||||
return;
|
||||
}
|
||||
|
||||
int pos = 0;
|
||||
unsigned int embPos = 0;
|
||||
d->elementID = readStringField(data, String::Latin1, &pos).data(String::Latin1);
|
||||
d->startTime = data.toUInt(pos, true);
|
||||
pos += 4;
|
||||
d->endTime = data.toUInt(pos, true);
|
||||
pos += 4;
|
||||
d->startOffset = data.toUInt(pos, true);
|
||||
pos += 4;
|
||||
d->endOffset = data.toUInt(pos, true);
|
||||
pos += 4;
|
||||
size -= pos;
|
||||
|
||||
// Embedded frames are optional
|
||||
|
||||
if(size < header()->size())
|
||||
return;
|
||||
|
||||
while(embPos < size - header()->size()) {
|
||||
Frame *frame = FrameFactory::instance()->createFrame(data.mid(pos + embPos), d->tagHeader);
|
||||
|
||||
if(!frame)
|
||||
return;
|
||||
|
||||
// Checks to make sure that frame parsed correctly.
|
||||
if(frame->size() <= 0) {
|
||||
delete frame;
|
||||
return;
|
||||
}
|
||||
|
||||
embPos += frame->size() + header()->size();
|
||||
addEmbeddedFrame(frame);
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector ChapterFrame::renderFields() const
|
||||
{
|
||||
ByteVector data;
|
||||
|
||||
data.append(d->elementID);
|
||||
data.append('\0');
|
||||
data.append(ByteVector::fromUInt(d->startTime, true));
|
||||
data.append(ByteVector::fromUInt(d->endTime, true));
|
||||
data.append(ByteVector::fromUInt(d->startOffset, true));
|
||||
data.append(ByteVector::fromUInt(d->endOffset, true));
|
||||
FrameList l = d->embeddedFrameList;
|
||||
for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it)
|
||||
data.append((*it)->render());
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
ChapterFrame::ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new ChapterFramePrivate())
|
||||
{
|
||||
d->tagHeader = tagHeader;
|
||||
parseFields(fieldData(data));
|
||||
}
|
|
@ -1,198 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/toolkit/tbytevectorlist.h>
|
||||
#include <taglib/mpeg/id3v2/id3v2tag.h>
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <taglib/toolkit/tstringlist.h>
|
||||
|
||||
#include <taglib/mpeg/id3v2/frames/commentsframe.h>
|
||||
#include <taglib/toolkit/tpropertymap.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class CommentsFrame::CommentsFramePrivate
|
||||
{
|
||||
public:
|
||||
CommentsFramePrivate() : textEncoding(String::Latin1) {}
|
||||
String::Type textEncoding;
|
||||
ByteVector language;
|
||||
String description;
|
||||
String text;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CommentsFrame::CommentsFrame(String::Type encoding) :
|
||||
Frame("COMM"),
|
||||
d(new CommentsFramePrivate())
|
||||
{
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
CommentsFrame::CommentsFrame(const ByteVector &data) :
|
||||
Frame(data),
|
||||
d(new CommentsFramePrivate())
|
||||
{
|
||||
setData(data);
|
||||
}
|
||||
|
||||
CommentsFrame::~CommentsFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String CommentsFrame::toString() const
|
||||
{
|
||||
return d->text;
|
||||
}
|
||||
|
||||
ByteVector CommentsFrame::language() const
|
||||
{
|
||||
return d->language;
|
||||
}
|
||||
|
||||
String CommentsFrame::description() const
|
||||
{
|
||||
return d->description;
|
||||
}
|
||||
|
||||
String CommentsFrame::text() const
|
||||
{
|
||||
return d->text;
|
||||
}
|
||||
|
||||
void CommentsFrame::setLanguage(const ByteVector &languageEncoding)
|
||||
{
|
||||
d->language = languageEncoding.mid(0, 3);
|
||||
}
|
||||
|
||||
void CommentsFrame::setDescription(const String &s)
|
||||
{
|
||||
d->description = s;
|
||||
}
|
||||
|
||||
void CommentsFrame::setText(const String &s)
|
||||
{
|
||||
d->text = s;
|
||||
}
|
||||
|
||||
String::Type CommentsFrame::textEncoding() const
|
||||
{
|
||||
return d->textEncoding;
|
||||
}
|
||||
|
||||
void CommentsFrame::setTextEncoding(String::Type encoding)
|
||||
{
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
PropertyMap CommentsFrame::asProperties() const
|
||||
{
|
||||
String key = description().upper();
|
||||
PropertyMap map;
|
||||
if(key.isEmpty() || key == "COMMENT")
|
||||
map.insert("COMMENT", text());
|
||||
else
|
||||
map.insert("COMMENT:" + key, text());
|
||||
return map;
|
||||
}
|
||||
|
||||
CommentsFrame *CommentsFrame::findByDescription(const ID3v2::Tag *tag, const String &d) // static
|
||||
{
|
||||
ID3v2::FrameList comments = tag->frameList("COMM");
|
||||
|
||||
for(ID3v2::FrameList::ConstIterator it = comments.begin();
|
||||
it != comments.end();
|
||||
++it)
|
||||
{
|
||||
CommentsFrame *frame = dynamic_cast<CommentsFrame *>(*it);
|
||||
if(frame && frame->description() == d)
|
||||
return frame;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CommentsFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
if(data.size() < 5) {
|
||||
debug("A comment frame must contain at least 5 bytes.");
|
||||
return;
|
||||
}
|
||||
|
||||
d->textEncoding = String::Type(data[0]);
|
||||
d->language = data.mid(1, 3);
|
||||
|
||||
int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
|
||||
|
||||
ByteVectorList l = ByteVectorList::split(data.mid(4), textDelimiter(d->textEncoding), byteAlign, 2);
|
||||
|
||||
if(l.size() == 2) {
|
||||
if(d->textEncoding == String::Latin1) {
|
||||
d->description = Tag::latin1StringHandler()->parse(l.front());
|
||||
d->text = Tag::latin1StringHandler()->parse(l.back());
|
||||
} else {
|
||||
d->description = String(l.front(), d->textEncoding);
|
||||
d->text = String(l.back(), d->textEncoding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector CommentsFrame::renderFields() const
|
||||
{
|
||||
ByteVector v;
|
||||
|
||||
String::Type encoding = d->textEncoding;
|
||||
|
||||
encoding = checkTextEncoding(d->description, encoding);
|
||||
encoding = checkTextEncoding(d->text, encoding);
|
||||
|
||||
v.append(char(encoding));
|
||||
v.append(d->language.size() == 3 ? d->language : "XXX");
|
||||
v.append(d->description.data(encoding));
|
||||
v.append(textDelimiter(encoding));
|
||||
v.append(d->text.data(encoding));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CommentsFrame::CommentsFrame(const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new CommentsFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
|
@ -1,144 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2014 by Urs Fleisch
|
||||
email : ufleisch@users.sourceforge.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/mpeg/id3v2/frames/eventtimingcodesframe.h>
|
||||
#include <taglib/toolkit/tbytevectorlist.h>
|
||||
#include <taglib/mpeg/id3v2/id3v2tag.h>
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <taglib/toolkit/tpropertymap.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class EventTimingCodesFrame::EventTimingCodesFramePrivate
|
||||
{
|
||||
public:
|
||||
EventTimingCodesFramePrivate() :
|
||||
timestampFormat(EventTimingCodesFrame::AbsoluteMilliseconds) {}
|
||||
EventTimingCodesFrame::TimestampFormat timestampFormat;
|
||||
EventTimingCodesFrame::SynchedEventList synchedEvents;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EventTimingCodesFrame::EventTimingCodesFrame() :
|
||||
Frame("ETCO"),
|
||||
d(new EventTimingCodesFramePrivate())
|
||||
{
|
||||
}
|
||||
|
||||
EventTimingCodesFrame::EventTimingCodesFrame(const ByteVector &data) :
|
||||
Frame(data),
|
||||
d(new EventTimingCodesFramePrivate())
|
||||
{
|
||||
setData(data);
|
||||
}
|
||||
|
||||
EventTimingCodesFrame::~EventTimingCodesFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String EventTimingCodesFrame::toString() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
EventTimingCodesFrame::TimestampFormat
|
||||
EventTimingCodesFrame::timestampFormat() const
|
||||
{
|
||||
return d->timestampFormat;
|
||||
}
|
||||
|
||||
EventTimingCodesFrame::SynchedEventList
|
||||
EventTimingCodesFrame::synchedEvents() const
|
||||
{
|
||||
return d->synchedEvents;
|
||||
}
|
||||
|
||||
void EventTimingCodesFrame::setTimestampFormat(
|
||||
EventTimingCodesFrame::TimestampFormat f)
|
||||
{
|
||||
d->timestampFormat = f;
|
||||
}
|
||||
|
||||
void EventTimingCodesFrame::setSynchedEvents(
|
||||
const EventTimingCodesFrame::SynchedEventList &e)
|
||||
{
|
||||
d->synchedEvents = e;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void EventTimingCodesFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
const int end = data.size();
|
||||
if(end < 1) {
|
||||
debug("An event timing codes frame must contain at least 1 byte.");
|
||||
return;
|
||||
}
|
||||
|
||||
d->timestampFormat = TimestampFormat(data[0]);
|
||||
|
||||
int pos = 1;
|
||||
d->synchedEvents.clear();
|
||||
while(pos + 4 < end) {
|
||||
EventType type = static_cast<EventType>(static_cast<unsigned char>(data[pos++]));
|
||||
unsigned int time = data.toUInt(pos, true);
|
||||
pos += 4;
|
||||
d->synchedEvents.append(SynchedEvent(time, type));
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector EventTimingCodesFrame::renderFields() const
|
||||
{
|
||||
ByteVector v;
|
||||
|
||||
v.append(char(d->timestampFormat));
|
||||
for(SynchedEventList::ConstIterator it = d->synchedEvents.begin();
|
||||
it != d->synchedEvents.end();
|
||||
++it) {
|
||||
const SynchedEvent &entry = *it;
|
||||
v.append(char(entry.type));
|
||||
v.append(ByteVector::fromUInt(entry.time));
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
EventTimingCodesFrame::EventTimingCodesFrame(const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new EventTimingCodesFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
|
@ -1,187 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
|
||||
copyright : (C) 2006 by Aaron VonderHaar
|
||||
email : avh4@users.sourceforge.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <taglib/toolkit/tstringlist.h>
|
||||
|
||||
#include <taglib/mpeg/id3v2/frames/generalencapsulatedobjectframe.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFramePrivate
|
||||
{
|
||||
public:
|
||||
GeneralEncapsulatedObjectFramePrivate() : textEncoding(String::Latin1) {}
|
||||
|
||||
String::Type textEncoding;
|
||||
String mimeType;
|
||||
String fileName;
|
||||
String description;
|
||||
ByteVector data;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame() :
|
||||
Frame("GEOB"),
|
||||
d(new GeneralEncapsulatedObjectFramePrivate())
|
||||
{
|
||||
}
|
||||
|
||||
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data) :
|
||||
Frame(data),
|
||||
d(new GeneralEncapsulatedObjectFramePrivate())
|
||||
{
|
||||
setData(data);
|
||||
}
|
||||
|
||||
GeneralEncapsulatedObjectFrame::~GeneralEncapsulatedObjectFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String GeneralEncapsulatedObjectFrame::toString() const
|
||||
{
|
||||
String text = "[" + d->mimeType + "]";
|
||||
|
||||
if(!d->fileName.isEmpty())
|
||||
text += " " + d->fileName;
|
||||
|
||||
if(!d->description.isEmpty())
|
||||
text += " \"" + d->description + "\"";
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
String::Type GeneralEncapsulatedObjectFrame::textEncoding() const
|
||||
{
|
||||
return d->textEncoding;
|
||||
}
|
||||
|
||||
void GeneralEncapsulatedObjectFrame::setTextEncoding(String::Type encoding)
|
||||
{
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
String GeneralEncapsulatedObjectFrame::mimeType() const
|
||||
{
|
||||
return d->mimeType;
|
||||
}
|
||||
|
||||
void GeneralEncapsulatedObjectFrame::setMimeType(const String &type)
|
||||
{
|
||||
d->mimeType = type;
|
||||
}
|
||||
|
||||
String GeneralEncapsulatedObjectFrame::fileName() const
|
||||
{
|
||||
return d->fileName;
|
||||
}
|
||||
|
||||
void GeneralEncapsulatedObjectFrame::setFileName(const String &name)
|
||||
{
|
||||
d->fileName = name;
|
||||
}
|
||||
|
||||
String GeneralEncapsulatedObjectFrame::description() const
|
||||
{
|
||||
return d->description;
|
||||
}
|
||||
|
||||
void GeneralEncapsulatedObjectFrame::setDescription(const String &desc)
|
||||
{
|
||||
d->description = desc;
|
||||
}
|
||||
|
||||
ByteVector GeneralEncapsulatedObjectFrame::object() const
|
||||
{
|
||||
return d->data;
|
||||
}
|
||||
|
||||
void GeneralEncapsulatedObjectFrame::setObject(const ByteVector &data)
|
||||
{
|
||||
d->data = data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void GeneralEncapsulatedObjectFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
if(data.size() < 4) {
|
||||
debug("An object frame must contain at least 4 bytes.");
|
||||
return;
|
||||
}
|
||||
|
||||
d->textEncoding = String::Type(data[0]);
|
||||
|
||||
int pos = 1;
|
||||
|
||||
d->mimeType = readStringField(data, String::Latin1, &pos);
|
||||
d->fileName = readStringField(data, d->textEncoding, &pos);
|
||||
d->description = readStringField(data, d->textEncoding, &pos);
|
||||
|
||||
d->data = data.mid(pos);
|
||||
}
|
||||
|
||||
ByteVector GeneralEncapsulatedObjectFrame::renderFields() const
|
||||
{
|
||||
StringList sl;
|
||||
sl.append(d->fileName);
|
||||
sl.append(d->description);
|
||||
|
||||
const String::Type encoding = checkTextEncoding(sl, d->textEncoding);
|
||||
|
||||
ByteVector data;
|
||||
|
||||
data.append(char(encoding));
|
||||
data.append(d->mimeType.data(String::Latin1));
|
||||
data.append(textDelimiter(String::Latin1));
|
||||
data.append(d->fileName.data(encoding));
|
||||
data.append(textDelimiter(encoding));
|
||||
data.append(d->description.data(encoding));
|
||||
data.append(textDelimiter(encoding));
|
||||
data.append(d->data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new GeneralEncapsulatedObjectFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
|
@ -1,171 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2012 by Rupert Daniel
|
||||
email : rupert@cancelmonday.com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <taglib/toolkit/tstringlist.h>
|
||||
#include <taglib/mpeg/id3v2/id3v2tag.h>
|
||||
|
||||
#include <taglib/mpeg/id3v2/frames/ownershipframe.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class OwnershipFrame::OwnershipFramePrivate
|
||||
{
|
||||
public:
|
||||
String pricePaid;
|
||||
String datePurchased;
|
||||
String seller;
|
||||
String::Type textEncoding;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
OwnershipFrame::OwnershipFrame(String::Type encoding) :
|
||||
Frame("OWNE"),
|
||||
d(new OwnershipFramePrivate())
|
||||
{
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
OwnershipFrame::OwnershipFrame(const ByteVector &data) :
|
||||
Frame(data),
|
||||
d(new OwnershipFramePrivate())
|
||||
{
|
||||
setData(data);
|
||||
}
|
||||
|
||||
OwnershipFrame::~OwnershipFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String OwnershipFrame::toString() const
|
||||
{
|
||||
return "pricePaid=" + d->pricePaid + " datePurchased=" + d->datePurchased + " seller=" + d->seller;
|
||||
}
|
||||
|
||||
String OwnershipFrame::pricePaid() const
|
||||
{
|
||||
return d->pricePaid;
|
||||
}
|
||||
|
||||
void OwnershipFrame::setPricePaid(const String &s)
|
||||
{
|
||||
d->pricePaid = s;
|
||||
}
|
||||
|
||||
String OwnershipFrame::datePurchased() const
|
||||
{
|
||||
return d->datePurchased;
|
||||
}
|
||||
|
||||
void OwnershipFrame::setDatePurchased(const String &s)
|
||||
{
|
||||
d->datePurchased = s;
|
||||
}
|
||||
|
||||
String OwnershipFrame::seller() const
|
||||
{
|
||||
return d->seller;
|
||||
}
|
||||
|
||||
void OwnershipFrame::setSeller(const String &s)
|
||||
{
|
||||
d->seller = s;
|
||||
}
|
||||
|
||||
String::Type OwnershipFrame::textEncoding() const
|
||||
{
|
||||
return d->textEncoding;
|
||||
}
|
||||
|
||||
void OwnershipFrame::setTextEncoding(String::Type encoding)
|
||||
{
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void OwnershipFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
int pos = 0;
|
||||
|
||||
// Get the text encoding
|
||||
d->textEncoding = String::Type(data[0]);
|
||||
pos += 1;
|
||||
|
||||
// Read the price paid this is a null terminate string
|
||||
d->pricePaid = readStringField(data, String::Latin1, &pos);
|
||||
|
||||
// If we don't have at least 8 bytes left then don't parse the rest of the
|
||||
// data
|
||||
if(data.size() - pos < 8) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Read the date purchased YYYYMMDD
|
||||
d->datePurchased = String(data.mid(pos, 8));
|
||||
pos += 8;
|
||||
|
||||
// Read the seller
|
||||
if(d->textEncoding == String::Latin1)
|
||||
d->seller = Tag::latin1StringHandler()->parse(data.mid(pos));
|
||||
else
|
||||
d->seller = String(data.mid(pos), d->textEncoding);
|
||||
}
|
||||
|
||||
ByteVector OwnershipFrame::renderFields() const
|
||||
{
|
||||
StringList sl;
|
||||
sl.append(d->seller);
|
||||
|
||||
const String::Type encoding = checkTextEncoding(sl, d->textEncoding);
|
||||
|
||||
ByteVector v;
|
||||
|
||||
v.append(char(encoding));
|
||||
v.append(d->pricePaid.data(String::Latin1));
|
||||
v.append(textDelimiter(String::Latin1));
|
||||
v.append(d->datePurchased.data(String::Latin1));
|
||||
v.append(d->seller.data(encoding));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
OwnershipFrame::OwnershipFrame(const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new OwnershipFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2015 by Urs Fleisch
|
||||
email : ufleisch@users.sourceforge.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/mpeg/id3v2/frames/podcastframe.h>
|
||||
#include <taglib/toolkit/tpropertymap.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class PodcastFrame::PodcastFramePrivate
|
||||
{
|
||||
public:
|
||||
ByteVector fieldData;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PodcastFrame::PodcastFrame() :
|
||||
Frame("PCST"),
|
||||
d(new PodcastFramePrivate())
|
||||
{
|
||||
d->fieldData = ByteVector(4, '\0');
|
||||
}
|
||||
|
||||
PodcastFrame::~PodcastFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String PodcastFrame::toString() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
PropertyMap PodcastFrame::asProperties() const
|
||||
{
|
||||
PropertyMap map;
|
||||
map.insert("PODCAST", StringList());
|
||||
return map;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PodcastFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
d->fieldData = data;
|
||||
}
|
||||
|
||||
ByteVector PodcastFrame::renderFields() const
|
||||
{
|
||||
return d->fieldData;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PodcastFrame::PodcastFrame(const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new PodcastFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
|
@ -1,140 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2008 by Lukas Lalinsky
|
||||
email : lalinsky@gmail.com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
|
||||
#include <taglib/mpeg/id3v2/frames/popularimeterframe.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class PopularimeterFrame::PopularimeterFramePrivate
|
||||
{
|
||||
public:
|
||||
PopularimeterFramePrivate() : rating(0), counter(0) {}
|
||||
String email;
|
||||
int rating;
|
||||
unsigned int counter;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PopularimeterFrame::PopularimeterFrame() :
|
||||
Frame("POPM"),
|
||||
d(new PopularimeterFramePrivate())
|
||||
{
|
||||
}
|
||||
|
||||
PopularimeterFrame::PopularimeterFrame(const ByteVector &data) :
|
||||
Frame(data),
|
||||
d(new PopularimeterFramePrivate())
|
||||
{
|
||||
setData(data);
|
||||
}
|
||||
|
||||
PopularimeterFrame::~PopularimeterFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String PopularimeterFrame::toString() const
|
||||
{
|
||||
return d->email + " rating=" + String::number(d->rating) + " counter=" + String::number(d->counter);
|
||||
}
|
||||
|
||||
String PopularimeterFrame::email() const
|
||||
{
|
||||
return d->email;
|
||||
}
|
||||
|
||||
void PopularimeterFrame::setEmail(const String &s)
|
||||
{
|
||||
d->email = s;
|
||||
}
|
||||
|
||||
int PopularimeterFrame::rating() const
|
||||
{
|
||||
return d->rating;
|
||||
}
|
||||
|
||||
void PopularimeterFrame::setRating(int s)
|
||||
{
|
||||
d->rating = s;
|
||||
}
|
||||
|
||||
unsigned int PopularimeterFrame::counter() const
|
||||
{
|
||||
return d->counter;
|
||||
}
|
||||
|
||||
void PopularimeterFrame::setCounter(unsigned int s)
|
||||
{
|
||||
d->counter = s;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PopularimeterFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
int pos = 0, size = int(data.size());
|
||||
|
||||
d->email = readStringField(data, String::Latin1, &pos);
|
||||
|
||||
d->rating = 0;
|
||||
d->counter = 0;
|
||||
if(pos < size) {
|
||||
d->rating = (unsigned char)(data[pos++]);
|
||||
if(pos < size) {
|
||||
d->counter = data.toUInt(static_cast<unsigned int>(pos));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector PopularimeterFrame::renderFields() const
|
||||
{
|
||||
ByteVector data;
|
||||
|
||||
data.append(d->email.data(String::Latin1));
|
||||
data.append(textDelimiter(String::Latin1));
|
||||
data.append(char(d->rating));
|
||||
data.append(ByteVector::fromUInt(d->counter));
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PopularimeterFrame::PopularimeterFrame(const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new PopularimeterFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
|
@ -1,131 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2008 by Serkan Kalyoncu
|
||||
copyright : (C) 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/toolkit/tbytevectorlist.h>
|
||||
#include <taglib/mpeg/id3v2/id3v2tag.h>
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
|
||||
#include <taglib/mpeg/id3v2/frames/privateframe.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
|
||||
class PrivateFrame::PrivateFramePrivate
|
||||
{
|
||||
public:
|
||||
ByteVector data;
|
||||
String owner;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PrivateFrame::PrivateFrame() :
|
||||
Frame("PRIV"),
|
||||
d(new PrivateFramePrivate())
|
||||
{
|
||||
}
|
||||
|
||||
PrivateFrame::PrivateFrame(const ByteVector &data) :
|
||||
Frame(data),
|
||||
d(new PrivateFramePrivate())
|
||||
{
|
||||
Frame::setData(data);
|
||||
}
|
||||
|
||||
PrivateFrame::~PrivateFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String PrivateFrame::toString() const
|
||||
{
|
||||
return d->owner;
|
||||
}
|
||||
|
||||
String PrivateFrame::owner() const
|
||||
{
|
||||
return d->owner;
|
||||
}
|
||||
|
||||
ByteVector PrivateFrame::data() const
|
||||
{
|
||||
return d->data;
|
||||
}
|
||||
|
||||
void PrivateFrame::setOwner(const String &s)
|
||||
{
|
||||
d->owner = s;
|
||||
}
|
||||
|
||||
void PrivateFrame::setData(const ByteVector & data)
|
||||
{
|
||||
d->data = data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PrivateFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
if(data.size() < 2) {
|
||||
debug("A private frame must contain at least 2 bytes.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Owner identifier is assumed to be Latin1
|
||||
|
||||
const int byteAlign = 1;
|
||||
const int endOfOwner = data.find(textDelimiter(String::Latin1), 0, byteAlign);
|
||||
|
||||
d->owner = String(data.mid(0, endOfOwner));
|
||||
d->data = data.mid(endOfOwner + 1);
|
||||
}
|
||||
|
||||
ByteVector PrivateFrame::renderFields() const
|
||||
{
|
||||
ByteVector v;
|
||||
|
||||
v.append(d->owner.data(String::Latin1));
|
||||
v.append(textDelimiter(String::Latin1));
|
||||
v.append(d->data);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PrivateFrame::PrivateFrame(const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new PrivateFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
|
@ -1,233 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <taglib/toolkit/tmap.h>
|
||||
|
||||
#include <taglib/mpeg/id3v2/frames/relativevolumeframe.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
struct ChannelData
|
||||
{
|
||||
ChannelData() : channelType(RelativeVolumeFrame::Other), volumeAdjustment(0) {}
|
||||
|
||||
RelativeVolumeFrame::ChannelType channelType;
|
||||
short volumeAdjustment;
|
||||
RelativeVolumeFrame::PeakVolume peakVolume;
|
||||
};
|
||||
|
||||
class RelativeVolumeFrame::RelativeVolumeFramePrivate
|
||||
{
|
||||
public:
|
||||
String identification;
|
||||
Map<ChannelType, ChannelData> channels;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RelativeVolumeFrame::RelativeVolumeFrame() :
|
||||
Frame("RVA2"),
|
||||
d(new RelativeVolumeFramePrivate())
|
||||
{
|
||||
}
|
||||
|
||||
RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data) :
|
||||
Frame(data),
|
||||
d(new RelativeVolumeFramePrivate())
|
||||
{
|
||||
setData(data);
|
||||
}
|
||||
|
||||
RelativeVolumeFrame::~RelativeVolumeFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String RelativeVolumeFrame::toString() const
|
||||
{
|
||||
return d->identification;
|
||||
}
|
||||
|
||||
List<RelativeVolumeFrame::ChannelType> RelativeVolumeFrame::channels() const
|
||||
{
|
||||
List<ChannelType> l;
|
||||
|
||||
Map<ChannelType, ChannelData>::ConstIterator it = d->channels.begin();
|
||||
for(; it != d->channels.end(); ++it)
|
||||
l.append((*it).first);
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
// deprecated
|
||||
|
||||
RelativeVolumeFrame::ChannelType RelativeVolumeFrame::channelType() const
|
||||
{
|
||||
return MasterVolume;
|
||||
}
|
||||
|
||||
// deprecated
|
||||
|
||||
void RelativeVolumeFrame::setChannelType(ChannelType)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
short RelativeVolumeFrame::volumeAdjustmentIndex(ChannelType type) const
|
||||
{
|
||||
return d->channels.contains(type) ? d->channels[type].volumeAdjustment : 0;
|
||||
}
|
||||
|
||||
short RelativeVolumeFrame::volumeAdjustmentIndex() const
|
||||
{
|
||||
return volumeAdjustmentIndex(MasterVolume);
|
||||
}
|
||||
|
||||
void RelativeVolumeFrame::setVolumeAdjustmentIndex(short index, ChannelType type)
|
||||
{
|
||||
d->channels[type].volumeAdjustment = index;
|
||||
}
|
||||
|
||||
void RelativeVolumeFrame::setVolumeAdjustmentIndex(short index)
|
||||
{
|
||||
setVolumeAdjustmentIndex(index, MasterVolume);
|
||||
}
|
||||
|
||||
float RelativeVolumeFrame::volumeAdjustment(ChannelType type) const
|
||||
{
|
||||
return d->channels.contains(type) ? float(d->channels[type].volumeAdjustment) / float(512) : 0;
|
||||
}
|
||||
|
||||
float RelativeVolumeFrame::volumeAdjustment() const
|
||||
{
|
||||
return volumeAdjustment(MasterVolume);
|
||||
}
|
||||
|
||||
void RelativeVolumeFrame::setVolumeAdjustment(float adjustment, ChannelType type)
|
||||
{
|
||||
d->channels[type].volumeAdjustment = short(adjustment * float(512));
|
||||
}
|
||||
|
||||
void RelativeVolumeFrame::setVolumeAdjustment(float adjustment)
|
||||
{
|
||||
setVolumeAdjustment(adjustment, MasterVolume);
|
||||
}
|
||||
|
||||
RelativeVolumeFrame::PeakVolume RelativeVolumeFrame::peakVolume(ChannelType type) const
|
||||
{
|
||||
return d->channels.contains(type) ? d->channels[type].peakVolume : PeakVolume();
|
||||
}
|
||||
|
||||
RelativeVolumeFrame::PeakVolume RelativeVolumeFrame::peakVolume() const
|
||||
{
|
||||
return peakVolume(MasterVolume);
|
||||
}
|
||||
|
||||
void RelativeVolumeFrame::setPeakVolume(const PeakVolume &peak, ChannelType type)
|
||||
{
|
||||
d->channels[type].peakVolume = peak;
|
||||
}
|
||||
|
||||
void RelativeVolumeFrame::setPeakVolume(const PeakVolume &peak)
|
||||
{
|
||||
setPeakVolume(peak, MasterVolume);
|
||||
}
|
||||
|
||||
String RelativeVolumeFrame::identification() const
|
||||
{
|
||||
return d->identification;
|
||||
}
|
||||
|
||||
void RelativeVolumeFrame::setIdentification(const String &s)
|
||||
{
|
||||
d->identification = s;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void RelativeVolumeFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
int pos = 0;
|
||||
d->identification = readStringField(data, String::Latin1, &pos);
|
||||
|
||||
// Each channel is at least 4 bytes.
|
||||
|
||||
while(pos <= (int)data.size() - 4) {
|
||||
|
||||
ChannelType type = ChannelType(data[pos]);
|
||||
pos += 1;
|
||||
|
||||
ChannelData &channel = d->channels[type];
|
||||
|
||||
channel.volumeAdjustment = data.toShort(static_cast<unsigned int>(pos));
|
||||
pos += 2;
|
||||
|
||||
channel.peakVolume.bitsRepresentingPeak = data[pos];
|
||||
pos += 1;
|
||||
|
||||
const int bytes = (channel.peakVolume.bitsRepresentingPeak + 7) / 8;
|
||||
channel.peakVolume.peakVolume = data.mid(pos, bytes);
|
||||
pos += bytes;
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector RelativeVolumeFrame::renderFields() const
|
||||
{
|
||||
ByteVector data;
|
||||
|
||||
data.append(d->identification.data(String::Latin1));
|
||||
data.append(textDelimiter(String::Latin1));
|
||||
|
||||
Map<ChannelType, ChannelData>::ConstIterator it = d->channels.begin();
|
||||
|
||||
for(; it != d->channels.end(); ++it) {
|
||||
ChannelType type = (*it).first;
|
||||
const ChannelData &channel = (*it).second;
|
||||
|
||||
data.append(char(type));
|
||||
data.append(ByteVector::fromShort(channel.volumeAdjustment));
|
||||
data.append(char(channel.peakVolume.bitsRepresentingPeak));
|
||||
data.append(channel.peakVolume.peakVolume);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new RelativeVolumeFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
|
@ -1,242 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2014 by Urs Fleisch
|
||||
email : ufleisch@users.sourceforge.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/mpeg/id3v2/frames/synchronizedlyricsframe.h>
|
||||
#include <taglib/toolkit/tbytevectorlist.h>
|
||||
#include <taglib/mpeg/id3v2/id3v2tag.h>
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <taglib/toolkit/tpropertymap.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class SynchronizedLyricsFrame::SynchronizedLyricsFramePrivate
|
||||
{
|
||||
public:
|
||||
SynchronizedLyricsFramePrivate() :
|
||||
textEncoding(String::Latin1),
|
||||
timestampFormat(SynchronizedLyricsFrame::AbsoluteMilliseconds),
|
||||
type(SynchronizedLyricsFrame::Lyrics) {}
|
||||
String::Type textEncoding;
|
||||
ByteVector language;
|
||||
SynchronizedLyricsFrame::TimestampFormat timestampFormat;
|
||||
SynchronizedLyricsFrame::Type type;
|
||||
String description;
|
||||
SynchronizedLyricsFrame::SynchedTextList synchedText;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SynchronizedLyricsFrame::SynchronizedLyricsFrame(String::Type encoding) :
|
||||
Frame("SYLT"),
|
||||
d(new SynchronizedLyricsFramePrivate())
|
||||
{
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
SynchronizedLyricsFrame::SynchronizedLyricsFrame(const ByteVector &data) :
|
||||
Frame(data),
|
||||
d(new SynchronizedLyricsFramePrivate())
|
||||
{
|
||||
setData(data);
|
||||
}
|
||||
|
||||
SynchronizedLyricsFrame::~SynchronizedLyricsFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String SynchronizedLyricsFrame::toString() const
|
||||
{
|
||||
return d->description;
|
||||
}
|
||||
|
||||
String::Type SynchronizedLyricsFrame::textEncoding() const
|
||||
{
|
||||
return d->textEncoding;
|
||||
}
|
||||
|
||||
ByteVector SynchronizedLyricsFrame::language() const
|
||||
{
|
||||
return d->language;
|
||||
}
|
||||
|
||||
SynchronizedLyricsFrame::TimestampFormat
|
||||
SynchronizedLyricsFrame::timestampFormat() const
|
||||
{
|
||||
return d->timestampFormat;
|
||||
}
|
||||
|
||||
SynchronizedLyricsFrame::Type SynchronizedLyricsFrame::type() const
|
||||
{
|
||||
return d->type;
|
||||
}
|
||||
|
||||
String SynchronizedLyricsFrame::description() const
|
||||
{
|
||||
return d->description;
|
||||
}
|
||||
|
||||
SynchronizedLyricsFrame::SynchedTextList
|
||||
SynchronizedLyricsFrame::synchedText() const
|
||||
{
|
||||
return d->synchedText;
|
||||
}
|
||||
|
||||
void SynchronizedLyricsFrame::setTextEncoding(String::Type encoding)
|
||||
{
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
void SynchronizedLyricsFrame::setLanguage(const ByteVector &languageEncoding)
|
||||
{
|
||||
d->language = languageEncoding.mid(0, 3);
|
||||
}
|
||||
|
||||
void SynchronizedLyricsFrame::setTimestampFormat(SynchronizedLyricsFrame::TimestampFormat f)
|
||||
{
|
||||
d->timestampFormat = f;
|
||||
}
|
||||
|
||||
void SynchronizedLyricsFrame::setType(SynchronizedLyricsFrame::Type t)
|
||||
{
|
||||
d->type = t;
|
||||
}
|
||||
|
||||
void SynchronizedLyricsFrame::setDescription(const String &s)
|
||||
{
|
||||
d->description = s;
|
||||
}
|
||||
|
||||
void SynchronizedLyricsFrame::setSynchedText(
|
||||
const SynchronizedLyricsFrame::SynchedTextList &t)
|
||||
{
|
||||
d->synchedText = t;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SynchronizedLyricsFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
const int end = data.size();
|
||||
if(end < 7) {
|
||||
debug("A synchronized lyrics frame must contain at least 7 bytes.");
|
||||
return;
|
||||
}
|
||||
|
||||
d->textEncoding = String::Type(data[0]);
|
||||
d->language = data.mid(1, 3);
|
||||
d->timestampFormat = TimestampFormat(data[4]);
|
||||
d->type = Type(data[5]);
|
||||
|
||||
int pos = 6;
|
||||
|
||||
d->description = readStringField(data, d->textEncoding, &pos);
|
||||
if(pos == 6)
|
||||
return;
|
||||
|
||||
/*
|
||||
* If UTF16 strings are found in SYLT frames, a BOM may only be
|
||||
* present in the first string (content descriptor), and the strings of
|
||||
* the synchronized text have no BOM. Here the BOM is read from
|
||||
* the first string to have a specific encoding with endianness for the
|
||||
* case of strings without BOM so that readStringField() will work.
|
||||
*/
|
||||
String::Type encWithEndianness = d->textEncoding;
|
||||
if(d->textEncoding == String::UTF16) {
|
||||
unsigned short bom = data.toUShort(6, true);
|
||||
if(bom == 0xfffe) {
|
||||
encWithEndianness = String::UTF16LE;
|
||||
} else if(bom == 0xfeff) {
|
||||
encWithEndianness = String::UTF16BE;
|
||||
}
|
||||
}
|
||||
|
||||
d->synchedText.clear();
|
||||
while(pos < end) {
|
||||
String::Type enc = d->textEncoding;
|
||||
// If a UTF16 string has no BOM, use the encoding found above.
|
||||
if(enc == String::UTF16 && pos + 1 < end) {
|
||||
unsigned short bom = data.toUShort(pos, true);
|
||||
if(bom != 0xfffe && bom != 0xfeff) {
|
||||
enc = encWithEndianness;
|
||||
}
|
||||
}
|
||||
String text = readStringField(data, enc, &pos);
|
||||
if(pos + 4 > end)
|
||||
return;
|
||||
|
||||
unsigned int time = data.toUInt(pos, true);
|
||||
pos += 4;
|
||||
|
||||
d->synchedText.append(SynchedText(time, text));
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector SynchronizedLyricsFrame::renderFields() const
|
||||
{
|
||||
ByteVector v;
|
||||
|
||||
String::Type encoding = d->textEncoding;
|
||||
|
||||
encoding = checkTextEncoding(d->description, encoding);
|
||||
for(SynchedTextList::ConstIterator it = d->synchedText.begin();
|
||||
it != d->synchedText.end();
|
||||
++it) {
|
||||
encoding = checkTextEncoding(it->text, encoding);
|
||||
}
|
||||
|
||||
v.append(char(encoding));
|
||||
v.append(d->language.size() == 3 ? d->language : "XXX");
|
||||
v.append(char(d->timestampFormat));
|
||||
v.append(char(d->type));
|
||||
v.append(d->description.data(encoding));
|
||||
v.append(textDelimiter(encoding));
|
||||
for(SynchedTextList::ConstIterator it = d->synchedText.begin();
|
||||
it != d->synchedText.end();
|
||||
++it) {
|
||||
const SynchedText &entry = *it;
|
||||
v.append(entry.text.data(encoding));
|
||||
v.append(textDelimiter(encoding));
|
||||
v.append(ByteVector::fromUInt(entry.time));
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SynchronizedLyricsFrame::SynchronizedLyricsFrame(const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new SynchronizedLyricsFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
|
@ -1,360 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2013 by Lukas Krejci
|
||||
email : krejclu6@fel.cvut.cz
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/toolkit/tbytevectorlist.h>
|
||||
#include <taglib/toolkit/tpropertymap.h>
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
|
||||
#include <taglib/mpeg/id3v2/frames/tableofcontentsframe.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class TableOfContentsFrame::TableOfContentsFramePrivate
|
||||
{
|
||||
public:
|
||||
TableOfContentsFramePrivate() :
|
||||
tagHeader(0),
|
||||
isTopLevel(false),
|
||||
isOrdered(false)
|
||||
{
|
||||
embeddedFrameList.setAutoDelete(true);
|
||||
}
|
||||
|
||||
const ID3v2::Header *tagHeader;
|
||||
ByteVector elementID;
|
||||
bool isTopLevel;
|
||||
bool isOrdered;
|
||||
ByteVectorList childElements;
|
||||
FrameListMap embeddedFrameListMap;
|
||||
FrameList embeddedFrameList;
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
// These functions are needed to try to aim for backward compatibility with
|
||||
// an API that previously (unreasonably) required null bytes to be appended
|
||||
// at the end of identifiers explicitly by the API user.
|
||||
|
||||
// BIC: remove these
|
||||
|
||||
ByteVector &strip(ByteVector &b)
|
||||
{
|
||||
if(b.endsWith('\0'))
|
||||
b.resize(b.size() - 1);
|
||||
return b;
|
||||
}
|
||||
|
||||
ByteVectorList &strip(ByteVectorList &l)
|
||||
{
|
||||
for(ByteVectorList::Iterator it = l.begin(); it != l.end(); ++it)
|
||||
{
|
||||
strip(*it);
|
||||
}
|
||||
return l;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TableOfContentsFrame::TableOfContentsFrame(const ID3v2::Header *tagHeader, const ByteVector &data) :
|
||||
ID3v2::Frame(data),
|
||||
d(new TableOfContentsFramePrivate())
|
||||
{
|
||||
d->tagHeader = tagHeader;
|
||||
setData(data);
|
||||
}
|
||||
|
||||
TableOfContentsFrame::TableOfContentsFrame(const ByteVector &elementID,
|
||||
const ByteVectorList &children,
|
||||
const FrameList &embeddedFrames) :
|
||||
ID3v2::Frame("CTOC"),
|
||||
d(new TableOfContentsFramePrivate())
|
||||
{
|
||||
d->elementID = elementID;
|
||||
strip(d->elementID);
|
||||
d->childElements = children;
|
||||
|
||||
for(FrameList::ConstIterator it = embeddedFrames.begin(); it != embeddedFrames.end(); ++it)
|
||||
addEmbeddedFrame(*it);
|
||||
}
|
||||
|
||||
TableOfContentsFrame::~TableOfContentsFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
ByteVector TableOfContentsFrame::elementID() const
|
||||
{
|
||||
return d->elementID;
|
||||
}
|
||||
|
||||
bool TableOfContentsFrame::isTopLevel() const
|
||||
{
|
||||
return d->isTopLevel;
|
||||
}
|
||||
|
||||
bool TableOfContentsFrame::isOrdered() const
|
||||
{
|
||||
return d->isOrdered;
|
||||
}
|
||||
|
||||
unsigned int TableOfContentsFrame::entryCount() const
|
||||
{
|
||||
return d->childElements.size();
|
||||
}
|
||||
|
||||
ByteVectorList TableOfContentsFrame::childElements() const
|
||||
{
|
||||
return d->childElements;
|
||||
}
|
||||
|
||||
void TableOfContentsFrame::setElementID(const ByteVector &eID)
|
||||
{
|
||||
d->elementID = eID;
|
||||
strip(d->elementID);
|
||||
}
|
||||
|
||||
void TableOfContentsFrame::setIsTopLevel(const bool &t)
|
||||
{
|
||||
d->isTopLevel = t;
|
||||
}
|
||||
|
||||
void TableOfContentsFrame::setIsOrdered(const bool &o)
|
||||
{
|
||||
d->isOrdered = o;
|
||||
}
|
||||
|
||||
void TableOfContentsFrame::setChildElements(const ByteVectorList &l)
|
||||
{
|
||||
d->childElements = l;
|
||||
strip(d->childElements);
|
||||
}
|
||||
|
||||
void TableOfContentsFrame::addChildElement(const ByteVector &cE)
|
||||
{
|
||||
d->childElements.append(cE);
|
||||
strip(d->childElements);
|
||||
}
|
||||
|
||||
void TableOfContentsFrame::removeChildElement(const ByteVector &cE)
|
||||
{
|
||||
ByteVectorList::Iterator it = d->childElements.find(cE);
|
||||
|
||||
if(it == d->childElements.end())
|
||||
it = d->childElements.find(cE + ByteVector("\0"));
|
||||
|
||||
if(it != d->childElements.end())
|
||||
d->childElements.erase(it);
|
||||
}
|
||||
|
||||
const FrameListMap &TableOfContentsFrame::embeddedFrameListMap() const
|
||||
{
|
||||
return d->embeddedFrameListMap;
|
||||
}
|
||||
|
||||
const FrameList &TableOfContentsFrame::embeddedFrameList() const
|
||||
{
|
||||
return d->embeddedFrameList;
|
||||
}
|
||||
|
||||
const FrameList &TableOfContentsFrame::embeddedFrameList(const ByteVector &frameID) const
|
||||
{
|
||||
return d->embeddedFrameListMap[frameID];
|
||||
}
|
||||
|
||||
void TableOfContentsFrame::addEmbeddedFrame(Frame *frame)
|
||||
{
|
||||
d->embeddedFrameList.append(frame);
|
||||
d->embeddedFrameListMap[frame->frameID()].append(frame);
|
||||
}
|
||||
|
||||
void TableOfContentsFrame::removeEmbeddedFrame(Frame *frame, bool del)
|
||||
{
|
||||
// remove the frame from the frame list
|
||||
FrameList::Iterator it = d->embeddedFrameList.find(frame);
|
||||
if(it != d->embeddedFrameList.end())
|
||||
d->embeddedFrameList.erase(it);
|
||||
|
||||
// ...and from the frame list map
|
||||
FrameList &mappedList = d->embeddedFrameListMap[frame->frameID()];
|
||||
it = mappedList.find(frame);
|
||||
if(it != mappedList.end())
|
||||
mappedList.erase(it);
|
||||
|
||||
// ...and delete as desired
|
||||
if(del)
|
||||
delete frame;
|
||||
}
|
||||
|
||||
void TableOfContentsFrame::removeEmbeddedFrames(const ByteVector &id)
|
||||
{
|
||||
FrameList l = d->embeddedFrameListMap[id];
|
||||
for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it)
|
||||
removeEmbeddedFrame(*it, true);
|
||||
}
|
||||
|
||||
String TableOfContentsFrame::toString() const
|
||||
{
|
||||
String s = String(d->elementID) +
|
||||
": top level: " + (d->isTopLevel ? "true" : "false") +
|
||||
", ordered: " + (d->isOrdered ? "true" : "false");
|
||||
|
||||
if(!d->childElements.isEmpty()) {
|
||||
s+= ", chapters: [ " + String(d->childElements.toByteVector(", ")) + " ]";
|
||||
}
|
||||
|
||||
if(!d->embeddedFrameList.isEmpty()) {
|
||||
StringList frameIDs;
|
||||
for(FrameList::ConstIterator it = d->embeddedFrameList.begin();
|
||||
it != d->embeddedFrameList.end(); ++it)
|
||||
frameIDs.append((*it)->frameID());
|
||||
s += ", sub-frames: [ " + frameIDs.toString(", ") + " ]";
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
PropertyMap TableOfContentsFrame::asProperties() const
|
||||
{
|
||||
PropertyMap map;
|
||||
|
||||
map.unsupportedData().append(frameID() + String("/") + d->elementID);
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
TableOfContentsFrame *TableOfContentsFrame::findByElementID(const ID3v2::Tag *tag,
|
||||
const ByteVector &eID) // static
|
||||
{
|
||||
ID3v2::FrameList tablesOfContents = tag->frameList("CTOC");
|
||||
|
||||
for(ID3v2::FrameList::ConstIterator it = tablesOfContents.begin();
|
||||
it != tablesOfContents.end();
|
||||
++it)
|
||||
{
|
||||
TableOfContentsFrame *frame = dynamic_cast<TableOfContentsFrame *>(*it);
|
||||
if(frame && frame->elementID() == eID)
|
||||
return frame;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
TableOfContentsFrame *TableOfContentsFrame::findTopLevel(const ID3v2::Tag *tag) // static
|
||||
{
|
||||
ID3v2::FrameList tablesOfContents = tag->frameList("CTOC");
|
||||
|
||||
for(ID3v2::FrameList::ConstIterator it = tablesOfContents.begin();
|
||||
it != tablesOfContents.end();
|
||||
++it)
|
||||
{
|
||||
TableOfContentsFrame *frame = dynamic_cast<TableOfContentsFrame *>(*it);
|
||||
if(frame && frame->isTopLevel() == true)
|
||||
return frame;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TableOfContentsFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
unsigned int size = data.size();
|
||||
if(size < 6) {
|
||||
debug("A CTOC frame must contain at least 6 bytes (1 byte element ID terminated by "
|
||||
"null, 1 byte flags, 1 byte entry count and 1 byte child element ID terminated "
|
||||
"by null.");
|
||||
return;
|
||||
}
|
||||
|
||||
int pos = 0;
|
||||
unsigned int embPos = 0;
|
||||
d->elementID = readStringField(data, String::Latin1, &pos).data(String::Latin1);
|
||||
d->isTopLevel = (data.at(pos) & 2) != 0;
|
||||
d->isOrdered = (data.at(pos++) & 1) != 0;
|
||||
unsigned int entryCount = static_cast<unsigned char>(data.at(pos++));
|
||||
for(unsigned int i = 0; i < entryCount; i++) {
|
||||
ByteVector childElementID = readStringField(data, String::Latin1, &pos).data(String::Latin1);
|
||||
d->childElements.append(childElementID);
|
||||
}
|
||||
|
||||
size -= pos;
|
||||
|
||||
if(size < header()->size())
|
||||
return;
|
||||
|
||||
while(embPos < size - header()->size()) {
|
||||
Frame *frame = FrameFactory::instance()->createFrame(data.mid(pos + embPos), d->tagHeader);
|
||||
|
||||
if(!frame)
|
||||
return;
|
||||
|
||||
// Checks to make sure that frame parsed correctly.
|
||||
if(frame->size() <= 0) {
|
||||
delete frame;
|
||||
return;
|
||||
}
|
||||
|
||||
embPos += frame->size() + header()->size();
|
||||
addEmbeddedFrame(frame);
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector TableOfContentsFrame::renderFields() const
|
||||
{
|
||||
ByteVector data;
|
||||
|
||||
data.append(d->elementID);
|
||||
data.append('\0');
|
||||
char flags = 0;
|
||||
if(d->isTopLevel)
|
||||
flags += 2;
|
||||
if(d->isOrdered)
|
||||
flags += 1;
|
||||
data.append(flags);
|
||||
data.append((char)(entryCount()));
|
||||
ByteVectorList::ConstIterator it = d->childElements.begin();
|
||||
while(it != d->childElements.end()) {
|
||||
data.append(*it);
|
||||
data.append('\0');
|
||||
it++;
|
||||
}
|
||||
FrameList l = d->embeddedFrameList;
|
||||
for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it)
|
||||
data.append((*it)->render());
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
TableOfContentsFrame::TableOfContentsFrame(const ID3v2::Header *tagHeader,
|
||||
const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new TableOfContentsFramePrivate())
|
||||
{
|
||||
d->tagHeader = tagHeader;
|
||||
parseFields(fieldData(data));
|
||||
}
|
|
@ -1,437 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/toolkit/tbytevectorlist.h>
|
||||
#include <taglib/mpeg/id3v2/id3v2tag.h>
|
||||
#include <taglib/mpeg/id3v2/frames/textidentificationframe.h>
|
||||
#include <taglib/toolkit/tpropertymap.h>
|
||||
#include <taglib/mpeg/id3v1/id3v1genres.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class TextIdentificationFrame::TextIdentificationFramePrivate
|
||||
{
|
||||
public:
|
||||
TextIdentificationFramePrivate() : textEncoding(String::Latin1) {}
|
||||
String::Type textEncoding;
|
||||
StringList fieldList;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// TextIdentificationFrame public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TextIdentificationFrame::TextIdentificationFrame(const ByteVector &type, String::Type encoding) :
|
||||
Frame(type),
|
||||
d(new TextIdentificationFramePrivate())
|
||||
{
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data) :
|
||||
Frame(data),
|
||||
d(new TextIdentificationFramePrivate())
|
||||
{
|
||||
setData(data);
|
||||
}
|
||||
|
||||
TextIdentificationFrame *TextIdentificationFrame::createTIPLFrame(const PropertyMap &properties) // static
|
||||
{
|
||||
TextIdentificationFrame *frame = new TextIdentificationFrame("TIPL");
|
||||
StringList l;
|
||||
for(PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it){
|
||||
const String role = involvedPeopleMap()[it->first];
|
||||
if(role.isEmpty()) // should not happen
|
||||
continue;
|
||||
l.append(role);
|
||||
l.append(it->second.toString(",")); // comma-separated list of names
|
||||
}
|
||||
frame->setText(l);
|
||||
return frame;
|
||||
}
|
||||
|
||||
TextIdentificationFrame *TextIdentificationFrame::createTMCLFrame(const PropertyMap &properties) // static
|
||||
{
|
||||
TextIdentificationFrame *frame = new TextIdentificationFrame("TMCL");
|
||||
StringList l;
|
||||
for(PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it){
|
||||
if(!it->first.startsWith(instrumentPrefix)) // should not happen
|
||||
continue;
|
||||
l.append(it->first.substr(instrumentPrefix.size()));
|
||||
l.append(it->second.toString(","));
|
||||
}
|
||||
frame->setText(l);
|
||||
return frame;
|
||||
}
|
||||
|
||||
TextIdentificationFrame::~TextIdentificationFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void TextIdentificationFrame::setText(const StringList &l)
|
||||
{
|
||||
d->fieldList = l;
|
||||
}
|
||||
|
||||
void TextIdentificationFrame::setText(const String &s)
|
||||
{
|
||||
d->fieldList = s;
|
||||
}
|
||||
|
||||
String TextIdentificationFrame::toString() const
|
||||
{
|
||||
return d->fieldList.toString();
|
||||
}
|
||||
|
||||
StringList TextIdentificationFrame::fieldList() const
|
||||
{
|
||||
return d->fieldList;
|
||||
}
|
||||
|
||||
String::Type TextIdentificationFrame::textEncoding() const
|
||||
{
|
||||
return d->textEncoding;
|
||||
}
|
||||
|
||||
void TextIdentificationFrame::setTextEncoding(String::Type encoding)
|
||||
{
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
// array of allowed TIPL prefixes and their corresponding key value
|
||||
const char* involvedPeople[][2] = {
|
||||
{"ARRANGER", "ARRANGER"},
|
||||
{"ENGINEER", "ENGINEER"},
|
||||
{"PRODUCER", "PRODUCER"},
|
||||
{"DJ-MIX", "DJMIXER"},
|
||||
{"MIX", "MIXER"},
|
||||
};
|
||||
const size_t involvedPeopleSize = sizeof(involvedPeople) / sizeof(involvedPeople[0]);
|
||||
}
|
||||
|
||||
const KeyConversionMap &TextIdentificationFrame::involvedPeopleMap() // static
|
||||
{
|
||||
static KeyConversionMap m;
|
||||
if(m.isEmpty()) {
|
||||
for(size_t i = 0; i < involvedPeopleSize; ++i)
|
||||
m.insert(involvedPeople[i][1], involvedPeople[i][0]);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
PropertyMap TextIdentificationFrame::asProperties() const
|
||||
{
|
||||
if(frameID() == "TIPL")
|
||||
return makeTIPLProperties();
|
||||
if(frameID() == "TMCL")
|
||||
return makeTMCLProperties();
|
||||
PropertyMap map;
|
||||
String tagName = frameIDToKey(frameID());
|
||||
if(tagName.isEmpty()) {
|
||||
map.unsupportedData().append(frameID());
|
||||
return map;
|
||||
}
|
||||
StringList values = fieldList();
|
||||
if(tagName == "GENRE") {
|
||||
// Special case: Support ID3v1-style genre numbers. They are not officially supported in
|
||||
// ID3v2, however it seems that still a lot of programs use them.
|
||||
for(StringList::Iterator it = values.begin(); it != values.end(); ++it) {
|
||||
bool ok = false;
|
||||
int test = it->toInt(&ok); // test if the genre value is an integer
|
||||
if(ok)
|
||||
*it = ID3v1::genre(test);
|
||||
}
|
||||
} else if(tagName == "DATE") {
|
||||
for(StringList::Iterator it = values.begin(); it != values.end(); ++it) {
|
||||
// ID3v2 specifies ISO8601 timestamps which contain a 'T' as separator between date and time.
|
||||
// Since this is unusual in other formats, the T is removed.
|
||||
int tpos = it->find("T");
|
||||
if(tpos != -1)
|
||||
(*it)[tpos] = ' ';
|
||||
}
|
||||
}
|
||||
PropertyMap ret;
|
||||
ret.insert(tagName, values);
|
||||
return ret;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// TextIdentificationFrame protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TextIdentificationFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
// Don't try to parse invalid frames
|
||||
|
||||
if(data.size() < 2)
|
||||
return;
|
||||
|
||||
// read the string data type (the first byte of the field data)
|
||||
|
||||
d->textEncoding = String::Type(data[0]);
|
||||
|
||||
// split the byte array into chunks based on the string type (two byte delimiter
|
||||
// for unicode encodings)
|
||||
|
||||
int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
|
||||
|
||||
// build a small counter to strip nulls off the end of the field
|
||||
|
||||
int dataLength = data.size() - 1;
|
||||
|
||||
while(dataLength > 0 && data[dataLength] == 0)
|
||||
dataLength--;
|
||||
|
||||
while(dataLength % byteAlign != 0)
|
||||
dataLength++;
|
||||
|
||||
ByteVectorList l = ByteVectorList::split(data.mid(1, dataLength), textDelimiter(d->textEncoding), byteAlign);
|
||||
|
||||
d->fieldList.clear();
|
||||
|
||||
// append those split values to the list and make sure that the new string's
|
||||
// type is the same specified for this frame
|
||||
|
||||
for(ByteVectorList::ConstIterator it = l.begin(); it != l.end(); it++) {
|
||||
if(!(*it).isEmpty()) {
|
||||
if(d->textEncoding == String::Latin1)
|
||||
d->fieldList.append(Tag::latin1StringHandler()->parse(*it));
|
||||
else
|
||||
d->fieldList.append(String(*it, d->textEncoding));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector TextIdentificationFrame::renderFields() const
|
||||
{
|
||||
String::Type encoding = checkTextEncoding(d->fieldList, d->textEncoding);
|
||||
|
||||
ByteVector v;
|
||||
|
||||
v.append(char(encoding));
|
||||
|
||||
for(StringList::ConstIterator it = d->fieldList.begin(); it != d->fieldList.end(); it++) {
|
||||
|
||||
// Since the field list is null delimited, if this is not the first
|
||||
// element in the list, append the appropriate delimiter for this
|
||||
// encoding.
|
||||
|
||||
if(it != d->fieldList.begin())
|
||||
v.append(textDelimiter(encoding));
|
||||
|
||||
v.append((*it).data(encoding));
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// TextIdentificationFrame private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new TextIdentificationFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
|
||||
PropertyMap TextIdentificationFrame::makeTIPLProperties() const
|
||||
{
|
||||
PropertyMap map;
|
||||
if(fieldList().size() % 2 != 0){
|
||||
// according to the ID3 spec, TIPL must contain an even number of entries
|
||||
map.unsupportedData().append(frameID());
|
||||
return map;
|
||||
}
|
||||
StringList l = fieldList();
|
||||
for(StringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
|
||||
bool found = false;
|
||||
for(size_t i = 0; i < involvedPeopleSize; ++i)
|
||||
if(*it == involvedPeople[i][0]) {
|
||||
map.insert(involvedPeople[i][1], (++it)->split(","));
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if(!found){
|
||||
// invalid involved role -> mark whole frame as unsupported in order to be consistent with writing
|
||||
map.clear();
|
||||
map.unsupportedData().append(frameID());
|
||||
return map;
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
PropertyMap TextIdentificationFrame::makeTMCLProperties() const
|
||||
{
|
||||
PropertyMap map;
|
||||
if(fieldList().size() % 2 != 0){
|
||||
// according to the ID3 spec, TMCL must contain an even number of entries
|
||||
map.unsupportedData().append(frameID());
|
||||
return map;
|
||||
}
|
||||
StringList l = fieldList();
|
||||
for(StringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
|
||||
String instrument = it->upper();
|
||||
if(instrument.isEmpty()) {
|
||||
// instrument is not a valid key -> frame unsupported
|
||||
map.clear();
|
||||
map.unsupportedData().append(frameID());
|
||||
return map;
|
||||
}
|
||||
map.insert(L"PERFORMER:" + instrument, (++it)->split(","));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// UserTextIdentificationFrame public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
UserTextIdentificationFrame::UserTextIdentificationFrame(String::Type encoding) :
|
||||
TextIdentificationFrame("TXXX", encoding),
|
||||
d(0)
|
||||
{
|
||||
StringList l;
|
||||
l.append(String());
|
||||
l.append(String());
|
||||
setText(l);
|
||||
}
|
||||
|
||||
|
||||
UserTextIdentificationFrame::UserTextIdentificationFrame(const ByteVector &data) :
|
||||
TextIdentificationFrame(data)
|
||||
{
|
||||
checkFields();
|
||||
}
|
||||
|
||||
UserTextIdentificationFrame::UserTextIdentificationFrame(const String &description, const StringList &values, String::Type encoding) :
|
||||
TextIdentificationFrame("TXXX", encoding),
|
||||
d(0)
|
||||
{
|
||||
setDescription(description);
|
||||
setText(values);
|
||||
}
|
||||
|
||||
String UserTextIdentificationFrame::toString() const
|
||||
{
|
||||
// first entry is the description itself, drop from values list
|
||||
StringList l = fieldList();
|
||||
for(StringList::Iterator it = l.begin(); it != l.end(); ++it) {
|
||||
l.erase(it);
|
||||
break;
|
||||
}
|
||||
return "[" + description() + "] " + l.toString();
|
||||
}
|
||||
|
||||
String UserTextIdentificationFrame::description() const
|
||||
{
|
||||
return !TextIdentificationFrame::fieldList().isEmpty()
|
||||
? TextIdentificationFrame::fieldList().front()
|
||||
: String();
|
||||
}
|
||||
|
||||
StringList UserTextIdentificationFrame::fieldList() const
|
||||
{
|
||||
// TODO: remove this function
|
||||
|
||||
return TextIdentificationFrame::fieldList();
|
||||
}
|
||||
|
||||
void UserTextIdentificationFrame::setText(const String &text)
|
||||
{
|
||||
if(description().isEmpty())
|
||||
setDescription(String());
|
||||
|
||||
TextIdentificationFrame::setText(StringList(description()).append(text));
|
||||
}
|
||||
|
||||
void UserTextIdentificationFrame::setText(const StringList &fields)
|
||||
{
|
||||
if(description().isEmpty())
|
||||
setDescription(String());
|
||||
|
||||
TextIdentificationFrame::setText(StringList(description()).append(fields));
|
||||
}
|
||||
|
||||
void UserTextIdentificationFrame::setDescription(const String &s)
|
||||
{
|
||||
StringList l = fieldList();
|
||||
|
||||
if(l.isEmpty())
|
||||
l.append(s);
|
||||
else
|
||||
l[0] = s;
|
||||
|
||||
TextIdentificationFrame::setText(l);
|
||||
}
|
||||
|
||||
PropertyMap UserTextIdentificationFrame::asProperties() const
|
||||
{
|
||||
PropertyMap map;
|
||||
String tagName = txxxToKey(description());
|
||||
StringList v = fieldList();
|
||||
for(StringList::ConstIterator it = v.begin(); it != v.end(); ++it)
|
||||
if(it != v.begin())
|
||||
map.insert(tagName, *it);
|
||||
return map;
|
||||
}
|
||||
|
||||
UserTextIdentificationFrame *UserTextIdentificationFrame::find(
|
||||
ID3v2::Tag *tag, const String &description) // static
|
||||
{
|
||||
FrameList l = tag->frameList("TXXX");
|
||||
for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it) {
|
||||
UserTextIdentificationFrame *f = dynamic_cast<UserTextIdentificationFrame *>(*it);
|
||||
if(f && f->description() == description)
|
||||
return f;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// UserTextIdentificationFrame private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
UserTextIdentificationFrame::UserTextIdentificationFrame(const ByteVector &data, Header *h) :
|
||||
TextIdentificationFrame(data, h)
|
||||
{
|
||||
checkFields();
|
||||
}
|
||||
|
||||
void UserTextIdentificationFrame::checkFields()
|
||||
{
|
||||
int fields = fieldList().size();
|
||||
|
||||
if(fields == 0)
|
||||
setDescription(String());
|
||||
if(fields <= 1)
|
||||
setText(String());
|
||||
}
|
|
@ -1,148 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/toolkit/tbytevectorlist.h>
|
||||
#include <taglib/toolkit/tpropertymap.h>
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
|
||||
#include <taglib/mpeg/id3v2/id3v2tag.h>
|
||||
#include <taglib/mpeg/id3v2/frames/uniquefileidentifierframe.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class UniqueFileIdentifierFrame::UniqueFileIdentifierFramePrivate
|
||||
{
|
||||
public:
|
||||
String owner;
|
||||
ByteVector identifier;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
UniqueFileIdentifierFrame::UniqueFileIdentifierFrame(const ByteVector &data) :
|
||||
ID3v2::Frame(data),
|
||||
d(new UniqueFileIdentifierFramePrivate())
|
||||
{
|
||||
setData(data);
|
||||
}
|
||||
|
||||
UniqueFileIdentifierFrame::UniqueFileIdentifierFrame(const String &owner, const ByteVector &id) :
|
||||
ID3v2::Frame("UFID"),
|
||||
d(new UniqueFileIdentifierFramePrivate())
|
||||
{
|
||||
d->owner = owner;
|
||||
d->identifier = id;
|
||||
}
|
||||
|
||||
UniqueFileIdentifierFrame::~UniqueFileIdentifierFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String UniqueFileIdentifierFrame::owner() const
|
||||
{
|
||||
return d->owner;
|
||||
}
|
||||
|
||||
ByteVector UniqueFileIdentifierFrame::identifier() const
|
||||
{
|
||||
return d->identifier;
|
||||
}
|
||||
|
||||
void UniqueFileIdentifierFrame::setOwner(const String &s)
|
||||
{
|
||||
d->owner = s;
|
||||
}
|
||||
|
||||
void UniqueFileIdentifierFrame::setIdentifier(const ByteVector &v)
|
||||
{
|
||||
d->identifier = v;
|
||||
}
|
||||
|
||||
String UniqueFileIdentifierFrame::toString() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
PropertyMap UniqueFileIdentifierFrame::asProperties() const
|
||||
{
|
||||
PropertyMap map;
|
||||
if(d->owner == "http://musicbrainz.org") {
|
||||
map.insert("MUSICBRAINZ_TRACKID", String(d->identifier));
|
||||
}
|
||||
else {
|
||||
map.unsupportedData().append(frameID() + String("/") + d->owner);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
UniqueFileIdentifierFrame *UniqueFileIdentifierFrame::findByOwner(const ID3v2::Tag *tag, const String &o) // static
|
||||
{
|
||||
ID3v2::FrameList comments = tag->frameList("UFID");
|
||||
|
||||
for(ID3v2::FrameList::ConstIterator it = comments.begin();
|
||||
it != comments.end();
|
||||
++it)
|
||||
{
|
||||
UniqueFileIdentifierFrame *frame = dynamic_cast<UniqueFileIdentifierFrame *>(*it);
|
||||
if(frame && frame->owner() == o)
|
||||
return frame;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void UniqueFileIdentifierFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
if(data.size() < 1) {
|
||||
debug("An UFID frame must contain at least 1 byte.");
|
||||
return;
|
||||
}
|
||||
|
||||
int pos = 0;
|
||||
d->owner = readStringField(data, String::Latin1, &pos);
|
||||
d->identifier = data.mid(pos);
|
||||
}
|
||||
|
||||
ByteVector UniqueFileIdentifierFrame::renderFields() const
|
||||
{
|
||||
ByteVector data;
|
||||
|
||||
data.append(d->owner.data(String::Latin1));
|
||||
data.append(char(0));
|
||||
data.append(d->identifier);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
UniqueFileIdentifierFrame::UniqueFileIdentifierFrame(const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new UniqueFileIdentifierFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/mpeg/id3v2/frames/unknownframe.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class UnknownFrame::UnknownFramePrivate
|
||||
{
|
||||
public:
|
||||
ByteVector fieldData;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
UnknownFrame::UnknownFrame(const ByteVector &data) :
|
||||
Frame(data),
|
||||
d(new UnknownFramePrivate())
|
||||
{
|
||||
setData(data);
|
||||
}
|
||||
|
||||
UnknownFrame::~UnknownFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String UnknownFrame::toString() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
ByteVector UnknownFrame::data() const
|
||||
{
|
||||
return d->fieldData;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void UnknownFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
d->fieldData = data;
|
||||
}
|
||||
|
||||
ByteVector UnknownFrame::renderFields() const
|
||||
{
|
||||
return d->fieldData;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
UnknownFrame::UnknownFrame(const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new UnknownFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
|
@ -1,198 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
|
||||
copyright : (C) 2006 by Urs Fleisch
|
||||
email : ufleisch@users.sourceforge.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/mpeg/id3v2/frames/unsynchronizedlyricsframe.h>
|
||||
#include <taglib/toolkit/tbytevectorlist.h>
|
||||
#include <taglib/mpeg/id3v2/id3v2tag.h>
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <taglib/toolkit/tpropertymap.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class UnsynchronizedLyricsFrame::UnsynchronizedLyricsFramePrivate
|
||||
{
|
||||
public:
|
||||
UnsynchronizedLyricsFramePrivate() : textEncoding(String::Latin1) {}
|
||||
String::Type textEncoding;
|
||||
ByteVector language;
|
||||
String description;
|
||||
String text;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(String::Type encoding) :
|
||||
Frame("USLT"),
|
||||
d(new UnsynchronizedLyricsFramePrivate())
|
||||
{
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(const ByteVector &data) :
|
||||
Frame(data),
|
||||
d(new UnsynchronizedLyricsFramePrivate())
|
||||
{
|
||||
setData(data);
|
||||
}
|
||||
|
||||
UnsynchronizedLyricsFrame::~UnsynchronizedLyricsFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String UnsynchronizedLyricsFrame::toString() const
|
||||
{
|
||||
return d->text;
|
||||
}
|
||||
|
||||
ByteVector UnsynchronizedLyricsFrame::language() const
|
||||
{
|
||||
return d->language;
|
||||
}
|
||||
|
||||
String UnsynchronizedLyricsFrame::description() const
|
||||
{
|
||||
return d->description;
|
||||
}
|
||||
|
||||
String UnsynchronizedLyricsFrame::text() const
|
||||
{
|
||||
return d->text;
|
||||
}
|
||||
|
||||
void UnsynchronizedLyricsFrame::setLanguage(const ByteVector &languageEncoding)
|
||||
{
|
||||
d->language = languageEncoding.mid(0, 3);
|
||||
}
|
||||
|
||||
void UnsynchronizedLyricsFrame::setDescription(const String &s)
|
||||
{
|
||||
d->description = s;
|
||||
}
|
||||
|
||||
void UnsynchronizedLyricsFrame::setText(const String &s)
|
||||
{
|
||||
d->text = s;
|
||||
}
|
||||
|
||||
|
||||
String::Type UnsynchronizedLyricsFrame::textEncoding() const
|
||||
{
|
||||
return d->textEncoding;
|
||||
}
|
||||
|
||||
void UnsynchronizedLyricsFrame::setTextEncoding(String::Type encoding)
|
||||
{
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
PropertyMap UnsynchronizedLyricsFrame::asProperties() const
|
||||
{
|
||||
PropertyMap map;
|
||||
String key = description().upper();
|
||||
if(key.isEmpty() || key == "LYRICS")
|
||||
map.insert("LYRICS", text());
|
||||
else
|
||||
map.insert("LYRICS:" + key, text());
|
||||
return map;
|
||||
}
|
||||
|
||||
UnsynchronizedLyricsFrame *UnsynchronizedLyricsFrame::findByDescription(const ID3v2::Tag *tag, const String &d) // static
|
||||
{
|
||||
ID3v2::FrameList lyrics = tag->frameList("USLT");
|
||||
|
||||
for(ID3v2::FrameList::ConstIterator it = lyrics.begin(); it != lyrics.end(); ++it){
|
||||
UnsynchronizedLyricsFrame *frame = dynamic_cast<UnsynchronizedLyricsFrame *>(*it);
|
||||
if(frame && frame->description() == d)
|
||||
return frame;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void UnsynchronizedLyricsFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
if(data.size() < 5) {
|
||||
debug("An unsynchronized lyrics frame must contain at least 5 bytes.");
|
||||
return;
|
||||
}
|
||||
|
||||
d->textEncoding = String::Type(data[0]);
|
||||
d->language = data.mid(1, 3);
|
||||
|
||||
int byteAlign
|
||||
= d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
|
||||
|
||||
ByteVectorList l =
|
||||
ByteVectorList::split(data.mid(4), textDelimiter(d->textEncoding), byteAlign, 2);
|
||||
|
||||
if(l.size() == 2) {
|
||||
if(d->textEncoding == String::Latin1) {
|
||||
d->description = Tag::latin1StringHandler()->parse(l.front());
|
||||
d->text = Tag::latin1StringHandler()->parse(l.back());
|
||||
} else {
|
||||
d->description = String(l.front(), d->textEncoding);
|
||||
d->text = String(l.back(), d->textEncoding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector UnsynchronizedLyricsFrame::renderFields() const
|
||||
{
|
||||
StringList sl;
|
||||
sl.append(d->description);
|
||||
sl.append(d->text);
|
||||
|
||||
const String::Type encoding = checkTextEncoding(sl, d->textEncoding);
|
||||
|
||||
ByteVector v;
|
||||
|
||||
v.append(char(encoding));
|
||||
v.append(d->language.size() == 3 ? d->language : "XXX");
|
||||
v.append(d->description.data(encoding));
|
||||
v.append(textDelimiter(encoding));
|
||||
v.append(d->text.data(encoding));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new UnsynchronizedLyricsFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
|
@ -1,246 +0,0 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
|
||||
copyright : (C) 2006 by Urs Fleisch
|
||||
email : ufleisch@users.sourceforge.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <taglib/mpeg/id3v2/frames/urllinkframe.h>
|
||||
#include <taglib/mpeg/id3v2/id3v2tag.h>
|
||||
#include <taglib/toolkit/tdebug.h>
|
||||
#include <taglib/toolkit/tstringlist.h>
|
||||
#include <taglib/toolkit/tpropertymap.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class UrlLinkFrame::UrlLinkFramePrivate
|
||||
{
|
||||
public:
|
||||
String url;
|
||||
};
|
||||
|
||||
class UserUrlLinkFrame::UserUrlLinkFramePrivate
|
||||
{
|
||||
public:
|
||||
UserUrlLinkFramePrivate() : textEncoding(String::Latin1) {}
|
||||
String::Type textEncoding;
|
||||
String description;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// UrlLinkFrame public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
UrlLinkFrame::UrlLinkFrame(const ByteVector &data) :
|
||||
Frame(data),
|
||||
d(new UrlLinkFramePrivate())
|
||||
{
|
||||
setData(data);
|
||||
}
|
||||
|
||||
UrlLinkFrame::~UrlLinkFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void UrlLinkFrame::setUrl(const String &s)
|
||||
{
|
||||
d->url = s;
|
||||
}
|
||||
|
||||
String UrlLinkFrame::url() const
|
||||
{
|
||||
return d->url;
|
||||
}
|
||||
|
||||
void UrlLinkFrame::setText(const String &s)
|
||||
{
|
||||
setUrl(s);
|
||||
}
|
||||
|
||||
String UrlLinkFrame::toString() const
|
||||
{
|
||||
return url();
|
||||
}
|
||||
|
||||
PropertyMap UrlLinkFrame::asProperties() const
|
||||
{
|
||||
String key = frameIDToKey(frameID());
|
||||
PropertyMap map;
|
||||
if(key.isEmpty())
|
||||
// unknown W*** frame - this normally shouldn't happen
|
||||
map.unsupportedData().append(frameID());
|
||||
else
|
||||
map.insert(key, url());
|
||||
return map;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// UrlLinkFrame protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void UrlLinkFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
d->url = String(data);
|
||||
}
|
||||
|
||||
ByteVector UrlLinkFrame::renderFields() const
|
||||
{
|
||||
return d->url.data(String::Latin1);
|
||||
}
|
||||
|
||||
UrlLinkFrame::UrlLinkFrame(const ByteVector &data, Header *h) :
|
||||
Frame(h),
|
||||
d(new UrlLinkFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// UserUrlLinkFrame public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
UserUrlLinkFrame::UserUrlLinkFrame(String::Type encoding) :
|
||||
UrlLinkFrame("WXXX"),
|
||||
d(new UserUrlLinkFramePrivate())
|
||||
{
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
UserUrlLinkFrame::UserUrlLinkFrame(const ByteVector &data) :
|
||||
UrlLinkFrame(data),
|
||||
d(new UserUrlLinkFramePrivate())
|
||||
{
|
||||
setData(data);
|
||||
}
|
||||
|
||||
UserUrlLinkFrame::~UserUrlLinkFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String UserUrlLinkFrame::toString() const
|
||||
{
|
||||
return "[" + description() + "] " + url();
|
||||
}
|
||||
|
||||
String::Type UserUrlLinkFrame::textEncoding() const
|
||||
{
|
||||
return d->textEncoding;
|
||||
}
|
||||
|
||||
void UserUrlLinkFrame::setTextEncoding(String::Type encoding)
|
||||
{
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
String UserUrlLinkFrame::description() const
|
||||
{
|
||||
return d->description;
|
||||
}
|
||||
|
||||
void UserUrlLinkFrame::setDescription(const String &s)
|
||||
{
|
||||
d->description = s;
|
||||
}
|
||||
|
||||
PropertyMap UserUrlLinkFrame::asProperties() const
|
||||
{
|
||||
PropertyMap map;
|
||||
String key = description().upper();
|
||||
if(key.isEmpty() || key == "URL")
|
||||
map.insert("URL", url());
|
||||
else
|
||||
map.insert("URL:" + key, url());
|
||||
return map;
|
||||
}
|
||||
|
||||
UserUrlLinkFrame *UserUrlLinkFrame::find(ID3v2::Tag *tag, const String &description) // static
|
||||
{
|
||||
FrameList l = tag->frameList("WXXX");
|
||||
for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it) {
|
||||
UserUrlLinkFrame *f = dynamic_cast<UserUrlLinkFrame *>(*it);
|
||||
if(f && f->description() == description)
|
||||
return f;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// UserUrlLinkFrame protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void UserUrlLinkFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
if(data.size() < 2) {
|
||||
debug("A user URL link frame must contain at least 2 bytes.");
|
||||
return;
|
||||
}
|
||||
|
||||
int pos = 0;
|
||||
|
||||
d->textEncoding = String::Type(data[0]);
|
||||
pos += 1;
|
||||
|
||||
if(d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8) {
|
||||
int offset = data.find(textDelimiter(d->textEncoding), pos);
|
||||
if(offset < pos)
|
||||
return;
|
||||
|
||||
d->description = String(data.mid(pos, offset - pos), d->textEncoding);
|
||||
pos = offset + 1;
|
||||
}
|
||||
else {
|
||||
int len = data.mid(pos).find(textDelimiter(d->textEncoding), 0, 2);
|
||||
if(len < 0)
|
||||
return;
|
||||
|
||||
d->description = String(data.mid(pos, len), d->textEncoding);
|
||||
pos += len + 2;
|
||||
}
|
||||
|
||||
setUrl(String(data.mid(pos)));
|
||||
}
|
||||
|
||||
ByteVector UserUrlLinkFrame::renderFields() const
|
||||
{
|
||||
ByteVector v;
|
||||
|
||||
String::Type encoding = checkTextEncoding(d->description, d->textEncoding);
|
||||
|
||||
v.append(char(encoding));
|
||||
v.append(d->description.data(encoding));
|
||||
v.append(textDelimiter(encoding));
|
||||
v.append(url().data(String::Latin1));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
UserUrlLinkFrame::UserUrlLinkFrame(const ByteVector &data, Header *h) :
|
||||
UrlLinkFrame(data, h),
|
||||
d(new UserUrlLinkFramePrivate())
|
||||
{
|
||||
parseFields(fieldData(data));
|
||||
}
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue