Add taglib-1.8 to 3rdparty
This commit is contained in:
parent
2302b80d52
commit
66ce3b4408
|
@ -0,0 +1,326 @@
|
|||
set(TAGLIB_SOVERSION_CURRENT 13)
|
||||
set(TAGLIB_SOVERSION_REVISION 0)
|
||||
set(TAGLIB_SOVERSION_AGE 12)
|
||||
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}")
|
||||
|
||||
configure_file(taglib_config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/taglib_config.h)
|
||||
|
||||
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}/mpeg/id3v2
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/mpeg/id3v2/frames
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/mpeg/id3v1
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ape
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/wavpack
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/trueaudio
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/riff
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/riff/aiff
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/riff/wav
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/mod
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/s3m
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/it
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/xm
|
||||
)
|
||||
|
||||
if(ZLIB_FOUND)
|
||||
include_directories(${ZLIB_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
set(tag_HDRS
|
||||
tag.h
|
||||
fileref.h
|
||||
audioproperties.h
|
||||
taglib_export.h
|
||||
${CMAKE_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
|
||||
mpeg/mpegfile.h
|
||||
mpeg/mpegproperties.h
|
||||
mpeg/mpegheader.h
|
||||
mpeg/xingheader.h
|
||||
mpeg/id3v1/id3v1tag.h
|
||||
mpeg/id3v1/id3v1genres.h
|
||||
mpeg/id3v2/id3v2extendedheader.h
|
||||
mpeg/id3v2/id3v2frame.h
|
||||
mpeg/id3v2/id3v2header.h
|
||||
mpeg/id3v2/id3v2synchdata.h
|
||||
mpeg/id3v2/id3v2footer.h
|
||||
mpeg/id3v2/id3v2framefactory.h
|
||||
mpeg/id3v2/id3v2tag.h
|
||||
mpeg/id3v2/frames/attachedpictureframe.h
|
||||
mpeg/id3v2/frames/commentsframe.h
|
||||
mpeg/id3v2/frames/generalencapsulatedobjectframe.h
|
||||
mpeg/id3v2/frames/ownershipframe.h
|
||||
mpeg/id3v2/frames/popularimeterframe.h
|
||||
mpeg/id3v2/frames/privateframe.h
|
||||
mpeg/id3v2/frames/relativevolumeframe.h
|
||||
mpeg/id3v2/frames/textidentificationframe.h
|
||||
mpeg/id3v2/frames/uniquefileidentifierframe.h
|
||||
mpeg/id3v2/frames/unknownframe.h
|
||||
mpeg/id3v2/frames/unsynchronizedlyricsframe.h
|
||||
mpeg/id3v2/frames/urllinkframe.h
|
||||
ogg/oggfile.h
|
||||
ogg/oggpage.h
|
||||
ogg/oggpageheader.h
|
||||
ogg/xiphcomment.h
|
||||
ogg/vorbis/vorbisfile.h
|
||||
ogg/vorbis/vorbisproperties.h
|
||||
ogg/flac/oggflacfile.h
|
||||
ogg/speex/speexfile.h
|
||||
ogg/speex/speexproperties.h
|
||||
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
|
||||
asf/asffile.h
|
||||
asf/asfproperties.h
|
||||
asf/asftag.h
|
||||
asf/asfattribute.h
|
||||
asf/asfpicture.h
|
||||
mp4/mp4file.h
|
||||
mp4/mp4atom.h
|
||||
mp4/mp4tag.h
|
||||
mp4/mp4item.h
|
||||
mp4/mp4properties.h
|
||||
mp4/mp4coverart.h
|
||||
mod/modfilebase.h
|
||||
mod/modfile.h
|
||||
mod/modtag.h
|
||||
mod/modproperties.h
|
||||
it/itfile.h
|
||||
it/itproperties.h
|
||||
s3m/s3mfile.h
|
||||
s3m/s3mproperties.h
|
||||
xm/xmfile.h
|
||||
xm/xmproperties.h
|
||||
)
|
||||
|
||||
set(mpeg_SRCS
|
||||
mpeg/mpegfile.cpp
|
||||
mpeg/mpegproperties.cpp
|
||||
mpeg/mpegheader.cpp
|
||||
mpeg/xingheader.cpp
|
||||
)
|
||||
|
||||
set(id3v1_SRCS
|
||||
mpeg/id3v1/id3v1tag.cpp
|
||||
mpeg/id3v1/id3v1genres.cpp
|
||||
)
|
||||
|
||||
set(id3v2_SRCS
|
||||
mpeg/id3v2/id3v2framefactory.cpp
|
||||
mpeg/id3v2/id3v2synchdata.cpp
|
||||
mpeg/id3v2/id3v2tag.cpp
|
||||
mpeg/id3v2/id3v2header.cpp
|
||||
mpeg/id3v2/id3v2frame.cpp
|
||||
mpeg/id3v2/id3v2footer.cpp
|
||||
mpeg/id3v2/id3v2extendedheader.cpp
|
||||
)
|
||||
|
||||
set(frames_SRCS
|
||||
mpeg/id3v2/frames/attachedpictureframe.cpp
|
||||
mpeg/id3v2/frames/commentsframe.cpp
|
||||
mpeg/id3v2/frames/generalencapsulatedobjectframe.cpp
|
||||
mpeg/id3v2/frames/ownershipframe.cpp
|
||||
mpeg/id3v2/frames/popularimeterframe.cpp
|
||||
mpeg/id3v2/frames/privateframe.cpp
|
||||
mpeg/id3v2/frames/relativevolumeframe.cpp
|
||||
mpeg/id3v2/frames/textidentificationframe.cpp
|
||||
mpeg/id3v2/frames/uniquefileidentifierframe.cpp
|
||||
mpeg/id3v2/frames/unknownframe.cpp
|
||||
mpeg/id3v2/frames/unsynchronizedlyricsframe.cpp
|
||||
mpeg/id3v2/frames/urllinkframe.cpp
|
||||
)
|
||||
|
||||
set(ogg_SRCS
|
||||
ogg/oggfile.cpp
|
||||
ogg/oggpage.cpp
|
||||
ogg/oggpageheader.cpp
|
||||
ogg/xiphcomment.cpp
|
||||
)
|
||||
|
||||
set(vorbis_SRCS
|
||||
ogg/vorbis/vorbisfile.cpp
|
||||
ogg/vorbis/vorbisproperties.cpp
|
||||
)
|
||||
|
||||
set(flacs_SRCS
|
||||
flac/flacfile.cpp
|
||||
flac/flacpicture.cpp
|
||||
flac/flacproperties.cpp
|
||||
flac/flacmetadatablock.cpp
|
||||
flac/flacunknownmetadatablock.cpp
|
||||
)
|
||||
|
||||
set(oggflacs_SRCS
|
||||
ogg/flac/oggflacfile.cpp
|
||||
)
|
||||
|
||||
set(mpc_SRCS
|
||||
mpc/mpcfile.cpp
|
||||
mpc/mpcproperties.cpp
|
||||
)
|
||||
|
||||
set(mp4_SRCS
|
||||
mp4/mp4file.cpp
|
||||
mp4/mp4atom.cpp
|
||||
mp4/mp4tag.cpp
|
||||
mp4/mp4item.cpp
|
||||
mp4/mp4properties.cpp
|
||||
mp4/mp4coverart.cpp
|
||||
)
|
||||
|
||||
set(ape_SRCS
|
||||
ape/apetag.cpp
|
||||
ape/apefooter.cpp
|
||||
ape/apeitem.cpp
|
||||
ape/apefile.cpp
|
||||
ape/apeproperties.cpp
|
||||
)
|
||||
|
||||
set(wavpack_SRCS
|
||||
wavpack/wavpackfile.cpp
|
||||
wavpack/wavpackproperties.cpp
|
||||
)
|
||||
|
||||
set(speex_SRCS
|
||||
ogg/speex/speexfile.cpp
|
||||
ogg/speex/speexproperties.cpp
|
||||
)
|
||||
|
||||
set(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
|
||||
)
|
||||
|
||||
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/unicode.cpp
|
||||
)
|
||||
|
||||
set(tag_LIB_SRCS
|
||||
${mpeg_SRCS} ${id3v1_SRCS} ${id3v2_SRCS} ${frames_SRCS} ${ogg_SRCS}
|
||||
${vorbis_SRCS} ${oggflacs_SRCS} ${mpc_SRCS} ${ape_SRCS} ${toolkit_SRCS} ${flacs_SRCS}
|
||||
${wavpack_SRCS} ${speex_SRCS} ${trueaudio_SRCS} ${riff_SRCS} ${aiff_SRCS} ${wav_SRCS}
|
||||
${asf_SRCS} ${mp4_SRCS} ${mod_SRCS} ${s3m_SRCS} ${it_SRCS} ${xm_SRCS}
|
||||
tag.cpp
|
||||
tagunion.cpp
|
||||
fileref.cpp
|
||||
audioproperties.cpp
|
||||
)
|
||||
|
||||
add_library(tag STATIC ${tag_LIB_SRCS} ${tag_HDRS})
|
||||
|
||||
if(ZLIB_FOUND)
|
||||
target_link_libraries(tag ${ZLIB_LIBRARIES})
|
||||
endif()
|
||||
|
||||
set_target_properties(tag PROPERTIES
|
||||
VERSION ${TAGLIB_SOVERSION_MAJOR}.${TAGLIB_SOVERSION_MINOR}.${TAGLIB_SOVERSION_PATCH}
|
||||
SOVERSION ${TAGLIB_SOVERSION_MAJOR}
|
||||
INSTALL_NAME_DIR ${LIB_INSTALL_DIR}
|
||||
DEFINE_SYMBOL MAKE_TAGLIB_LIB
|
||||
LINK_INTERFACE_LIBRARIES ""
|
||||
)
|
||||
|
||||
foreach(header ${tag_HDRS})
|
||||
get_filename_component(header_name ${header} NAME)
|
||||
configure_file(
|
||||
"${header}"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/headers/${header_name}"
|
||||
COPY_ONLY
|
||||
)
|
||||
endforeach()
|
|
@ -0,0 +1,170 @@
|
|||
================================================================================
|
||||
= APE Tag Specification, Version 2.000
|
||||
================================================================================
|
||||
|
||||
Original Content (C) 2004, Frank Klemm <frank.klemm@elster.offl.uni-jena.de>
|
||||
Formatting / Editing (C) 2004, Scott Wheeler <wheeler@kde.org>
|
||||
|
||||
================================================================================
|
||||
= Contents
|
||||
================================================================================
|
||||
|
||||
1 - APE Tag General Structure
|
||||
2 - APE Tag Header / Footer Format
|
||||
3 - APE Tag Flags
|
||||
4 - APE Tag Item Format
|
||||
5 - APE Tag Item Supported Keys
|
||||
6 - APE Tag Item Content
|
||||
7 - Data Types
|
||||
7.1 - Data Types / UTF-8
|
||||
7.2 - Data Types / Dates
|
||||
7.3 - Data Types / Timestamps
|
||||
|
||||
================================================================================
|
||||
= 1 - APE Tag General Structure
|
||||
================================================================================
|
||||
|
||||
Member of Basic Components of SV8 Stream Note:
|
||||
|
||||
It is strongly recommended that the data size be stored in the tags. The size
|
||||
should normally be in the roughly one kilobyte, never more than 8 kilobytes.
|
||||
|
||||
Larger data should be stored externally using link entries. Linked data is much
|
||||
easier to process by normal programs, so for instance JPEG data should not be
|
||||
included inside the audio file.
|
||||
|
||||
APE Tag Version 2.000 (with header, recommended):
|
||||
|
||||
/================================\
|
||||
| APE Tag Header | 32 bytes |
|
||||
|-------------------|------------|
|
||||
| APE Tag Item 1 | > 10 bytes |
|
||||
| APE Tag Item 2 | > 10 bytes |
|
||||
| APE Tag Item n-1 | > 10 bytes |
|
||||
| APE Tag Item n | > 10 bytes |
|
||||
|-------------------|------------|
|
||||
| APE Tag Footer | 32 bytes |
|
||||
\================================/
|
||||
|
||||
|
||||
APE tag items should be sorted ascending by size. When streaming, parts of the
|
||||
APE tag may be dropped to reduce the danger of drop outs between tracks. This
|
||||
is not required, but is strongly recommended. It would be desirable for the i
|
||||
tems to be sorted by importance / size, but this is not feasible. This
|
||||
convention should only be broken when adding less important small items and it
|
||||
is not desirable to rewrite the entire tag. An APE tag at the end of a file
|
||||
(the recommended location) must have at least a footer; an APE tag at the
|
||||
beginning of a file (strongly discouraged) must have at least a header.
|
||||
|
||||
APE Tag Version 1.000 (without header, deprecated)
|
||||
|
||||
/================================\
|
||||
| APE Tag Item 1 | > 10 bytes |
|
||||
| APE Tag Item 2 | > 10 bytes |
|
||||
| APE Tag Item n-1 | > 10 bytes |
|
||||
| APE Tag Item n | > 10 bytes |
|
||||
|-------------------|------------|
|
||||
| APE Tag Footer | 32 bytes |
|
||||
\================================/
|
||||
|
||||
================================================================================
|
||||
= 2 - APE Tag Header / Footer Format
|
||||
================================================================================
|
||||
|
||||
Contains number, length and attributes of all tag items
|
||||
|
||||
Header and Footer are different in 1 bit in the Tags Flags to distinguish
|
||||
between them.
|
||||
|
||||
Member of APE Tag 2.0
|
||||
|
||||
/===========================================================================\
|
||||
| Preamble | 8 bytes | { 'A', 'P', 'E', 'T', 'A', 'G', 'E', 'X' } |
|
||||
|----------------|---------|------------------------------------------------|
|
||||
| Version Number | 4 bytes | 1000 = Version 1.000, 2000 = Version 2.000 |
|
||||
|----------------|---------|------------------------------------------------|
|
||||
| Tag Size | 4 bytes | Tag size in bytes including footer and all tag |
|
||||
| | | items excluding the header (for 1.000 |
|
||||
| | | compatibility) |
|
||||
|----------------|---------|------------------------------------------------|
|
||||
| Item Count | 4 bytes | Number of items in the tag |
|
||||
|----------------|---------|------------------------------------------------|
|
||||
| Tag Flags | 4 bytes | Global flags |
|
||||
|----------------|---------|------------------------------------------------|
|
||||
| Reserved | 8 bytes | Must be zeroed |
|
||||
\===========================================================================/
|
||||
|
||||
================================================================================
|
||||
= 3 - APE Tag Flags
|
||||
================================================================================
|
||||
|
||||
The general flag structure for either items or headers / footers is the same.
|
||||
Bits 31, 30 and 29 are specific to headers / footers, whereas 2 through 0 are
|
||||
item specific.
|
||||
|
||||
Note: APE Tags from Version 1.0 do not use any of the following. All flags in
|
||||
that version are zeroed and ignored when reading.
|
||||
|
||||
/=================================================================\
|
||||
| Contains Header | Bit 31 | 1 - has header | 0 - no header |
|
||||
|-----------------|-------------|---------------------------------|
|
||||
| Contains Footer | Bit 30 | 1 - has footer | 0 - no footer |
|
||||
|-----------------|-------------|---------------------------------|
|
||||
| Is Header | Bit 29 | 1 - is header | 0 - is footer |
|
||||
|-----------------|-------------|---------------------------------|
|
||||
| Undefined | Bits 28 - 3 | Undefined, must be zeroed |
|
||||
|-----------------|-------------|---------------------------------|
|
||||
| Encoding | Bits 2 - 1 | 00 - UTF-8 |
|
||||
| | | 01 - Binary Data * |
|
||||
| | | 10 - External Reference ** |
|
||||
| | | 11 - Reserved |
|
||||
|-----------------|-------------|---------------------------------|
|
||||
| Read Only | Bit 0 | 1 - read only | 0 - read/write |
|
||||
\=================================================================/
|
||||
|
||||
(*) Should be ignored by tools for editing text values
|
||||
(**) Allowed external reference formats:
|
||||
- http://host/directory/filename.ext
|
||||
- ftp://host/directory/filename.ext
|
||||
- filename.ext
|
||||
- /directory/filename.ext
|
||||
- DRIVE:/directory/filename.ext
|
||||
|
||||
Note: External references are also UTF-8 encoded.
|
||||
|
||||
================================================================================
|
||||
= 4 - APE Tag Item Format
|
||||
================================================================================
|
||||
|
||||
APE Tag Items are stored as key-value pairs. APE Tags Item Key are case
|
||||
sensitive, however it is illegal to use keys which only differ in case and
|
||||
it is recommended that tag reading not be case sensitive.
|
||||
|
||||
Every key can only occur (at most) once. It is not possible to repeat a key
|
||||
to signify updated contents.
|
||||
|
||||
Tags can be partially or completely repeated in the streaming format. This
|
||||
makes it possible to display an artist and / or title if it was missed at the
|
||||
beginning of the stream. It is recommended that the important information like
|
||||
artist, album and title should occur approximately every 2 minutes in the
|
||||
stream and again 5 to 10 seconds before the end. However, care should be tak
|
||||
en not to replicate this information too often or during passages with high
|
||||
bitrate demands to avoid unnecessary drop-outs.
|
||||
|
||||
/==============================================================================\
|
||||
| Content Size | 4 bytes | Length of the value in bytes |
|
||||
|----------------|---------------|---------------------------------------------|
|
||||
| Flags | 4 bytes | Item flags |
|
||||
|----------------|---------------|---------------------------------------------|
|
||||
| Key | 2 - 255 bytes | Item key |
|
||||
|----------------|---------------|---------------------------------------------|
|
||||
| Key Terminator | 1 byte | Null byte that indicates the end of the key |
|
||||
|----------------|---------------|---------------------------------------------|
|
||||
| Value | variable | Content (formatted according to the flags) |
|
||||
\==============================================================================/
|
||||
|
||||
================================================================================
|
||||
|
||||
Sections 5 - 7 haven't yet been converted from:
|
||||
|
||||
http://www.personal.uni-jena.de/~pfk/mpp/sv8/apetag.html
|
|
@ -0,0 +1,305 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2010 by Alex Novichkov
|
||||
email : novichko@atnet.ru
|
||||
|
||||
copyright : (C) 2006 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
(original WavPack implementation)
|
||||
|
||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||
email : kde@carewolf.org
|
||||
(original MPC implementation)
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tbytevector.h>
|
||||
#include <tstring.h>
|
||||
#include <tdebug.h>
|
||||
#include <tagunion.h>
|
||||
#include <id3v1tag.h>
|
||||
#include <tpropertymap.h>
|
||||
|
||||
#include "apefile.h"
|
||||
|
||||
#include "apetag.h"
|
||||
#include "apefooter.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
namespace
|
||||
{
|
||||
enum { ApeAPEIndex, ApeID3v1Index };
|
||||
}
|
||||
|
||||
class APE::File::FilePrivate
|
||||
{
|
||||
public:
|
||||
FilePrivate() :
|
||||
APELocation(-1),
|
||||
APESize(0),
|
||||
ID3v1Location(-1),
|
||||
properties(0),
|
||||
hasAPE(false),
|
||||
hasID3v1(false) {}
|
||||
|
||||
~FilePrivate()
|
||||
{
|
||||
delete properties;
|
||||
}
|
||||
|
||||
long APELocation;
|
||||
uint APESize;
|
||||
|
||||
long ID3v1Location;
|
||||
|
||||
TagUnion tag;
|
||||
|
||||
Properties *properties;
|
||||
|
||||
// These indicate whether the file *on disk* has these tags, not if
|
||||
// this data structure does. This is used in computing offsets.
|
||||
|
||||
bool hasAPE;
|
||||
bool hasID3v1;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
APE::File::File(FileName file, bool readProperties,
|
||||
Properties::ReadStyle propertiesStyle) : TagLib::File(file)
|
||||
{
|
||||
d = new FilePrivate;
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
APE::File::File(IOStream *stream, bool readProperties,
|
||||
Properties::ReadStyle propertiesStyle) : TagLib::File(stream)
|
||||
{
|
||||
d = new FilePrivate;
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
APE::File::~File()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
TagLib::Tag *APE::File::tag() const
|
||||
{
|
||||
return &d->tag;
|
||||
}
|
||||
|
||||
PropertyMap APE::File::properties() const
|
||||
{
|
||||
if(d->hasAPE)
|
||||
return d->tag.access<APE::Tag>(ApeAPEIndex, false)->properties();
|
||||
if(d->hasID3v1)
|
||||
return d->tag.access<ID3v1::Tag>(ApeID3v1Index, false)->properties();
|
||||
return PropertyMap();
|
||||
}
|
||||
|
||||
void APE::File::removeUnsupportedProperties(const StringList &properties)
|
||||
{
|
||||
if(d->hasAPE)
|
||||
d->tag.access<APE::Tag>(ApeAPEIndex, false)->removeUnsupportedProperties(properties);
|
||||
if(d->hasID3v1)
|
||||
d->tag.access<ID3v1::Tag>(ApeID3v1Index, false)->removeUnsupportedProperties(properties);
|
||||
}
|
||||
|
||||
PropertyMap APE::File::setProperties(const PropertyMap &properties)
|
||||
{
|
||||
if(d->hasAPE)
|
||||
return d->tag.access<APE::Tag>(ApeAPEIndex, false)->setProperties(properties);
|
||||
else if(d->hasID3v1)
|
||||
return d->tag.access<ID3v1::Tag>(ApeID3v1Index, false)->setProperties(properties);
|
||||
else
|
||||
return d->tag.access<APE::Tag>(ApeAPEIndex, true)->setProperties(properties);
|
||||
}
|
||||
|
||||
APE::Properties *APE::File::audioProperties() const
|
||||
{
|
||||
return d->properties;
|
||||
}
|
||||
|
||||
bool APE::File::save()
|
||||
{
|
||||
if(readOnly()) {
|
||||
debug("APE::File::save() -- File is read only.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update ID3v1 tag
|
||||
|
||||
if(ID3v1Tag()) {
|
||||
if(d->hasID3v1) {
|
||||
seek(d->ID3v1Location);
|
||||
writeBlock(ID3v1Tag()->render());
|
||||
}
|
||||
else {
|
||||
seek(0, End);
|
||||
d->ID3v1Location = tell();
|
||||
writeBlock(ID3v1Tag()->render());
|
||||
d->hasID3v1 = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(d->hasID3v1) {
|
||||
removeBlock(d->ID3v1Location, 128);
|
||||
d->hasID3v1 = false;
|
||||
if(d->hasAPE) {
|
||||
if(d->APELocation > d->ID3v1Location)
|
||||
d->APELocation -= 128;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update APE tag
|
||||
|
||||
if(APETag()) {
|
||||
if(d->hasAPE)
|
||||
insert(APETag()->render(), d->APELocation, d->APESize);
|
||||
else {
|
||||
if(d->hasID3v1) {
|
||||
insert(APETag()->render(), d->ID3v1Location, 0);
|
||||
d->APESize = APETag()->footer()->completeTagSize();
|
||||
d->hasAPE = true;
|
||||
d->APELocation = d->ID3v1Location;
|
||||
d->ID3v1Location += d->APESize;
|
||||
}
|
||||
else {
|
||||
seek(0, End);
|
||||
d->APELocation = tell();
|
||||
writeBlock(APETag()->render());
|
||||
d->APESize = APETag()->footer()->completeTagSize();
|
||||
d->hasAPE = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(d->hasAPE) {
|
||||
removeBlock(d->APELocation, d->APESize);
|
||||
d->hasAPE = false;
|
||||
if(d->hasID3v1) {
|
||||
if(d->ID3v1Location > d->APELocation) {
|
||||
d->ID3v1Location -= d->APESize;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ID3v1::Tag *APE::File::ID3v1Tag(bool create)
|
||||
{
|
||||
return d->tag.access<ID3v1::Tag>(ApeID3v1Index, create);
|
||||
}
|
||||
|
||||
APE::Tag *APE::File::APETag(bool create)
|
||||
{
|
||||
return d->tag.access<APE::Tag>(ApeAPEIndex, create);
|
||||
}
|
||||
|
||||
void APE::File::strip(int tags)
|
||||
{
|
||||
if(tags & ID3v1) {
|
||||
d->tag.set(ApeID3v1Index, 0);
|
||||
APETag(true);
|
||||
}
|
||||
|
||||
if(tags & APE) {
|
||||
d->tag.set(ApeAPEIndex, 0);
|
||||
|
||||
if(!ID3v1Tag())
|
||||
APETag(true);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void APE::File::read(bool readProperties, Properties::ReadStyle /* propertiesStyle */)
|
||||
{
|
||||
// Look for an ID3v1 tag
|
||||
|
||||
d->ID3v1Location = findID3v1();
|
||||
|
||||
if(d->ID3v1Location >= 0) {
|
||||
d->tag.set(ApeID3v1Index, new ID3v1::Tag(this, d->ID3v1Location));
|
||||
d->hasID3v1 = true;
|
||||
}
|
||||
|
||||
// Look for an APE tag
|
||||
|
||||
d->APELocation = findAPE();
|
||||
|
||||
if(d->APELocation >= 0) {
|
||||
d->tag.set(ApeAPEIndex, new APE::Tag(this, d->APELocation));
|
||||
d->APESize = APETag()->footer()->completeTagSize();
|
||||
d->APELocation = d->APELocation + APETag()->footer()->size() - d->APESize;
|
||||
d->hasAPE = true;
|
||||
}
|
||||
|
||||
if(!d->hasID3v1)
|
||||
APETag(true);
|
||||
|
||||
// Look for APE audio properties
|
||||
|
||||
if(readProperties) {
|
||||
d->properties = new Properties(this);
|
||||
}
|
||||
}
|
||||
|
||||
long APE::File::findAPE()
|
||||
{
|
||||
if(!isValid())
|
||||
return -1;
|
||||
|
||||
if(d->hasID3v1)
|
||||
seek(-160, End);
|
||||
else
|
||||
seek(-32, End);
|
||||
|
||||
long p = tell();
|
||||
|
||||
if(readBlock(8) == APE::Tag::fileIdentifier())
|
||||
return p;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
long APE::File::findID3v1()
|
||||
{
|
||||
if(!isValid())
|
||||
return -1;
|
||||
|
||||
seek(-128, End);
|
||||
long p = tell();
|
||||
|
||||
if(readBlock(3) == ID3v1::Tag::fileIdentifier())
|
||||
return p;
|
||||
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,201 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2010 by Alex Novichkov
|
||||
email : novichko@atnet.ru
|
||||
|
||||
copyright : (C) 2006 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
(original WavPack implementation)
|
||||
|
||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||
email : kde@carewolf.org
|
||||
(original MPC implementation)
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_APEFILE_H
|
||||
#define TAGLIB_APEFILE_H
|
||||
|
||||
#include "tfile.h"
|
||||
#include "taglib_export.h"
|
||||
#include "apeproperties.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
class Tag;
|
||||
|
||||
namespace ID3v1 { class Tag; }
|
||||
namespace APE { class Tag; }
|
||||
|
||||
//! An implementation of APE metadata
|
||||
|
||||
/*!
|
||||
* This is implementation of APE metadata.
|
||||
*
|
||||
* This supports ID3v1 and APE (v1 and v2) style comments as well as reading stream
|
||||
* properties from the file.
|
||||
*/
|
||||
|
||||
namespace APE {
|
||||
|
||||
//! An implementation of TagLib::File with APE specific methods
|
||||
|
||||
/*!
|
||||
* This implements and provides an interface APE WavPack files to the
|
||||
* TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing
|
||||
* the abstract TagLib::File API as well as providing some additional
|
||||
* information specific to APE files.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT File : public TagLib::File
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* This set of flags is used for various operations and is suitable for
|
||||
* being OR-ed together.
|
||||
*/
|
||||
enum TagTypes {
|
||||
//! Empty set. Matches no tag types.
|
||||
NoTags = 0x0000,
|
||||
//! Matches ID3v1 tags.
|
||||
ID3v1 = 0x0001,
|
||||
//! Matches APE tags.
|
||||
APE = 0x0002,
|
||||
//! Matches all tag types.
|
||||
AllTags = 0xffff
|
||||
};
|
||||
|
||||
/*!
|
||||
* Contructs an WavPack file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Contructs an WavPack file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*
|
||||
* \note TagLib will *not* take ownership of the stream, the caller is
|
||||
* responsible for deleting it after the File object.
|
||||
*/
|
||||
File(IOStream *stream, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
virtual ~File();
|
||||
|
||||
/*!
|
||||
* Returns the Tag for this file. This will be an APE tag, an ID3v1 tag
|
||||
* or a combination of the two.
|
||||
*/
|
||||
virtual TagLib::Tag *tag() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- export function.
|
||||
* If the file contains both an APE and an ID3v1 tag, only APE
|
||||
* will be converted to the PropertyMap.
|
||||
*/
|
||||
PropertyMap properties() const;
|
||||
|
||||
/*!
|
||||
* Removes unsupported properties. Forwards to the actual Tag's
|
||||
* removeUnsupportedProperties() function.
|
||||
*/
|
||||
void removeUnsupportedProperties(const StringList &properties);
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- import function.
|
||||
* As for the export, only one tag is taken into account. If the file
|
||||
* has no tag at all, APE will be created.
|
||||
*/
|
||||
PropertyMap setProperties(const PropertyMap &);
|
||||
/*!
|
||||
* Returns the APE::Properties for this file. If no audio properties
|
||||
* were read then this will return a null pointer.
|
||||
*/
|
||||
virtual Properties *audioProperties() const;
|
||||
|
||||
/*!
|
||||
* Saves the file.
|
||||
*
|
||||
* \note According to the official Monkey's Audio SDK, an APE file
|
||||
* can only have either ID3V1 or APE tags, so a parameter is used here.
|
||||
*/
|
||||
virtual bool save();
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the ID3v1 tag of the file.
|
||||
*
|
||||
* If \a create is false (the default) this will return a null pointer
|
||||
* if there is no valid ID3v1 tag. If \a create is true it will create
|
||||
* an ID3v1 tag if one does not exist. If there is already an APE tag, the
|
||||
* new ID3v1 tag will be placed after it.
|
||||
*
|
||||
* \note The Tag <b>is still</b> owned by the APE::File and should not be
|
||||
* deleted by the user. It will be deleted when the file (object) is
|
||||
* destroyed.
|
||||
*/
|
||||
ID3v1::Tag *ID3v1Tag(bool create = false);
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the APE tag of the file.
|
||||
*
|
||||
* If \a create is false (the default) this will return a null pointer
|
||||
* if there is no valid APE tag. If \a create is true it will create
|
||||
* a APE tag if one does not exist.
|
||||
*
|
||||
* \note The Tag <b>is still</b> owned by the APE::File and should not be
|
||||
* deleted by the user. It will be deleted when the file (object) is
|
||||
* destroyed.
|
||||
*/
|
||||
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);
|
||||
|
||||
private:
|
||||
File(const File &);
|
||||
File &operator=(const File &);
|
||||
|
||||
void read(bool readProperties, Properties::ReadStyle propertiesStyle);
|
||||
void scan();
|
||||
long findID3v1();
|
||||
long findAPE();
|
||||
|
||||
class FilePrivate;
|
||||
FilePrivate *d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,236 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||
(C) 2002 - 2008 by Scott Wheeler (id3v2header.cpp)
|
||||
email : kde@carewolf.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
#include <bitset>
|
||||
|
||||
#include <tstring.h>
|
||||
#include <tdebug.h>
|
||||
|
||||
#include "apefooter.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace APE;
|
||||
|
||||
class APE::Footer::FooterPrivate
|
||||
{
|
||||
public:
|
||||
FooterPrivate() : version(0),
|
||||
footerPresent(true),
|
||||
headerPresent(false),
|
||||
isHeader(false),
|
||||
itemCount(0),
|
||||
tagSize(0) {}
|
||||
|
||||
~FooterPrivate() {}
|
||||
|
||||
uint version;
|
||||
|
||||
bool footerPresent;
|
||||
bool headerPresent;
|
||||
|
||||
bool isHeader;
|
||||
|
||||
uint itemCount;
|
||||
uint tagSize;
|
||||
|
||||
static const uint size = 32;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// static members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TagLib::uint APE::Footer::size()
|
||||
{
|
||||
return FooterPrivate::size;
|
||||
}
|
||||
|
||||
ByteVector APE::Footer::fileIdentifier()
|
||||
{
|
||||
return ByteVector::fromCString("APETAGEX");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
APE::Footer::Footer()
|
||||
{
|
||||
d = new FooterPrivate;
|
||||
}
|
||||
|
||||
APE::Footer::Footer(const ByteVector &data)
|
||||
{
|
||||
d = new FooterPrivate;
|
||||
parse(data);
|
||||
}
|
||||
|
||||
APE::Footer::~Footer()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
TagLib::uint APE::Footer::version() const
|
||||
{
|
||||
return d->version;
|
||||
}
|
||||
|
||||
bool APE::Footer::headerPresent() const
|
||||
{
|
||||
return d->headerPresent;
|
||||
}
|
||||
|
||||
bool APE::Footer::footerPresent() const
|
||||
{
|
||||
return d->footerPresent;
|
||||
}
|
||||
|
||||
bool APE::Footer::isHeader() const
|
||||
{
|
||||
return d->isHeader;
|
||||
}
|
||||
|
||||
void APE::Footer::setHeaderPresent(bool b) const
|
||||
{
|
||||
d->headerPresent = b;
|
||||
}
|
||||
|
||||
TagLib::uint APE::Footer::itemCount() const
|
||||
{
|
||||
return d->itemCount;
|
||||
}
|
||||
|
||||
void APE::Footer::setItemCount(uint s)
|
||||
{
|
||||
d->itemCount = s;
|
||||
}
|
||||
|
||||
TagLib::uint APE::Footer::tagSize() const
|
||||
{
|
||||
return d->tagSize;
|
||||
}
|
||||
|
||||
TagLib::uint APE::Footer::completeTagSize() const
|
||||
{
|
||||
if(d->headerPresent)
|
||||
return d->tagSize + d->size;
|
||||
else
|
||||
return d->tagSize;
|
||||
}
|
||||
|
||||
void APE::Footer::setTagSize(uint s)
|
||||
{
|
||||
d->tagSize = s;
|
||||
}
|
||||
|
||||
void APE::Footer::setData(const ByteVector &data)
|
||||
{
|
||||
parse(data);
|
||||
}
|
||||
|
||||
ByteVector APE::Footer::renderFooter() const
|
||||
{
|
||||
return render(false);
|
||||
}
|
||||
|
||||
ByteVector APE::Footer::renderHeader() const
|
||||
{
|
||||
if (!d->headerPresent) return ByteVector();
|
||||
|
||||
return render(true);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void APE::Footer::parse(const ByteVector &data)
|
||||
{
|
||||
if(data.size() < size())
|
||||
return;
|
||||
|
||||
// The first eight bytes, data[0..7], are the File Identifier, "APETAGEX".
|
||||
|
||||
// Read the version number
|
||||
|
||||
d->version = data.mid(8, 4).toUInt(false);
|
||||
|
||||
// Read the tag size
|
||||
|
||||
d->tagSize = data.mid(12, 4).toUInt(false);
|
||||
|
||||
// Read the item count
|
||||
|
||||
d->itemCount = data.mid(16, 4).toUInt(false);
|
||||
|
||||
// Read the flags
|
||||
|
||||
std::bitset<32> flags(TAGLIB_CONSTRUCT_BITSET(data.mid(20, 4).toUInt(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;
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||
email : kde@carewolf.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_APEFOOTER_H
|
||||
#define TAGLIB_APEFOOTER_H
|
||||
|
||||
#include "tbytevector.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace APE {
|
||||
|
||||
//! An implementation of APE footers
|
||||
|
||||
/*!
|
||||
* This class implements APE footers (and headers). It attempts to follow, both
|
||||
* semantically and programatically, the structure specified in
|
||||
* the APE v2.0 standard. The API is based on the properties of APE footer and
|
||||
* headers specified there.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT Footer
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* Constructs an empty APE footer.
|
||||
*/
|
||||
Footer();
|
||||
|
||||
/*!
|
||||
* Constructs an APE footer based on \a data. parse() is called
|
||||
* immediately.
|
||||
*/
|
||||
Footer(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Destroys the footer.
|
||||
*/
|
||||
virtual ~Footer();
|
||||
|
||||
/*!
|
||||
* Returns the version number. (Note: This is the 1000 or 2000.)
|
||||
*/
|
||||
uint version() const;
|
||||
|
||||
/*!
|
||||
* Returns true if a header is present in the tag.
|
||||
*/
|
||||
bool headerPresent() const;
|
||||
|
||||
/*!
|
||||
* Returns true if a footer is present in the tag.
|
||||
*/
|
||||
bool footerPresent() const;
|
||||
|
||||
/*!
|
||||
* Returns true this is actually the header.
|
||||
*/
|
||||
bool isHeader() const;
|
||||
|
||||
/*!
|
||||
* Sets whether the header should be rendered or not
|
||||
*/
|
||||
void setHeaderPresent(bool b) const;
|
||||
|
||||
/*!
|
||||
* Returns the number of items in the tag.
|
||||
*/
|
||||
uint itemCount() const;
|
||||
|
||||
/*!
|
||||
* Set the item count to \a s.
|
||||
* \see itemCount()
|
||||
*/
|
||||
void setItemCount(uint s);
|
||||
|
||||
/*!
|
||||
* Returns the tag size in bytes. This is the size of the frame content and footer.
|
||||
* The size of the \e entire tag will be this plus the header size, if present.
|
||||
*
|
||||
* \see completeTagSize()
|
||||
*/
|
||||
uint tagSize() const;
|
||||
|
||||
/*!
|
||||
* Returns the tag size, including if present, the header
|
||||
* size.
|
||||
*
|
||||
* \see tagSize()
|
||||
*/
|
||||
uint completeTagSize() const;
|
||||
|
||||
/*!
|
||||
* Set the tag size to \a s.
|
||||
* \see tagSize()
|
||||
*/
|
||||
void setTagSize(uint s);
|
||||
|
||||
/*!
|
||||
* Returns the size of the footer. Presently this is always 32 bytes.
|
||||
*/
|
||||
static uint size();
|
||||
|
||||
/*!
|
||||
* Returns the string used to identify an APE tag inside of a file.
|
||||
* Presently this is always "APETAGEX".
|
||||
*/
|
||||
static ByteVector fileIdentifier();
|
||||
|
||||
/*!
|
||||
* Sets the data that will be used as the footer. 32 bytes,
|
||||
* starting from \a data will be used.
|
||||
*/
|
||||
void setData(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Renders the footer back to binary format.
|
||||
*/
|
||||
ByteVector renderFooter() const;
|
||||
|
||||
/*!
|
||||
* Renders the header corresponding to the footer. If headerPresent is
|
||||
* set to false, it returns an empty ByteVector.
|
||||
*/
|
||||
ByteVector renderHeader() const;
|
||||
|
||||
protected:
|
||||
/*!
|
||||
* Called by setData() to parse the footer data. It makes this information
|
||||
* available through the public API.
|
||||
*/
|
||||
void parse(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Called by renderFooter and renderHeader
|
||||
*/
|
||||
ByteVector render(bool isHeader) const;
|
||||
|
||||
private:
|
||||
Footer(const Footer &);
|
||||
Footer &operator=(const Footer &);
|
||||
|
||||
class FooterPrivate;
|
||||
FooterPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,276 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||
email : kde@carewolf.com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tbytevectorlist.h>
|
||||
#include <tdebug.h>
|
||||
|
||||
#include "apeitem.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace APE;
|
||||
|
||||
class APE::Item::ItemPrivate
|
||||
{
|
||||
public:
|
||||
ItemPrivate() : type(Text), readOnly(false) {}
|
||||
|
||||
Item::ItemTypes type;
|
||||
String key;
|
||||
ByteVector value;
|
||||
StringList text;
|
||||
bool readOnly;
|
||||
};
|
||||
|
||||
APE::Item::Item()
|
||||
{
|
||||
d = new ItemPrivate;
|
||||
}
|
||||
|
||||
APE::Item::Item(const String &key, const String &value)
|
||||
{
|
||||
d = new ItemPrivate;
|
||||
d->key = key;
|
||||
d->text.append(value);
|
||||
}
|
||||
|
||||
APE::Item::Item(const String &key, const StringList &values)
|
||||
{
|
||||
d = new ItemPrivate;
|
||||
d->key = key;
|
||||
d->text = values;
|
||||
}
|
||||
|
||||
APE::Item::Item(const String &key, const ByteVector &value, bool binary)
|
||||
{
|
||||
d = new ItemPrivate;
|
||||
d->key = key;
|
||||
if(binary) {
|
||||
d->type = Binary;
|
||||
d->value = value;
|
||||
}
|
||||
else
|
||||
d->text.append(value);
|
||||
}
|
||||
|
||||
APE::Item::Item(const Item &item)
|
||||
{
|
||||
d = new ItemPrivate(*item.d);
|
||||
}
|
||||
|
||||
APE::Item::~Item()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
Item &APE::Item::operator=(const Item &item)
|
||||
{
|
||||
delete d;
|
||||
d = new ItemPrivate(*item.d);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void APE::Item::setReadOnly(bool readOnly)
|
||||
{
|
||||
d->readOnly = readOnly;
|
||||
}
|
||||
|
||||
bool APE::Item::isReadOnly() const
|
||||
{
|
||||
return d->readOnly;
|
||||
}
|
||||
|
||||
void APE::Item::setType(APE::Item::ItemTypes val)
|
||||
{
|
||||
d->type = val;
|
||||
}
|
||||
|
||||
APE::Item::ItemTypes APE::Item::type() const
|
||||
{
|
||||
return d->type;
|
||||
}
|
||||
|
||||
String APE::Item::key() const
|
||||
{
|
||||
return d->key;
|
||||
}
|
||||
|
||||
ByteVector APE::Item::binaryData() const
|
||||
{
|
||||
return d->value;
|
||||
}
|
||||
|
||||
void APE::Item::setBinaryData(const ByteVector &value)
|
||||
{
|
||||
d->type = Binary;
|
||||
d->value = value;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void APE::Item::setValues(const StringList &value)
|
||||
{
|
||||
d->type = Text;
|
||||
d->text = value;
|
||||
}
|
||||
|
||||
void APE::Item::appendValue(const String &value)
|
||||
{
|
||||
d->type = Text;
|
||||
d->text.append(value);
|
||||
}
|
||||
|
||||
void APE::Item::appendValues(const StringList &values)
|
||||
{
|
||||
d->type = Text;
|
||||
d->text.append(values);
|
||||
}
|
||||
|
||||
int APE::Item::size() const
|
||||
{
|
||||
// SFB: Why is d->key.size() used when size() returns the length in UniChars and not UTF-8?
|
||||
int result = 8 + d->key.size() /* d->key.data(String::UTF8).size() */ + 1;
|
||||
switch (d->type) {
|
||||
case Text:
|
||||
if(d->text.size()) {
|
||||
StringList::ConstIterator it = d->text.begin();
|
||||
|
||||
result += it->data(String::UTF8).size();
|
||||
it++;
|
||||
for(; it != d->text.end(); ++it)
|
||||
result += 1 + it->data(String::UTF8).size();
|
||||
}
|
||||
break;
|
||||
|
||||
case Binary:
|
||||
case Locator:
|
||||
result += d->value.size();
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
StringList APE::Item::toStringList() const
|
||||
{
|
||||
return d->text;
|
||||
}
|
||||
|
||||
StringList APE::Item::values() const
|
||||
{
|
||||
return d->text;
|
||||
}
|
||||
|
||||
String APE::Item::toString() const
|
||||
{
|
||||
return isEmpty() ? String::null : d->text.front();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
uint valueLength = data.mid(0, 4).toUInt(false);
|
||||
uint flags = data.mid(4, 4).toUInt(false);
|
||||
|
||||
d->key = String(data.mid(8), String::UTF8);
|
||||
|
||||
d->value = data.mid(8 + d->key.size() + 1, valueLength);
|
||||
|
||||
setReadOnly(flags & 1);
|
||||
setType(ItemTypes((flags >> 1) & 3));
|
||||
|
||||
if(Text == d->type)
|
||||
d->text = StringList(ByteVectorList::split(d->value, '\0'), String::UTF8);
|
||||
}
|
||||
|
||||
ByteVector APE::Item::render() const
|
||||
{
|
||||
ByteVector data;
|
||||
TagLib::uint flags = ((d->readOnly) ? 1 : 0) | (d->type << 1);
|
||||
ByteVector value;
|
||||
|
||||
if(isEmpty())
|
||||
return data;
|
||||
|
||||
if(d->type == Text) {
|
||||
StringList::ConstIterator it = d->text.begin();
|
||||
|
||||
value.append(it->data(String::UTF8));
|
||||
it++;
|
||||
for(; it != d->text.end(); ++it) {
|
||||
value.append('\0');
|
||||
value.append(it->data(String::UTF8));
|
||||
}
|
||||
d->value = value;
|
||||
}
|
||||
else
|
||||
value.append(d->value);
|
||||
|
||||
data.append(ByteVector::fromUInt(value.size(), false));
|
||||
data.append(ByteVector::fromUInt(flags, false));
|
||||
data.append(d->key.data(String::UTF8));
|
||||
data.append(ByteVector('\0'));
|
||||
data.append(value);
|
||||
|
||||
return data;
|
||||
}
|
|
@ -0,0 +1,217 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||
email : kde@carewolf.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_APEITEM_H
|
||||
#define TAGLIB_APEITEM_H
|
||||
|
||||
#include "tbytevector.h"
|
||||
#include "tstring.h"
|
||||
#include "tstringlist.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace APE {
|
||||
|
||||
//! An implementation of APE-items
|
||||
|
||||
/*!
|
||||
* This class provides the features of items in the APEv2 standard.
|
||||
*/
|
||||
class TAGLIB_EXPORT Item
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* Enum of types an Item can have. The value of 3 is reserved.
|
||||
*/
|
||||
enum ItemTypes {
|
||||
//! Item contains text information coded in UTF-8
|
||||
Text = 0,
|
||||
//! Item contains binary information
|
||||
Binary = 1,
|
||||
//! Item is a locator of external stored information
|
||||
Locator = 2
|
||||
};
|
||||
/*!
|
||||
* Constructs an empty item.
|
||||
*/
|
||||
Item();
|
||||
|
||||
/*!
|
||||
* Constructs a text item with \a key and \a value.
|
||||
*/
|
||||
// BIC: Remove this, StringList has a constructor from a single string
|
||||
Item(const String &key, const String &value);
|
||||
|
||||
/*!
|
||||
* Constructs a text item with \a key and \a values.
|
||||
*/
|
||||
Item(const String &key, const StringList &values);
|
||||
|
||||
/*!
|
||||
* Constructs an item with \a key and \a value.
|
||||
* If \a binary is true a Binary item will be created, otherwise \a value will be interpreted as text
|
||||
*/
|
||||
Item(const String &key, const ByteVector &value, bool binary);
|
||||
|
||||
/*!
|
||||
* Construct an item as a copy of \a item.
|
||||
*/
|
||||
Item(const Item &item);
|
||||
|
||||
/*!
|
||||
* Destroys the item.
|
||||
*/
|
||||
virtual ~Item();
|
||||
|
||||
/*!
|
||||
* Copies the contents of \a item into this item.
|
||||
*/
|
||||
Item &operator=(const Item &item);
|
||||
|
||||
/*!
|
||||
* Returns the key.
|
||||
*/
|
||||
String key() const;
|
||||
|
||||
/*!
|
||||
* Returns the binary value.
|
||||
* If the item type is not \a Binary, the returned contents are undefined
|
||||
*/
|
||||
ByteVector binaryData() const;
|
||||
|
||||
/*!
|
||||
* Set the binary value to \a value
|
||||
* The item's type will also be set to \a Binary
|
||||
*/
|
||||
void setBinaryData(const ByteVector &value);
|
||||
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
/* Remove in next binary incompatible release */
|
||||
ByteVector value() const;
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* Sets the key for the item to \a key.
|
||||
*/
|
||||
void setKey(const String &key);
|
||||
|
||||
/*!
|
||||
* Sets the text value of the item to \a value and clears any previous contents.
|
||||
*
|
||||
* \see toString()
|
||||
*/
|
||||
void setValue(const String &value);
|
||||
|
||||
/*!
|
||||
* Sets the text value of the item to the list of values in \a value and clears
|
||||
* any previous contents.
|
||||
*
|
||||
* \see toStringList()
|
||||
*/
|
||||
void setValues(const StringList &values);
|
||||
|
||||
/*!
|
||||
* Appends \a value to create (or extend) the current list of text values.
|
||||
*
|
||||
* \see toString()
|
||||
*/
|
||||
void appendValue(const String &value);
|
||||
|
||||
/*!
|
||||
* Appends \a values to extend the current list of text values.
|
||||
*
|
||||
* \see toStringList()
|
||||
*/
|
||||
void appendValues(const StringList &values);
|
||||
|
||||
/*!
|
||||
* Returns the size of the full item.
|
||||
*/
|
||||
int size() const;
|
||||
|
||||
/*!
|
||||
* Returns the value as a single string. In case of multiple strings,
|
||||
* the first is returned.
|
||||
*/
|
||||
String toString() const;
|
||||
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
/* Remove in next binary incompatible release */
|
||||
StringList toStringList() const;
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* Returns the list of text values.
|
||||
*/
|
||||
StringList values() const;
|
||||
|
||||
/*!
|
||||
* Render the item to a ByteVector.
|
||||
*/
|
||||
ByteVector render() const;
|
||||
|
||||
/*!
|
||||
* Parse the item from the ByteVector \a data.
|
||||
*/
|
||||
void parse(const ByteVector& data);
|
||||
|
||||
/*!
|
||||
* Set the item to read-only.
|
||||
*/
|
||||
void setReadOnly(bool readOnly);
|
||||
|
||||
/*!
|
||||
* Return true if the item is read-only.
|
||||
*/
|
||||
bool isReadOnly() const;
|
||||
|
||||
/*!
|
||||
* Sets the type of the item to \a type.
|
||||
*
|
||||
* \see ItemTypes
|
||||
*/
|
||||
void setType(ItemTypes type);
|
||||
|
||||
/*!
|
||||
* Returns the type of the item.
|
||||
*/
|
||||
ItemTypes type() const;
|
||||
|
||||
/*!
|
||||
* Returns if the item has any real content.
|
||||
*/
|
||||
bool isEmpty() const;
|
||||
|
||||
private:
|
||||
class ItemPrivate;
|
||||
ItemPrivate *d;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,231 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2010 by Alex Novichkov
|
||||
email : novichko@atnet.ru
|
||||
|
||||
copyright : (C) 2006 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
(original WavPack implementation)
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tstring.h>
|
||||
#include <tdebug.h>
|
||||
#include <bitset>
|
||||
#include "id3v2tag.h"
|
||||
#include "apeproperties.h"
|
||||
#include "apefile.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class APE::Properties::PropertiesPrivate
|
||||
{
|
||||
public:
|
||||
PropertiesPrivate(File *file, long streamLength) :
|
||||
length(0),
|
||||
bitrate(0),
|
||||
sampleRate(0),
|
||||
channels(0),
|
||||
version(0),
|
||||
bitsPerSample(0),
|
||||
sampleFrames(0),
|
||||
file(file),
|
||||
streamLength(streamLength) {}
|
||||
|
||||
int length;
|
||||
int bitrate;
|
||||
int sampleRate;
|
||||
int channels;
|
||||
int version;
|
||||
int bitsPerSample;
|
||||
uint sampleFrames;
|
||||
File *file;
|
||||
long streamLength;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
APE::Properties::Properties(File *file, ReadStyle style) : AudioProperties(style)
|
||||
{
|
||||
d = new PropertiesPrivate(file, file->length());
|
||||
read();
|
||||
}
|
||||
|
||||
APE::Properties::~Properties()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
int APE::Properties::length() const
|
||||
{
|
||||
return d->length;
|
||||
}
|
||||
|
||||
int APE::Properties::bitrate() const
|
||||
{
|
||||
return d->bitrate;
|
||||
}
|
||||
|
||||
int APE::Properties::sampleRate() const
|
||||
{
|
||||
return d->sampleRate;
|
||||
}
|
||||
|
||||
int APE::Properties::channels() const
|
||||
{
|
||||
return d->channels;
|
||||
}
|
||||
|
||||
int APE::Properties::version() const
|
||||
{
|
||||
return d->version;
|
||||
}
|
||||
|
||||
int APE::Properties::bitsPerSample() const
|
||||
{
|
||||
return d->bitsPerSample;
|
||||
}
|
||||
|
||||
TagLib::uint APE::Properties::sampleFrames() const
|
||||
{
|
||||
return d->sampleFrames;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void APE::Properties::read()
|
||||
{
|
||||
// First we are searching the descriptor
|
||||
long offset = findDescriptor();
|
||||
if(offset < 0)
|
||||
return;
|
||||
|
||||
// Then we read the header common for all versions of APE
|
||||
d->file->seek(offset);
|
||||
ByteVector commonHeader=d->file->readBlock(6);
|
||||
if(!commonHeader.startsWith("MAC "))
|
||||
return;
|
||||
d->version = commonHeader.mid(4).toUInt(false);
|
||||
|
||||
if(d->version >= 3980) {
|
||||
analyzeCurrent();
|
||||
}
|
||||
else {
|
||||
analyzeOld();
|
||||
}
|
||||
}
|
||||
|
||||
long APE::Properties::findDescriptor()
|
||||
{
|
||||
long ID3v2Location = findID3v2();
|
||||
long ID3v2OriginalSize = 0;
|
||||
bool hasID3v2 = false;
|
||||
if(ID3v2Location >= 0) {
|
||||
ID3v2::Tag tag(d->file, ID3v2Location);
|
||||
ID3v2OriginalSize = tag.header()->completeTagSize();
|
||||
if(tag.header()->tagSize() > 0)
|
||||
hasID3v2 = true;
|
||||
}
|
||||
|
||||
long offset = 0;
|
||||
if(hasID3v2)
|
||||
offset = d->file->find("MAC ", ID3v2Location + ID3v2OriginalSize);
|
||||
else
|
||||
offset = d->file->find("MAC ");
|
||||
|
||||
if(offset < 0) {
|
||||
debug("APE::Properties::findDescriptor() -- APE descriptor not found");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
long APE::Properties::findID3v2()
|
||||
{
|
||||
if(!d->file->isValid())
|
||||
return -1;
|
||||
|
||||
d->file->seek(0);
|
||||
|
||||
if(d->file->readBlock(3) == ID3v2::Header::fileIdentifier())
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void APE::Properties::analyzeCurrent()
|
||||
{
|
||||
// Read the descriptor
|
||||
d->file->seek(2, File::Current);
|
||||
ByteVector descriptor = d->file->readBlock(44);
|
||||
uint descriptorBytes = descriptor.mid(0,4).toUInt(false);
|
||||
|
||||
if ((descriptorBytes - 52) > 0)
|
||||
d->file->seek(descriptorBytes - 52, File::Current);
|
||||
|
||||
// Read the header
|
||||
ByteVector header = d->file->readBlock(24);
|
||||
|
||||
// Get the APE info
|
||||
d->channels = header.mid(18, 2).toShort(false);
|
||||
d->sampleRate = header.mid(20, 4).toUInt(false);
|
||||
d->bitsPerSample = header.mid(16, 2).toShort(false);
|
||||
//d->compressionLevel =
|
||||
|
||||
uint totalFrames = header.mid(12, 4).toUInt(false);
|
||||
uint blocksPerFrame = header.mid(4, 4).toUInt(false);
|
||||
uint finalFrameBlocks = header.mid(8, 4).toUInt(false);
|
||||
d->sampleFrames = totalFrames > 0 ? (totalFrames - 1) * blocksPerFrame + finalFrameBlocks : 0;
|
||||
d->length = d->sampleRate > 0 ? d->sampleFrames / d->sampleRate : 0;
|
||||
d->bitrate = d->length > 0 ? ((d->streamLength * 8L) / d->length) / 1000 : 0;
|
||||
}
|
||||
|
||||
void APE::Properties::analyzeOld()
|
||||
{
|
||||
ByteVector header = d->file->readBlock(26);
|
||||
uint totalFrames = header.mid(18, 4).toUInt(false);
|
||||
|
||||
// Fail on 0 length APE files (catches non-finalized APE files)
|
||||
if(totalFrames == 0)
|
||||
return;
|
||||
|
||||
short compressionLevel = header.mid(0, 2).toShort(false);
|
||||
uint blocksPerFrame;
|
||||
if(d->version >= 3950)
|
||||
blocksPerFrame = 73728 * 4;
|
||||
else if(d->version >= 3900 || (d->version >= 3800 && compressionLevel == 4000))
|
||||
blocksPerFrame = 73728;
|
||||
else
|
||||
blocksPerFrame = 9216;
|
||||
d->channels = header.mid(4, 2).toShort(false);
|
||||
d->sampleRate = header.mid(6, 4).toUInt(false);
|
||||
uint finalFrameBlocks = header.mid(22, 4).toUInt(false);
|
||||
uint totalBlocks = totalFrames > 0 ? (totalFrames - 1) * blocksPerFrame + finalFrameBlocks : 0;
|
||||
d->length = totalBlocks / d->sampleRate;
|
||||
d->bitrate = d->length > 0 ? ((d->streamLength * 8L) / d->length) / 1000 : 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2010 by Alex Novichkov
|
||||
email : novichko@atnet.ru
|
||||
|
||||
copyright : (C) 2006 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
(original WavPack implementation)
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_APEPROPERTIES_H
|
||||
#define TAGLIB_APEPROPERTIES_H
|
||||
|
||||
#include "taglib_export.h"
|
||||
#include "audioproperties.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace APE {
|
||||
|
||||
class File;
|
||||
|
||||
//! An implementation of audio property reading for APE
|
||||
|
||||
/*!
|
||||
* This reads the data from an APE stream found in the AudioProperties
|
||||
* API.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT Properties : public AudioProperties
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* Create an instance of APE::Properties with the data read from the
|
||||
* ByteVector \a data.
|
||||
*/
|
||||
Properties(File *f, ReadStyle style = Average);
|
||||
|
||||
/*!
|
||||
* Destroys this APE::Properties instance.
|
||||
*/
|
||||
virtual ~Properties();
|
||||
|
||||
// Reimplementations.
|
||||
|
||||
virtual int length() const;
|
||||
virtual int bitrate() const;
|
||||
virtual int sampleRate() const;
|
||||
virtual int channels() const;
|
||||
|
||||
/*!
|
||||
* Returns number of bits per sample.
|
||||
*/
|
||||
int bitsPerSample() const;
|
||||
uint sampleFrames() const;
|
||||
|
||||
/*!
|
||||
* Returns APE version.
|
||||
*/
|
||||
int version() const;
|
||||
|
||||
private:
|
||||
Properties(const Properties &);
|
||||
Properties &operator=(const Properties &);
|
||||
|
||||
void read();
|
||||
|
||||
long findDescriptor();
|
||||
long findID3v2();
|
||||
|
||||
void analyzeCurrent();
|
||||
void analyzeOld();
|
||||
|
||||
class PropertiesPrivate;
|
||||
PropertiesPrivate *d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,383 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||
email : kde@carewolf.com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef __SUNPRO_CC
|
||||
// Sun Studio finds multiple specializations of Map because
|
||||
// it considers specializations with and without class types
|
||||
// to be different; this define forces Map to use only the
|
||||
// specialization with the class keyword.
|
||||
#define WANT_CLASS_INSTANTIATION_OF_MAP (1)
|
||||
#endif
|
||||
|
||||
#include <tfile.h>
|
||||
#include <tstring.h>
|
||||
#include <tmap.h>
|
||||
#include <tpropertymap.h>
|
||||
|
||||
#include "apetag.h"
|
||||
#include "apefooter.h"
|
||||
#include "apeitem.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace APE;
|
||||
|
||||
class APE::Tag::TagPrivate
|
||||
{
|
||||
public:
|
||||
TagPrivate() : file(0), footerLocation(-1), tagLength(0) {}
|
||||
|
||||
TagLib::File *file;
|
||||
long footerLocation;
|
||||
long tagLength;
|
||||
|
||||
Footer footer;
|
||||
|
||||
ItemListMap itemListMap;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
APE::Tag::Tag() : TagLib::Tag()
|
||||
{
|
||||
d = new TagPrivate;
|
||||
}
|
||||
|
||||
APE::Tag::Tag(TagLib::File *file, long footerLocation) : TagLib::Tag()
|
||||
{
|
||||
d = new TagPrivate;
|
||||
d->file = file;
|
||||
d->footerLocation = footerLocation;
|
||||
|
||||
read();
|
||||
}
|
||||
|
||||
APE::Tag::~Tag()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
ByteVector APE::Tag::fileIdentifier()
|
||||
{
|
||||
return ByteVector::fromCString("APETAGEX");
|
||||
}
|
||||
|
||||
String APE::Tag::title() const
|
||||
{
|
||||
if(d->itemListMap["TITLE"].isEmpty())
|
||||
return String::null;
|
||||
return d->itemListMap["TITLE"].toString();
|
||||
}
|
||||
|
||||
String APE::Tag::artist() const
|
||||
{
|
||||
if(d->itemListMap["ARTIST"].isEmpty())
|
||||
return String::null;
|
||||
return d->itemListMap["ARTIST"].toString();
|
||||
}
|
||||
|
||||
String APE::Tag::album() const
|
||||
{
|
||||
if(d->itemListMap["ALBUM"].isEmpty())
|
||||
return String::null;
|
||||
return d->itemListMap["ALBUM"].toString();
|
||||
}
|
||||
|
||||
String APE::Tag::comment() const
|
||||
{
|
||||
if(d->itemListMap["COMMENT"].isEmpty())
|
||||
return String::null;
|
||||
return d->itemListMap["COMMENT"].toString();
|
||||
}
|
||||
|
||||
String APE::Tag::genre() const
|
||||
{
|
||||
if(d->itemListMap["GENRE"].isEmpty())
|
||||
return String::null;
|
||||
return d->itemListMap["GENRE"].toString();
|
||||
}
|
||||
|
||||
TagLib::uint APE::Tag::year() const
|
||||
{
|
||||
if(d->itemListMap["YEAR"].isEmpty())
|
||||
return 0;
|
||||
return d->itemListMap["YEAR"].toString().toInt();
|
||||
}
|
||||
|
||||
TagLib::uint APE::Tag::track() const
|
||||
{
|
||||
if(d->itemListMap["TRACK"].isEmpty())
|
||||
return 0;
|
||||
return d->itemListMap["TRACK"].toString().toInt();
|
||||
}
|
||||
|
||||
void APE::Tag::setTitle(const String &s)
|
||||
{
|
||||
addValue("TITLE", s, true);
|
||||
}
|
||||
|
||||
void APE::Tag::setArtist(const String &s)
|
||||
{
|
||||
addValue("ARTIST", s, true);
|
||||
}
|
||||
|
||||
void APE::Tag::setAlbum(const String &s)
|
||||
{
|
||||
addValue("ALBUM", s, true);
|
||||
}
|
||||
|
||||
void APE::Tag::setComment(const String &s)
|
||||
{
|
||||
addValue("COMMENT", s, true);
|
||||
}
|
||||
|
||||
void APE::Tag::setGenre(const String &s)
|
||||
{
|
||||
addValue("GENRE", s, true);
|
||||
}
|
||||
|
||||
void APE::Tag::setYear(uint i)
|
||||
{
|
||||
if(i <= 0)
|
||||
removeItem("YEAR");
|
||||
else
|
||||
addValue("YEAR", String::number(i), true);
|
||||
}
|
||||
|
||||
void APE::Tag::setTrack(uint i)
|
||||
{
|
||||
if(i <= 0)
|
||||
removeItem("TRACK");
|
||||
else
|
||||
addValue("TRACK", String::number(i), true);
|
||||
}
|
||||
|
||||
// conversions of tag keys between what we use in PropertyMap and what's usual
|
||||
// for APE tags
|
||||
static const TagLib::uint keyConversionsSize = 5; //usual, APE
|
||||
static const char *keyConversions[][2] = {{"TRACKNUMBER", "TRACK" },
|
||||
{"DATE", "YEAR" },
|
||||
{"ALBUMARTIST", "ALBUM ARTIST"},
|
||||
{"DISCNUMBER", "DISC" },
|
||||
{"REMIXER", "MIXARTIST" }};
|
||||
|
||||
PropertyMap APE::Tag::properties() const
|
||||
{
|
||||
PropertyMap properties;
|
||||
ItemListMap::ConstIterator it = itemListMap().begin();
|
||||
for(; it != itemListMap().end(); ++it) {
|
||||
String tagName = it->first.upper();
|
||||
// if the item is Binary or Locator, or if the key is an invalid string,
|
||||
// add to unsupportedData
|
||||
if(it->second.type() != Item::Text || tagName.isNull())
|
||||
properties.unsupportedData().append(it->first);
|
||||
else {
|
||||
// Some tags need to be handled specially
|
||||
for(uint i = 0; i < keyConversionsSize; ++i)
|
||||
if(tagName == keyConversions[i][1])
|
||||
tagName = keyConversions[i][0];
|
||||
properties[tagName].append(it->second.toStringList());
|
||||
}
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
void APE::Tag::removeUnsupportedProperties(const StringList &properties)
|
||||
{
|
||||
StringList::ConstIterator it = properties.begin();
|
||||
for(; it != properties.end(); ++it)
|
||||
removeItem(*it);
|
||||
}
|
||||
|
||||
PropertyMap APE::Tag::setProperties(const PropertyMap &origProps)
|
||||
{
|
||||
PropertyMap properties(origProps); // make a local copy that can be modified
|
||||
|
||||
// see comment in properties()
|
||||
for(uint i = 0; i < keyConversionsSize; ++i)
|
||||
if(properties.contains(keyConversions[i][0])) {
|
||||
properties.insert(keyConversions[i][1], properties[keyConversions[i][0]]);
|
||||
properties.erase(keyConversions[i][0]);
|
||||
}
|
||||
|
||||
// first check if tags need to be removed completely
|
||||
StringList toRemove;
|
||||
ItemListMap::ConstIterator remIt = itemListMap().begin();
|
||||
for(; remIt != itemListMap().end(); ++remIt) {
|
||||
String key = remIt->first.upper();
|
||||
// only remove if a) key is valid, b) type is text, c) key not contained in new properties
|
||||
if(!key.isNull() && remIt->second.type() == APE::Item::Text && !properties.contains(key))
|
||||
toRemove.append(remIt->first);
|
||||
}
|
||||
|
||||
for (StringList::Iterator removeIt = toRemove.begin(); removeIt != toRemove.end(); removeIt++)
|
||||
removeItem(*removeIt);
|
||||
|
||||
// now sync in the "forward direction"
|
||||
PropertyMap::ConstIterator it = properties.begin();
|
||||
PropertyMap invalid;
|
||||
for(; it != properties.end(); ++it) {
|
||||
const String &tagName = it->first;
|
||||
if(!checkKey(tagName))
|
||||
invalid.insert(it->first, it->second);
|
||||
else if(!(itemListMap().contains(tagName)) || !(itemListMap()[tagName].values() == it->second)) {
|
||||
if(it->second.size() == 0)
|
||||
removeItem(tagName);
|
||||
else {
|
||||
StringList::ConstIterator valueIt = it->second.begin();
|
||||
addValue(tagName, *valueIt, true);
|
||||
++valueIt;
|
||||
for(; valueIt != it->second.end(); ++valueIt)
|
||||
addValue(tagName, *valueIt, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
return invalid;
|
||||
}
|
||||
|
||||
bool APE::Tag::checkKey(const String &key)
|
||||
{
|
||||
if(key.size() < 2 || key.size() > 16)
|
||||
return false;
|
||||
for(String::ConstIterator it = key.begin(); it != key.end(); it++)
|
||||
// only allow printable ASCII including space (32..127)
|
||||
if (*it < 32 || *it >= 128)
|
||||
return false;
|
||||
String upperKey = key.upper();
|
||||
if (upperKey=="ID3" || upperKey=="TAG" || upperKey=="OGGS" || upperKey=="MP+")
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
APE::Footer *APE::Tag::footer() const
|
||||
{
|
||||
return &d->footer;
|
||||
}
|
||||
|
||||
const APE::ItemListMap& APE::Tag::itemListMap() const
|
||||
{
|
||||
return d->itemListMap;
|
||||
}
|
||||
|
||||
void APE::Tag::removeItem(const String &key)
|
||||
{
|
||||
Map<const String, Item>::Iterator it = d->itemListMap.find(key.upper());
|
||||
if(it != d->itemListMap.end())
|
||||
d->itemListMap.erase(it);
|
||||
}
|
||||
|
||||
void APE::Tag::addValue(const String &key, const String &value, bool replace)
|
||||
{
|
||||
if(replace)
|
||||
removeItem(key);
|
||||
if(!key.isEmpty() && !value.isEmpty()) {
|
||||
if(!replace && d->itemListMap.contains(key)) {
|
||||
// Text items may contain more than one value
|
||||
if(APE::Item::Text == d->itemListMap.begin()->second.type())
|
||||
d->itemListMap[key.upper()].appendValue(value);
|
||||
// Binary or locator items may have only one value
|
||||
else
|
||||
setItem(key, Item(key, value));
|
||||
}
|
||||
else
|
||||
setItem(key, Item(key, value));
|
||||
}
|
||||
}
|
||||
|
||||
void APE::Tag::setData(const String &key, const ByteVector &value)
|
||||
{
|
||||
removeItem(key);
|
||||
if(!key.isEmpty() && !value.isEmpty())
|
||||
setItem(key, Item(key, value, true));
|
||||
}
|
||||
|
||||
void APE::Tag::setItem(const String &key, const Item &item)
|
||||
{
|
||||
if(!key.isEmpty())
|
||||
d->itemListMap.insert(key.upper(), item);
|
||||
}
|
||||
|
||||
bool APE::Tag::isEmpty() const
|
||||
{
|
||||
return d->itemListMap.isEmpty();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void APE::Tag::read()
|
||||
{
|
||||
if(d->file && d->file->isValid()) {
|
||||
|
||||
d->file->seek(d->footerLocation);
|
||||
d->footer.setData(d->file->readBlock(Footer::size()));
|
||||
|
||||
if(d->footer.tagSize() <= Footer::size() ||
|
||||
d->footer.tagSize() > uint(d->file->length()))
|
||||
return;
|
||||
|
||||
d->file->seek(d->footerLocation + Footer::size() - d->footer.tagSize());
|
||||
parse(d->file->readBlock(d->footer.tagSize() - Footer::size()));
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector APE::Tag::render() const
|
||||
{
|
||||
ByteVector data;
|
||||
uint itemCount = 0;
|
||||
|
||||
{
|
||||
for(Map<const String, Item>::ConstIterator it = d->itemListMap.begin();
|
||||
it != d->itemListMap.end(); ++it)
|
||||
{
|
||||
data.append(it->second.render());
|
||||
itemCount++;
|
||||
}
|
||||
}
|
||||
|
||||
d->footer.setItemCount(itemCount);
|
||||
d->footer.setTagSize(data.size() + Footer::size());
|
||||
d->footer.setHeaderPresent(true);
|
||||
|
||||
return d->footer.renderHeader() + data + d->footer.renderFooter();
|
||||
}
|
||||
|
||||
void APE::Tag::parse(const ByteVector &data)
|
||||
{
|
||||
uint pos = 0;
|
||||
|
||||
// 11 bytes is the minimum size for an APE item
|
||||
|
||||
for(uint i = 0; i < d->footer.itemCount() && pos <= data.size() - 11; i++) {
|
||||
APE::Item item;
|
||||
item.parse(data.mid(pos));
|
||||
|
||||
d->itemListMap.insert(item.key().upper(), item);
|
||||
|
||||
pos += item.size();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,208 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||
email : kde@carewolf.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_APETAG_H
|
||||
#define TAGLIB_APETAG_H
|
||||
|
||||
#include "tag.h"
|
||||
#include "tbytevector.h"
|
||||
#include "tmap.h"
|
||||
#include "tstring.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
#include "apeitem.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
class File;
|
||||
|
||||
//! An implementation of the APE tagging format
|
||||
|
||||
namespace APE {
|
||||
|
||||
class Footer;
|
||||
|
||||
/*!
|
||||
* A mapping between a list of item names, or keys, and the associated item.
|
||||
*
|
||||
* \see APE::Tag::itemListMap()
|
||||
*/
|
||||
typedef Map<const String, Item> ItemListMap;
|
||||
|
||||
|
||||
//! An APE tag implementation
|
||||
|
||||
class TAGLIB_EXPORT Tag : public TagLib::Tag
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* Create an APE tag with default values.
|
||||
*/
|
||||
Tag();
|
||||
|
||||
/*!
|
||||
* Create an APE tag and parse the data in \a file with APE footer at
|
||||
* \a tagOffset.
|
||||
*/
|
||||
Tag(TagLib::File *file, long footerLocation);
|
||||
|
||||
/*!
|
||||
* Destroys this Tag instance.
|
||||
*/
|
||||
virtual ~Tag();
|
||||
|
||||
/*!
|
||||
* Renders the in memory values to a ByteVector suitable for writing to
|
||||
* the file.
|
||||
*/
|
||||
ByteVector render() const;
|
||||
|
||||
/*!
|
||||
* Returns the string "APETAGEX" suitable for usage in locating the tag in a
|
||||
* file.
|
||||
*/
|
||||
static ByteVector fileIdentifier();
|
||||
|
||||
// Reimplementations.
|
||||
|
||||
virtual String title() const;
|
||||
virtual String artist() const;
|
||||
virtual String album() const;
|
||||
virtual String comment() const;
|
||||
virtual String genre() const;
|
||||
virtual uint year() const;
|
||||
virtual uint track() const;
|
||||
|
||||
virtual void setTitle(const String &s);
|
||||
virtual void setArtist(const String &s);
|
||||
virtual void setAlbum(const String &s);
|
||||
virtual void setComment(const String &s);
|
||||
virtual void setGenre(const String &s);
|
||||
virtual void setYear(uint i);
|
||||
virtual void setTrack(uint i);
|
||||
|
||||
/*!
|
||||
* Implements the unified tag dictionary interface -- export function.
|
||||
* APE tags are perfectly compatible with the dictionary interface because they
|
||||
* support both arbitrary tag names and multiple values. Currently only
|
||||
* APE items of type *Text* are handled by the dictionary interface; all *Binary*
|
||||
* and *Locator* items will be put into the unsupportedData list and can be
|
||||
* deleted on request using removeUnsupportedProperties(). The same happens
|
||||
* to Text items if their key is invalid for PropertyMap (which should actually
|
||||
* never happen).
|
||||
*
|
||||
* The only conversion done by this export function is to rename the APE tags
|
||||
* TRACK to TRACKNUMBER, YEAR to DATE, and ALBUM ARTIST to ALBUMARTIST, respectively,
|
||||
* in order to be compliant with the names used in other formats.
|
||||
*/
|
||||
PropertyMap properties() const;
|
||||
|
||||
void removeUnsupportedProperties(const StringList &properties);
|
||||
|
||||
/*!
|
||||
* Implements the unified tag dictionary interface -- import function. The same
|
||||
* comments as for the export function apply; additionally note that the APE tag
|
||||
* specification requires keys to have between 2 and 16 printable ASCII characters
|
||||
* with the exception of the fixed strings "ID3", "TAG", "OGGS", and "MP+".
|
||||
*/
|
||||
PropertyMap setProperties(const PropertyMap &);
|
||||
|
||||
/*!
|
||||
* Check if the given String is a valid APE tag key.
|
||||
*/
|
||||
static bool checkKey(const String&);
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the tag's footer.
|
||||
*/
|
||||
Footer *footer() const;
|
||||
|
||||
/*!
|
||||
* Returns a reference to the item list map. This is an ItemListMap of
|
||||
* all of the items in the tag.
|
||||
*
|
||||
* This is the most powerfull structure for accessing the items of the tag.
|
||||
*
|
||||
* APE tags are case-insensitive, all keys in this map have been converted
|
||||
* to upper case.
|
||||
*
|
||||
* \warning You should not modify this data structure directly, instead
|
||||
* use setItem() and removeItem().
|
||||
*/
|
||||
const ItemListMap &itemListMap() const;
|
||||
|
||||
/*!
|
||||
* Removes the \a key item from the tag
|
||||
*/
|
||||
void removeItem(const String &key);
|
||||
|
||||
/*!
|
||||
* Adds to the text item specified by \a key the data \a value. If \a replace
|
||||
* is true, then all of the other values on the same key will be removed
|
||||
* first. If a binary item exists for \a key it will be removed first.
|
||||
*/
|
||||
void addValue(const String &key, const String &value, bool replace = true);
|
||||
|
||||
/*!
|
||||
* Set the binary data for the key specified by \a item to \a value
|
||||
* This will convert the item to type \a Binary if it isn't already and
|
||||
* all of the other values on the same key will be removed.
|
||||
*/
|
||||
void setData(const String &key, const ByteVector &value);
|
||||
|
||||
/*!
|
||||
* Sets the \a key item to the value of \a item. If an item with the \a key is already
|
||||
* present, it will be replaced.
|
||||
*/
|
||||
void setItem(const String &key, const Item &item);
|
||||
|
||||
/*!
|
||||
* Returns true if the tag does not contain any data.
|
||||
*/
|
||||
bool isEmpty() const;
|
||||
|
||||
protected:
|
||||
|
||||
/*!
|
||||
* Reads from the file specified in the constructor.
|
||||
*/
|
||||
void read();
|
||||
|
||||
/*!
|
||||
* Parses the body of the tag in \a data.
|
||||
*/
|
||||
void parse(const ByteVector &data);
|
||||
|
||||
private:
|
||||
Tag(const Tag &);
|
||||
Tag &operator=(const Tag &);
|
||||
|
||||
class TagPrivate;
|
||||
TagPrivate *d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,353 @@
|
|||
/**************************************************************************
|
||||
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/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <taglib.h>
|
||||
#include <tdebug.h>
|
||||
#include "asfattribute.h"
|
||||
#include "asffile.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class ASF::Attribute::AttributePrivate : public RefCounter
|
||||
{
|
||||
public:
|
||||
AttributePrivate()
|
||||
: pictureValue(ASF::Picture::fromInvalid()),
|
||||
stream(0),
|
||||
language(0) {}
|
||||
AttributeTypes type;
|
||||
String stringValue;
|
||||
ByteVector byteVectorValue;
|
||||
ASF::Picture pictureValue;
|
||||
union {
|
||||
unsigned int intValue;
|
||||
unsigned short shortValue;
|
||||
unsigned long long longLongValue;
|
||||
bool boolValue;
|
||||
};
|
||||
int stream;
|
||||
int language;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ASF::Attribute::Attribute()
|
||||
{
|
||||
d = new AttributePrivate;
|
||||
d->type = UnicodeType;
|
||||
}
|
||||
|
||||
ASF::Attribute::Attribute(const ASF::Attribute &other)
|
||||
: d(other.d)
|
||||
{
|
||||
d->ref();
|
||||
}
|
||||
|
||||
ASF::Attribute &ASF::Attribute::operator=(const ASF::Attribute &other)
|
||||
{
|
||||
if(d->deref())
|
||||
delete d;
|
||||
d = other.d;
|
||||
d->ref();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ASF::Attribute::~Attribute()
|
||||
{
|
||||
if(d->deref())
|
||||
delete d;
|
||||
}
|
||||
|
||||
ASF::Attribute::Attribute(const String &value)
|
||||
{
|
||||
d = new AttributePrivate;
|
||||
d->type = UnicodeType;
|
||||
d->stringValue = value;
|
||||
}
|
||||
|
||||
ASF::Attribute::Attribute(const ByteVector &value)
|
||||
{
|
||||
d = new AttributePrivate;
|
||||
d->type = BytesType;
|
||||
d->byteVectorValue = value;
|
||||
}
|
||||
|
||||
ASF::Attribute::Attribute(const ASF::Picture &value)
|
||||
{
|
||||
d = new AttributePrivate;
|
||||
d->type = BytesType;
|
||||
d->pictureValue = value;
|
||||
}
|
||||
|
||||
ASF::Attribute::Attribute(unsigned int value)
|
||||
{
|
||||
d = new AttributePrivate;
|
||||
d->type = DWordType;
|
||||
d->intValue = value;
|
||||
}
|
||||
|
||||
ASF::Attribute::Attribute(unsigned long long value)
|
||||
{
|
||||
d = new AttributePrivate;
|
||||
d->type = QWordType;
|
||||
d->longLongValue = value;
|
||||
}
|
||||
|
||||
ASF::Attribute::Attribute(unsigned short value)
|
||||
{
|
||||
d = new AttributePrivate;
|
||||
d->type = WordType;
|
||||
d->shortValue = value;
|
||||
}
|
||||
|
||||
ASF::Attribute::Attribute(bool value)
|
||||
{
|
||||
d = new AttributePrivate;
|
||||
d->type = BoolType;
|
||||
d->boolValue = value;
|
||||
}
|
||||
|
||||
ASF::Attribute::AttributeTypes ASF::Attribute::type() const
|
||||
{
|
||||
return d->type;
|
||||
}
|
||||
|
||||
String ASF::Attribute::toString() const
|
||||
{
|
||||
return d->stringValue;
|
||||
}
|
||||
|
||||
ByteVector ASF::Attribute::toByteVector() const
|
||||
{
|
||||
if(d->pictureValue.isValid())
|
||||
return d->pictureValue.render();
|
||||
return d->byteVectorValue;
|
||||
}
|
||||
|
||||
unsigned short ASF::Attribute::toBool() const
|
||||
{
|
||||
return d->shortValue;
|
||||
}
|
||||
|
||||
unsigned short ASF::Attribute::toUShort() const
|
||||
{
|
||||
return d->shortValue;
|
||||
}
|
||||
|
||||
unsigned int ASF::Attribute::toUInt() const
|
||||
{
|
||||
return d->intValue;
|
||||
}
|
||||
|
||||
unsigned long long ASF::Attribute::toULongLong() const
|
||||
{
|
||||
return d->longLongValue;
|
||||
}
|
||||
|
||||
ASF::Picture ASF::Attribute::toPicture() const
|
||||
{
|
||||
return d->pictureValue;
|
||||
}
|
||||
|
||||
String ASF::Attribute::parse(ASF::File &f, int kind)
|
||||
{
|
||||
uint size, nameLength;
|
||||
String name;
|
||||
d->pictureValue = Picture::fromInvalid();
|
||||
// extended content descriptor
|
||||
if(kind == 0) {
|
||||
nameLength = f.readWORD();
|
||||
name = f.readString(nameLength);
|
||||
d->type = ASF::Attribute::AttributeTypes(f.readWORD());
|
||||
size = f.readWORD();
|
||||
}
|
||||
// metadata & metadata library
|
||||
else {
|
||||
int temp = f.readWORD();
|
||||
// metadata library
|
||||
if(kind == 2) {
|
||||
d->language = temp;
|
||||
}
|
||||
d->stream = f.readWORD();
|
||||
nameLength = f.readWORD();
|
||||
d->type = ASF::Attribute::AttributeTypes(f.readWORD());
|
||||
size = f.readDWORD();
|
||||
name = f.readString(nameLength);
|
||||
}
|
||||
|
||||
if(kind != 2 && size > 65535) {
|
||||
debug("ASF::Attribute::parse() -- Value larger than 64kB");
|
||||
}
|
||||
|
||||
switch(d->type) {
|
||||
case WordType:
|
||||
d->shortValue = f.readWORD();
|
||||
break;
|
||||
|
||||
case BoolType:
|
||||
if(kind == 0) {
|
||||
d->boolValue = f.readDWORD() == 1;
|
||||
}
|
||||
else {
|
||||
d->boolValue = f.readWORD() == 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case DWordType:
|
||||
d->intValue = f.readDWORD();
|
||||
break;
|
||||
|
||||
case QWordType:
|
||||
d->longLongValue = f.readQWORD();
|
||||
break;
|
||||
|
||||
case UnicodeType:
|
||||
d->stringValue = f.readString(size);
|
||||
break;
|
||||
|
||||
case BytesType:
|
||||
case GuidType:
|
||||
d->byteVectorValue = f.readBlock(size);
|
||||
break;
|
||||
}
|
||||
|
||||
if(d->type == BytesType && name == "WM/Picture") {
|
||||
d->pictureValue.parse(d->byteVectorValue);
|
||||
if(d->pictureValue.isValid()) {
|
||||
d->byteVectorValue.clear();
|
||||
}
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
int ASF::Attribute::dataSize() const
|
||||
{
|
||||
switch (d->type) {
|
||||
case WordType:
|
||||
return 2;
|
||||
case BoolType:
|
||||
return 4;
|
||||
case DWordType:
|
||||
return 4;
|
||||
case QWordType:
|
||||
return 5;
|
||||
case UnicodeType:
|
||||
return d->stringValue.size() * 2 + 2;
|
||||
case BytesType:
|
||||
if(d->pictureValue.isValid())
|
||||
return d->pictureValue.dataSize();
|
||||
case GuidType:
|
||||
return d->byteVectorValue.size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ByteVector ASF::Attribute::render(const String &name, int kind) const
|
||||
{
|
||||
ByteVector data;
|
||||
|
||||
switch (d->type) {
|
||||
case WordType:
|
||||
data.append(ByteVector::fromShort(d->shortValue, false));
|
||||
break;
|
||||
|
||||
case BoolType:
|
||||
if(kind == 0) {
|
||||
data.append(ByteVector::fromUInt(d->boolValue ? 1 : 0, false));
|
||||
}
|
||||
else {
|
||||
data.append(ByteVector::fromShort(d->boolValue ? 1 : 0, false));
|
||||
}
|
||||
break;
|
||||
|
||||
case DWordType:
|
||||
data.append(ByteVector::fromUInt(d->intValue, false));
|
||||
break;
|
||||
|
||||
case QWordType:
|
||||
data.append(ByteVector::fromLongLong(d->longLongValue, false));
|
||||
break;
|
||||
|
||||
case UnicodeType:
|
||||
data.append(File::renderString(d->stringValue));
|
||||
break;
|
||||
|
||||
case BytesType:
|
||||
if(d->pictureValue.isValid()) {
|
||||
data.append(d->pictureValue.render());
|
||||
break;
|
||||
}
|
||||
case GuidType:
|
||||
data.append(d->byteVectorValue);
|
||||
break;
|
||||
}
|
||||
|
||||
if(kind == 0) {
|
||||
data = File::renderString(name, true) +
|
||||
ByteVector::fromShort((int)d->type, false) +
|
||||
ByteVector::fromShort(data.size(), false) +
|
||||
data;
|
||||
}
|
||||
else {
|
||||
ByteVector nameData = File::renderString(name);
|
||||
data = ByteVector::fromShort(kind == 2 ? d->language : 0, false) +
|
||||
ByteVector::fromShort(d->stream, false) +
|
||||
ByteVector::fromShort(nameData.size(), false) +
|
||||
ByteVector::fromShort((int)d->type, false) +
|
||||
ByteVector::fromUInt(data.size(), false) +
|
||||
nameData +
|
||||
data;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
int ASF::Attribute::language() const
|
||||
{
|
||||
return d->language;
|
||||
}
|
||||
|
||||
void ASF::Attribute::setLanguage(int value)
|
||||
{
|
||||
d->language = value;
|
||||
}
|
||||
|
||||
int ASF::Attribute::stream() const
|
||||
{
|
||||
return d->stream;
|
||||
}
|
||||
|
||||
void ASF::Attribute::setStream(int value)
|
||||
{
|
||||
d->stream = value;
|
||||
}
|
||||
|
|
@ -0,0 +1,203 @@
|
|||
/**************************************************************************
|
||||
copyright : (C) 2005-2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_ASFATTRIBUTE_H
|
||||
#define TAGLIB_ASFATTRIBUTE_H
|
||||
|
||||
#include "tstring.h"
|
||||
#include "tbytevector.h"
|
||||
#include "taglib_export.h"
|
||||
#include "asfpicture.h"
|
||||
|
||||
namespace TagLib
|
||||
{
|
||||
|
||||
namespace ASF
|
||||
{
|
||||
|
||||
class File;
|
||||
class Picture;
|
||||
|
||||
class TAGLIB_EXPORT Attribute
|
||||
{
|
||||
public:
|
||||
|
||||
/*!
|
||||
* Enum of types an Attribute can have.
|
||||
*/
|
||||
enum AttributeTypes {
|
||||
UnicodeType = 0,
|
||||
BytesType = 1,
|
||||
BoolType = 2,
|
||||
DWordType = 3,
|
||||
QWordType = 4,
|
||||
WordType = 5,
|
||||
GuidType = 6
|
||||
};
|
||||
|
||||
/*!
|
||||
* Constructs an empty attribute.
|
||||
*/
|
||||
Attribute();
|
||||
|
||||
/*!
|
||||
* Constructs an attribute with \a key and a UnicodeType \a value.
|
||||
*/
|
||||
Attribute(const String &value);
|
||||
|
||||
/*!
|
||||
* Constructs an attribute with \a key and a BytesType \a value.
|
||||
*/
|
||||
Attribute(const ByteVector &value);
|
||||
|
||||
/*!
|
||||
* Constructs an attribute with \a key and a Picture \a value.
|
||||
*
|
||||
* This attribute is compatible with the ID3 frame, APIC. The ID3 specification for the APIC frame stipulates that,
|
||||
* while there may be any number of APIC frames associated with a file,
|
||||
* only one may be of type 1 and only one may be of type 2.
|
||||
*
|
||||
* The specification also states that the description of the picture can be no longer than 64 characters, but can be empty.
|
||||
* WM/Picture attributes added with TagLib::ASF are not automatically validated to conform to ID3 specifications.
|
||||
* You must add code in your application to perform validations if you want to maintain complete compatibility with ID3.
|
||||
*/
|
||||
Attribute(const Picture &value);
|
||||
|
||||
/*!
|
||||
* Constructs an attribute with \a key and a DWordType \a value.
|
||||
*/
|
||||
Attribute(unsigned int value);
|
||||
|
||||
/*!
|
||||
* Constructs an attribute with \a key and a QWordType \a value.
|
||||
*/
|
||||
Attribute(unsigned long long value);
|
||||
|
||||
/*!
|
||||
* Constructs an attribute with \a key and a WordType \a value.
|
||||
*/
|
||||
Attribute(unsigned short value);
|
||||
|
||||
/*!
|
||||
* Constructs an attribute with \a key and a BoolType \a value.
|
||||
*/
|
||||
Attribute(bool value);
|
||||
|
||||
/*!
|
||||
* Construct an attribute as a copy of \a other.
|
||||
*/
|
||||
Attribute(const Attribute &item);
|
||||
|
||||
/*!
|
||||
* Copies the contents of \a other into this item.
|
||||
*/
|
||||
ASF::Attribute &operator=(const Attribute &other);
|
||||
|
||||
/*!
|
||||
* Destroys the attribute.
|
||||
*/
|
||||
virtual ~Attribute();
|
||||
|
||||
/*!
|
||||
* Returns type of the value.
|
||||
*/
|
||||
AttributeTypes type() const;
|
||||
|
||||
/*!
|
||||
* Returns the BoolType \a value.
|
||||
*/
|
||||
unsigned short toBool() const;
|
||||
|
||||
/*!
|
||||
* Returns the WordType \a value.
|
||||
*/
|
||||
unsigned short toUShort() const;
|
||||
|
||||
/*!
|
||||
* Returns the DWordType \a value.
|
||||
*/
|
||||
unsigned int toUInt() const;
|
||||
|
||||
/*!
|
||||
* Returns the QWordType \a value.
|
||||
*/
|
||||
unsigned long long toULongLong() const;
|
||||
|
||||
/*!
|
||||
* Returns the UnicodeType \a value.
|
||||
*/
|
||||
String toString() const;
|
||||
|
||||
/*!
|
||||
* Returns the BytesType \a value.
|
||||
*/
|
||||
ByteVector toByteVector() const;
|
||||
|
||||
/*!
|
||||
* Returns the Picture \a value.
|
||||
*/
|
||||
Picture toPicture() const;
|
||||
|
||||
/*!
|
||||
* Returns the language number, or 0 is no stream number was set.
|
||||
*/
|
||||
int language() const;
|
||||
|
||||
/*!
|
||||
* Sets the language number.
|
||||
*/
|
||||
void setLanguage(int value);
|
||||
|
||||
/*!
|
||||
* Returns the stream number, or 0 is no stream number was set.
|
||||
*/
|
||||
int stream() const;
|
||||
|
||||
/*!
|
||||
* Sets the stream number.
|
||||
*/
|
||||
void setStream(int value);
|
||||
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
/* THIS IS PRIVATE, DON'T TOUCH IT! */
|
||||
String parse(ASF::File &file, int kind = 0);
|
||||
#endif
|
||||
|
||||
//! Returns the size of the stored data
|
||||
int dataSize() const;
|
||||
|
||||
private:
|
||||
friend class File;
|
||||
|
||||
ByteVector render(const String &name, int kind = 0) const;
|
||||
|
||||
class AttributePrivate;
|
||||
AttributePrivate *d;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,615 @@
|
|||
/**************************************************************************
|
||||
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/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <tdebug.h>
|
||||
#include <tbytevectorlist.h>
|
||||
#include <tstring.h>
|
||||
#include "asffile.h"
|
||||
#include "asftag.h"
|
||||
#include "asfproperties.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class ASF::File::FilePrivate
|
||||
{
|
||||
public:
|
||||
FilePrivate():
|
||||
size(0),
|
||||
tag(0),
|
||||
properties(0),
|
||||
contentDescriptionObject(0),
|
||||
extendedContentDescriptionObject(0),
|
||||
headerExtensionObject(0),
|
||||
metadataObject(0),
|
||||
metadataLibraryObject(0) {}
|
||||
unsigned long long size;
|
||||
ASF::Tag *tag;
|
||||
ASF::Properties *properties;
|
||||
List<ASF::File::BaseObject *> objects;
|
||||
ASF::File::ContentDescriptionObject *contentDescriptionObject;
|
||||
ASF::File::ExtendedContentDescriptionObject *extendedContentDescriptionObject;
|
||||
ASF::File::HeaderExtensionObject *headerExtensionObject;
|
||||
ASF::File::MetadataObject *metadataObject;
|
||||
ASF::File::MetadataLibraryObject *metadataLibraryObject;
|
||||
};
|
||||
|
||||
static ByteVector headerGuid("\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
|
||||
static ByteVector filePropertiesGuid("\xA1\xDC\xAB\x8C\x47\xA9\xCF\x11\x8E\xE4\x00\xC0\x0C\x20\x53\x65", 16);
|
||||
static ByteVector streamPropertiesGuid("\x91\x07\xDC\xB7\xB7\xA9\xCF\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65", 16);
|
||||
static ByteVector contentDescriptionGuid("\x33\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C", 16);
|
||||
static ByteVector extendedContentDescriptionGuid("\x40\xA4\xD0\xD2\x07\xE3\xD2\x11\x97\xF0\x00\xA0\xC9\x5E\xA8\x50", 16);
|
||||
static ByteVector headerExtensionGuid("\xb5\x03\xbf_.\xa9\xcf\x11\x8e\xe3\x00\xc0\x0c Se", 16);
|
||||
static ByteVector metadataGuid("\xEA\xCB\xF8\xC5\xAF[wH\204g\xAA\214D\xFAL\xCA", 16);
|
||||
static ByteVector metadataLibraryGuid("\224\034#D\230\224\321I\241A\x1d\x13NEpT", 16);
|
||||
static ByteVector contentEncryptionGuid("\xFB\xB3\x11\x22\x23\xBD\xD2\x11\xB4\xB7\x00\xA0\xC9\x55\xFC\x6E", 16);
|
||||
static ByteVector extendedContentEncryptionGuid("\x14\xE6\x8A\x29\x22\x26 \x17\x4C\xB9\x35\xDA\xE0\x7E\xE9\x28\x9C", 16);
|
||||
static ByteVector advancedContentEncryptionGuid("\xB6\x9B\x07\x7A\xA4\xDA\x12\x4E\xA5\xCA\x91\xD3\x8D\xC1\x1A\x8D", 16);
|
||||
|
||||
class ASF::File::BaseObject
|
||||
{
|
||||
public:
|
||||
ByteVector data;
|
||||
virtual ~BaseObject() {}
|
||||
virtual ByteVector guid() = 0;
|
||||
virtual void parse(ASF::File *file, unsigned int size);
|
||||
virtual ByteVector render(ASF::File *file);
|
||||
};
|
||||
|
||||
class ASF::File::UnknownObject : public ASF::File::BaseObject
|
||||
{
|
||||
ByteVector myGuid;
|
||||
public:
|
||||
UnknownObject(const ByteVector &guid);
|
||||
ByteVector guid();
|
||||
};
|
||||
|
||||
class ASF::File::FilePropertiesObject : public ASF::File::BaseObject
|
||||
{
|
||||
public:
|
||||
ByteVector guid();
|
||||
void parse(ASF::File *file, uint size);
|
||||
};
|
||||
|
||||
class ASF::File::StreamPropertiesObject : public ASF::File::BaseObject
|
||||
{
|
||||
public:
|
||||
ByteVector guid();
|
||||
void parse(ASF::File *file, uint size);
|
||||
};
|
||||
|
||||
class ASF::File::ContentDescriptionObject : public ASF::File::BaseObject
|
||||
{
|
||||
public:
|
||||
ByteVector guid();
|
||||
void parse(ASF::File *file, uint size);
|
||||
ByteVector render(ASF::File *file);
|
||||
};
|
||||
|
||||
class ASF::File::ExtendedContentDescriptionObject : public ASF::File::BaseObject
|
||||
{
|
||||
public:
|
||||
ByteVectorList attributeData;
|
||||
ByteVector guid();
|
||||
void parse(ASF::File *file, uint size);
|
||||
ByteVector render(ASF::File *file);
|
||||
};
|
||||
|
||||
class ASF::File::MetadataObject : public ASF::File::BaseObject
|
||||
{
|
||||
public:
|
||||
ByteVectorList attributeData;
|
||||
ByteVector guid();
|
||||
void parse(ASF::File *file, uint size);
|
||||
ByteVector render(ASF::File *file);
|
||||
};
|
||||
|
||||
class ASF::File::MetadataLibraryObject : public ASF::File::BaseObject
|
||||
{
|
||||
public:
|
||||
ByteVectorList attributeData;
|
||||
ByteVector guid();
|
||||
void parse(ASF::File *file, uint size);
|
||||
ByteVector render(ASF::File *file);
|
||||
};
|
||||
|
||||
class ASF::File::HeaderExtensionObject : public ASF::File::BaseObject
|
||||
{
|
||||
public:
|
||||
List<ASF::File::BaseObject *> objects;
|
||||
~HeaderExtensionObject();
|
||||
ByteVector guid();
|
||||
void parse(ASF::File *file, uint size);
|
||||
ByteVector render(ASF::File *file);
|
||||
};
|
||||
|
||||
ASF::File::HeaderExtensionObject::~HeaderExtensionObject()
|
||||
{
|
||||
for(unsigned int i = 0; i < objects.size(); i++) {
|
||||
delete objects[i];
|
||||
}
|
||||
}
|
||||
|
||||
void ASF::File::BaseObject::parse(ASF::File *file, unsigned int size)
|
||||
{
|
||||
data.clear();
|
||||
if (size > 24 && size <= (unsigned int)(file->length()))
|
||||
data = file->readBlock(size - 24);
|
||||
else
|
||||
data = ByteVector::null;
|
||||
}
|
||||
|
||||
ByteVector ASF::File::BaseObject::render(ASF::File * /*file*/)
|
||||
{
|
||||
return guid() + ByteVector::fromLongLong(data.size() + 24, false) + data;
|
||||
}
|
||||
|
||||
ASF::File::UnknownObject::UnknownObject(const ByteVector &guid) : myGuid(guid)
|
||||
{
|
||||
}
|
||||
|
||||
ByteVector ASF::File::UnknownObject::guid()
|
||||
{
|
||||
return myGuid;
|
||||
}
|
||||
|
||||
ByteVector ASF::File::FilePropertiesObject::guid()
|
||||
{
|
||||
return filePropertiesGuid;
|
||||
}
|
||||
|
||||
void ASF::File::FilePropertiesObject::parse(ASF::File *file, uint size)
|
||||
{
|
||||
BaseObject::parse(file, size);
|
||||
file->d->properties->setLength((int)(data.mid(40, 8).toLongLong(false) / 10000000L - data.mid(56, 8).toLongLong(false) / 1000L));
|
||||
}
|
||||
|
||||
ByteVector ASF::File::StreamPropertiesObject::guid()
|
||||
{
|
||||
return streamPropertiesGuid;
|
||||
}
|
||||
|
||||
void ASF::File::StreamPropertiesObject::parse(ASF::File *file, uint size)
|
||||
{
|
||||
BaseObject::parse(file, size);
|
||||
file->d->properties->setChannels(data.mid(56, 2).toShort(false));
|
||||
file->d->properties->setSampleRate(data.mid(58, 4).toUInt(false));
|
||||
file->d->properties->setBitrate(data.mid(62, 4).toUInt(false) * 8 / 1000);
|
||||
}
|
||||
|
||||
ByteVector ASF::File::ContentDescriptionObject::guid()
|
||||
{
|
||||
return contentDescriptionGuid;
|
||||
}
|
||||
|
||||
void ASF::File::ContentDescriptionObject::parse(ASF::File *file, uint /*size*/)
|
||||
{
|
||||
file->d->contentDescriptionObject = this;
|
||||
int titleLength = file->readWORD();
|
||||
int artistLength = file->readWORD();
|
||||
int copyrightLength = file->readWORD();
|
||||
int commentLength = file->readWORD();
|
||||
int ratingLength = file->readWORD();
|
||||
file->d->tag->setTitle(file->readString(titleLength));
|
||||
file->d->tag->setArtist(file->readString(artistLength));
|
||||
file->d->tag->setCopyright(file->readString(copyrightLength));
|
||||
file->d->tag->setComment(file->readString(commentLength));
|
||||
file->d->tag->setRating(file->readString(ratingLength));
|
||||
}
|
||||
|
||||
ByteVector ASF::File::ContentDescriptionObject::render(ASF::File *file)
|
||||
{
|
||||
ByteVector v1 = file->renderString(file->d->tag->title());
|
||||
ByteVector v2 = file->renderString(file->d->tag->artist());
|
||||
ByteVector v3 = file->renderString(file->d->tag->copyright());
|
||||
ByteVector v4 = file->renderString(file->d->tag->comment());
|
||||
ByteVector v5 = file->renderString(file->d->tag->rating());
|
||||
data.clear();
|
||||
data.append(ByteVector::fromShort(v1.size(), false));
|
||||
data.append(ByteVector::fromShort(v2.size(), false));
|
||||
data.append(ByteVector::fromShort(v3.size(), false));
|
||||
data.append(ByteVector::fromShort(v4.size(), false));
|
||||
data.append(ByteVector::fromShort(v5.size(), false));
|
||||
data.append(v1);
|
||||
data.append(v2);
|
||||
data.append(v3);
|
||||
data.append(v4);
|
||||
data.append(v5);
|
||||
return BaseObject::render(file);
|
||||
}
|
||||
|
||||
ByteVector ASF::File::ExtendedContentDescriptionObject::guid()
|
||||
{
|
||||
return extendedContentDescriptionGuid;
|
||||
}
|
||||
|
||||
void ASF::File::ExtendedContentDescriptionObject::parse(ASF::File *file, uint /*size*/)
|
||||
{
|
||||
file->d->extendedContentDescriptionObject = this;
|
||||
int count = file->readWORD();
|
||||
while(count--) {
|
||||
ASF::Attribute attribute;
|
||||
String name = attribute.parse(*file);
|
||||
file->d->tag->addAttribute(name, attribute);
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector ASF::File::ExtendedContentDescriptionObject::render(ASF::File *file)
|
||||
{
|
||||
data.clear();
|
||||
data.append(ByteVector::fromShort(attributeData.size(), false));
|
||||
data.append(attributeData.toByteVector(ByteVector::null));
|
||||
return BaseObject::render(file);
|
||||
}
|
||||
|
||||
ByteVector ASF::File::MetadataObject::guid()
|
||||
{
|
||||
return metadataGuid;
|
||||
}
|
||||
|
||||
void ASF::File::MetadataObject::parse(ASF::File *file, uint /*size*/)
|
||||
{
|
||||
file->d->metadataObject = this;
|
||||
int count = file->readWORD();
|
||||
while(count--) {
|
||||
ASF::Attribute attribute;
|
||||
String name = attribute.parse(*file, 1);
|
||||
file->d->tag->addAttribute(name, attribute);
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector ASF::File::MetadataObject::render(ASF::File *file)
|
||||
{
|
||||
data.clear();
|
||||
data.append(ByteVector::fromShort(attributeData.size(), false));
|
||||
data.append(attributeData.toByteVector(ByteVector::null));
|
||||
return BaseObject::render(file);
|
||||
}
|
||||
|
||||
ByteVector ASF::File::MetadataLibraryObject::guid()
|
||||
{
|
||||
return metadataLibraryGuid;
|
||||
}
|
||||
|
||||
void ASF::File::MetadataLibraryObject::parse(ASF::File *file, uint /*size*/)
|
||||
{
|
||||
file->d->metadataLibraryObject = this;
|
||||
int count = file->readWORD();
|
||||
while(count--) {
|
||||
ASF::Attribute attribute;
|
||||
String name = attribute.parse(*file, 2);
|
||||
file->d->tag->addAttribute(name, attribute);
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector ASF::File::MetadataLibraryObject::render(ASF::File *file)
|
||||
{
|
||||
data.clear();
|
||||
data.append(ByteVector::fromShort(attributeData.size(), false));
|
||||
data.append(attributeData.toByteVector(ByteVector::null));
|
||||
return BaseObject::render(file);
|
||||
}
|
||||
|
||||
ByteVector ASF::File::HeaderExtensionObject::guid()
|
||||
{
|
||||
return headerExtensionGuid;
|
||||
}
|
||||
|
||||
void ASF::File::HeaderExtensionObject::parse(ASF::File *file, uint /*size*/)
|
||||
{
|
||||
file->d->headerExtensionObject = this;
|
||||
file->seek(18, File::Current);
|
||||
long long dataSize = file->readDWORD();
|
||||
long long dataPos = 0;
|
||||
while(dataPos < dataSize) {
|
||||
ByteVector guid = file->readBlock(16);
|
||||
if(guid.size() != 16) {
|
||||
file->setValid(false);
|
||||
break;
|
||||
}
|
||||
bool ok;
|
||||
long long size = file->readQWORD(&ok);
|
||||
if(!ok) {
|
||||
file->setValid(false);
|
||||
break;
|
||||
}
|
||||
BaseObject *obj;
|
||||
if(guid == metadataGuid) {
|
||||
obj = new MetadataObject();
|
||||
}
|
||||
else if(guid == metadataLibraryGuid) {
|
||||
obj = new MetadataLibraryObject();
|
||||
}
|
||||
else {
|
||||
obj = new UnknownObject(guid);
|
||||
}
|
||||
obj->parse(file, (unsigned int)size);
|
||||
objects.append(obj);
|
||||
dataPos += size;
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector ASF::File::HeaderExtensionObject::render(ASF::File *file)
|
||||
{
|
||||
data.clear();
|
||||
for(unsigned int i = 0; i < objects.size(); i++) {
|
||||
data.append(objects[i]->render(file));
|
||||
}
|
||||
data = ByteVector("\x11\xD2\xD3\xAB\xBA\xA9\xcf\x11\x8E\xE6\x00\xC0\x0C\x20\x53\x65\x06\x00", 18) + ByteVector::fromUInt(data.size(), false) + data;
|
||||
return BaseObject::render(file);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ASF::File::File(FileName file, bool readProperties, Properties::ReadStyle propertiesStyle)
|
||||
: TagLib::File(file)
|
||||
{
|
||||
d = new FilePrivate;
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
ASF::File::File(IOStream *stream, bool readProperties, Properties::ReadStyle propertiesStyle)
|
||||
: TagLib::File(stream)
|
||||
{
|
||||
d = new FilePrivate;
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
ASF::File::~File()
|
||||
{
|
||||
for(unsigned int i = 0; i < d->objects.size(); i++) {
|
||||
delete d->objects[i];
|
||||
}
|
||||
if(d->tag) {
|
||||
delete d->tag;
|
||||
}
|
||||
if(d->properties) {
|
||||
delete d->properties;
|
||||
}
|
||||
delete d;
|
||||
}
|
||||
|
||||
ASF::Tag *ASF::File::tag() const
|
||||
{
|
||||
return d->tag;
|
||||
}
|
||||
|
||||
ASF::Properties *ASF::File::audioProperties() const
|
||||
{
|
||||
return d->properties;
|
||||
}
|
||||
|
||||
void ASF::File::read(bool /*readProperties*/, Properties::ReadStyle /*propertiesStyle*/)
|
||||
{
|
||||
if(!isValid())
|
||||
return;
|
||||
|
||||
ByteVector guid = readBlock(16);
|
||||
if(guid != headerGuid) {
|
||||
debug("ASF: Not an ASF file.");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
d->tag = new ASF::Tag();
|
||||
d->properties = new ASF::Properties();
|
||||
|
||||
bool ok;
|
||||
d->size = readQWORD(&ok);
|
||||
if(!ok) {
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
int numObjects = readDWORD(&ok);
|
||||
if(!ok) {
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
seek(2, Current);
|
||||
|
||||
for(int i = 0; i < numObjects; i++) {
|
||||
ByteVector guid = readBlock(16);
|
||||
if(guid.size() != 16) {
|
||||
setValid(false);
|
||||
break;
|
||||
}
|
||||
long size = (long)readQWORD(&ok);
|
||||
if(!ok) {
|
||||
setValid(false);
|
||||
break;
|
||||
}
|
||||
BaseObject *obj;
|
||||
if(guid == filePropertiesGuid) {
|
||||
obj = new FilePropertiesObject();
|
||||
}
|
||||
else if(guid == streamPropertiesGuid) {
|
||||
obj = new StreamPropertiesObject();
|
||||
}
|
||||
else if(guid == contentDescriptionGuid) {
|
||||
obj = new ContentDescriptionObject();
|
||||
}
|
||||
else if(guid == extendedContentDescriptionGuid) {
|
||||
obj = new ExtendedContentDescriptionObject();
|
||||
}
|
||||
else if(guid == headerExtensionGuid) {
|
||||
obj = new HeaderExtensionObject();
|
||||
}
|
||||
else {
|
||||
if(guid == contentEncryptionGuid ||
|
||||
guid == extendedContentEncryptionGuid ||
|
||||
guid == advancedContentEncryptionGuid) {
|
||||
d->properties->setEncrypted(true);
|
||||
}
|
||||
obj = new UnknownObject(guid);
|
||||
}
|
||||
obj->parse(this, size);
|
||||
d->objects.append(obj);
|
||||
}
|
||||
}
|
||||
|
||||
bool ASF::File::save()
|
||||
{
|
||||
if(readOnly()) {
|
||||
debug("ASF::File::save() -- File is read only.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!isValid()) {
|
||||
debug("ASF::File::save() -- Trying to save invalid file.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!d->contentDescriptionObject) {
|
||||
d->contentDescriptionObject = new ContentDescriptionObject();
|
||||
d->objects.append(d->contentDescriptionObject);
|
||||
}
|
||||
if(!d->extendedContentDescriptionObject) {
|
||||
d->extendedContentDescriptionObject = new ExtendedContentDescriptionObject();
|
||||
d->objects.append(d->extendedContentDescriptionObject);
|
||||
}
|
||||
if(!d->headerExtensionObject) {
|
||||
d->headerExtensionObject = new HeaderExtensionObject();
|
||||
d->objects.append(d->headerExtensionObject);
|
||||
}
|
||||
if(!d->metadataObject) {
|
||||
d->metadataObject = new MetadataObject();
|
||||
d->headerExtensionObject->objects.append(d->metadataObject);
|
||||
}
|
||||
if(!d->metadataLibraryObject) {
|
||||
d->metadataLibraryObject = new MetadataLibraryObject();
|
||||
d->headerExtensionObject->objects.append(d->metadataLibraryObject);
|
||||
}
|
||||
|
||||
ASF::AttributeListMap::ConstIterator it = d->tag->attributeListMap().begin();
|
||||
for(; it != d->tag->attributeListMap().end(); it++) {
|
||||
const String &name = it->first;
|
||||
const AttributeList &attributes = it->second;
|
||||
bool inExtendedContentDescriptionObject = false;
|
||||
bool inMetadataObject = false;
|
||||
for(unsigned int j = 0; j < attributes.size(); j++) {
|
||||
const Attribute &attribute = attributes[j];
|
||||
bool largeValue = attribute.dataSize() > 65535;
|
||||
if(!inExtendedContentDescriptionObject && !largeValue && attribute.language() == 0 && attribute.stream() == 0) {
|
||||
d->extendedContentDescriptionObject->attributeData.append(attribute.render(name));
|
||||
inExtendedContentDescriptionObject = true;
|
||||
}
|
||||
else if(!inMetadataObject && !largeValue && attribute.language() == 0 && attribute.stream() != 0) {
|
||||
d->metadataObject->attributeData.append(attribute.render(name, 1));
|
||||
inMetadataObject = true;
|
||||
}
|
||||
else {
|
||||
d->metadataLibraryObject->attributeData.append(attribute.render(name, 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector data;
|
||||
for(unsigned int i = 0; i < d->objects.size(); i++) {
|
||||
data.append(d->objects[i]->render(this));
|
||||
}
|
||||
data = headerGuid + ByteVector::fromLongLong(data.size() + 30, false) + ByteVector::fromUInt(d->objects.size(), false) + ByteVector("\x01\x02", 2) + data;
|
||||
insert(data, 0, (TagLib::ulong)d->size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int ASF::File::readBYTE(bool *ok)
|
||||
{
|
||||
ByteVector v = readBlock(1);
|
||||
if(v.size() != 1) {
|
||||
if(ok) *ok = false;
|
||||
return 0;
|
||||
}
|
||||
if(ok) *ok = true;
|
||||
return v[0];
|
||||
}
|
||||
|
||||
int ASF::File::readWORD(bool *ok)
|
||||
{
|
||||
ByteVector v = readBlock(2);
|
||||
if(v.size() != 2) {
|
||||
if(ok) *ok = false;
|
||||
return 0;
|
||||
}
|
||||
if(ok) *ok = true;
|
||||
return v.toUShort(false);
|
||||
}
|
||||
|
||||
unsigned int ASF::File::readDWORD(bool *ok)
|
||||
{
|
||||
ByteVector v = readBlock(4);
|
||||
if(v.size() != 4) {
|
||||
if(ok) *ok = false;
|
||||
return 0;
|
||||
}
|
||||
if(ok) *ok = true;
|
||||
return v.toUInt(false);
|
||||
}
|
||||
|
||||
long long ASF::File::readQWORD(bool *ok)
|
||||
{
|
||||
ByteVector v = readBlock(8);
|
||||
if(v.size() != 8) {
|
||||
if(ok) *ok = false;
|
||||
return 0;
|
||||
}
|
||||
if(ok) *ok = true;
|
||||
return v.toLongLong(false);
|
||||
}
|
||||
|
||||
String ASF::File::readString(int length)
|
||||
{
|
||||
ByteVector data = readBlock(length);
|
||||
unsigned int size = data.size();
|
||||
while (size >= 2) {
|
||||
if(data[size - 1] != '\0' || data[size - 2] != '\0') {
|
||||
break;
|
||||
}
|
||||
size -= 2;
|
||||
}
|
||||
if(size != data.size()) {
|
||||
data.resize(size);
|
||||
}
|
||||
return String(data, String::UTF16LE);
|
||||
}
|
||||
|
||||
ByteVector ASF::File::renderString(const String &str, bool includeLength)
|
||||
{
|
||||
ByteVector data = str.data(String::UTF16LE) + ByteVector::fromShort(0, false);
|
||||
if(includeLength) {
|
||||
data = ByteVector::fromShort(data.size(), false) + data;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
/**************************************************************************
|
||||
copyright : (C) 2005-2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_ASFFILE_H
|
||||
#define TAGLIB_ASFFILE_H
|
||||
|
||||
#include "tag.h"
|
||||
#include "tfile.h"
|
||||
#include "taglib_export.h"
|
||||
#include "asfproperties.h"
|
||||
#include "asftag.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
//! An implementation of ASF (WMA) metadata
|
||||
namespace ASF {
|
||||
|
||||
/*!
|
||||
* This implements and provides an interface for ASF files to the
|
||||
* TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing
|
||||
* the abstract TagLib::File API as well as providing some additional
|
||||
* information specific to ASF files.
|
||||
*/
|
||||
class TAGLIB_EXPORT File : public TagLib::File
|
||||
{
|
||||
public:
|
||||
|
||||
/*!
|
||||
* Contructs an ASF file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*
|
||||
* \note In the current implementation, both \a readProperties and
|
||||
* \a propertiesStyle are ignored.
|
||||
*
|
||||
* \note TagLib will *not* take ownership of the stream, the caller is
|
||||
* responsible for deleting it after the File object.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Contructs an ASF file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*
|
||||
* \note In the current implementation, both \a readProperties and
|
||||
* \a propertiesStyle are ignored.
|
||||
*
|
||||
* \note TagLib will *not* take ownership of the stream, the caller is
|
||||
* responsible for deleting it after the File object.
|
||||
*/
|
||||
File(IOStream *stream, bool readProperties = true, Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
virtual ~File();
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the ASF tag of the file.
|
||||
*
|
||||
* ASF::Tag implements the tag interface, so this serves as the
|
||||
* reimplementation of TagLib::File::tag().
|
||||
*
|
||||
* \note The Tag <b>is still</b> owned by the ASF::File and should not be
|
||||
* deleted by the user. It will be deleted when the file (object) is
|
||||
* destroyed.
|
||||
*/
|
||||
virtual Tag *tag() const;
|
||||
|
||||
/*!
|
||||
* Returns the ASF audio properties for this file.
|
||||
*/
|
||||
virtual Properties *audioProperties() const;
|
||||
|
||||
/*!
|
||||
* Save the file.
|
||||
*
|
||||
* This returns true if the save was successful.
|
||||
*/
|
||||
virtual bool save();
|
||||
|
||||
private:
|
||||
|
||||
int readBYTE(bool *ok = 0);
|
||||
int readWORD(bool *ok = 0);
|
||||
unsigned int readDWORD(bool *ok = 0);
|
||||
long long readQWORD(bool *ok = 0);
|
||||
static ByteVector renderString(const String &str, bool includeLength = false);
|
||||
String readString(int len);
|
||||
void read(bool readProperties, Properties::ReadStyle propertiesStyle);
|
||||
|
||||
friend class Attribute;
|
||||
friend class Picture;
|
||||
|
||||
class BaseObject;
|
||||
class UnknownObject;
|
||||
class FilePropertiesObject;
|
||||
class StreamPropertiesObject;
|
||||
class ContentDescriptionObject;
|
||||
class ExtendedContentDescriptionObject;
|
||||
class HeaderExtensionObject;
|
||||
class MetadataObject;
|
||||
class MetadataLibraryObject;
|
||||
|
||||
class FilePrivate;
|
||||
FilePrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,182 @@
|
|||
/**************************************************************************
|
||||
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/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <taglib.h>
|
||||
#include <tdebug.h>
|
||||
#include "asfattribute.h"
|
||||
#include "asffile.h"
|
||||
#include "asfpicture.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class ASF::Picture::PicturePrivate : public RefCounter
|
||||
{
|
||||
public:
|
||||
bool valid;
|
||||
Type type;
|
||||
String mimeType;
|
||||
String description;
|
||||
ByteVector picture;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Picture class members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ASF::Picture::Picture()
|
||||
{
|
||||
d = new PicturePrivate();
|
||||
d->valid = true;
|
||||
}
|
||||
|
||||
ASF::Picture::Picture(const Picture& other)
|
||||
: d(other.d)
|
||||
{
|
||||
d->ref();
|
||||
}
|
||||
|
||||
ASF::Picture::~Picture()
|
||||
{
|
||||
if(d->deref())
|
||||
delete d;
|
||||
}
|
||||
|
||||
bool ASF::Picture::isValid() const
|
||||
{
|
||||
return d->valid;
|
||||
}
|
||||
|
||||
String ASF::Picture::mimeType() const
|
||||
{
|
||||
return d->mimeType;
|
||||
}
|
||||
|
||||
void ASF::Picture::setMimeType(const String &value)
|
||||
{
|
||||
d->mimeType = value;
|
||||
}
|
||||
|
||||
ASF::Picture::Type ASF::Picture::type() const
|
||||
{
|
||||
return d->type;
|
||||
}
|
||||
|
||||
void ASF::Picture::setType(const ASF::Picture::Type& t)
|
||||
{
|
||||
d->type = t;
|
||||
}
|
||||
|
||||
String ASF::Picture::description() const
|
||||
{
|
||||
return d->description;
|
||||
}
|
||||
|
||||
void ASF::Picture::setDescription(const String &desc)
|
||||
{
|
||||
d->description = desc;
|
||||
}
|
||||
|
||||
ByteVector ASF::Picture::picture() const
|
||||
{
|
||||
return d->picture;
|
||||
}
|
||||
|
||||
void ASF::Picture::setPicture(const ByteVector &p)
|
||||
{
|
||||
d->picture = p;
|
||||
}
|
||||
|
||||
int ASF::Picture::dataSize() const
|
||||
{
|
||||
return
|
||||
9 + (d->mimeType.length() + d->description.length()) * 2 +
|
||||
d->picture.size();
|
||||
}
|
||||
|
||||
ASF::Picture& ASF::Picture::operator=(const ASF::Picture& other)
|
||||
{
|
||||
if(other.d != d) {
|
||||
if(d->deref())
|
||||
delete d;
|
||||
d = other.d;
|
||||
d->ref();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ByteVector ASF::Picture::render() const
|
||||
{
|
||||
if(!isValid())
|
||||
return ByteVector::null;
|
||||
return
|
||||
ByteVector((char)d->type) +
|
||||
ByteVector::fromUInt(d->picture.size(), false) +
|
||||
ASF::File::renderString(d->mimeType) +
|
||||
ASF::File::renderString(d->description) +
|
||||
d->picture;
|
||||
}
|
||||
|
||||
void ASF::Picture::parse(const ByteVector& bytes)
|
||||
{
|
||||
d->valid = false;
|
||||
if(bytes.size() < 9)
|
||||
return;
|
||||
int pos = 0;
|
||||
d->type = (Type)bytes[0]; ++pos;
|
||||
uint dataLen = bytes.mid(pos, 4).toUInt(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;
|
||||
}
|
||||
|
|
@ -0,0 +1,217 @@
|
|||
/**************************************************************************
|
||||
copyright : (C) 2010 by Anton Sergunov
|
||||
email : setosha@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef ASFPICTURE_H
|
||||
#define ASFPICTURE_H
|
||||
|
||||
#include "tstring.h"
|
||||
#include "tbytevector.h"
|
||||
#include "taglib_export.h"
|
||||
#include "attachedpictureframe.h"
|
||||
|
||||
namespace TagLib
|
||||
{
|
||||
namespace ASF
|
||||
{
|
||||
|
||||
//! An ASF attached picture interface implementation
|
||||
|
||||
/*!
|
||||
* This is an implementation of ASF attached pictures interface. Pictures may be
|
||||
* included in attributes, one per WM/Picture attribute (but there may be multiple WM/Picture
|
||||
* attribute in a single tag). These pictures are usually in either JPEG or
|
||||
* PNG format.
|
||||
* \see Attribute::toPicture()
|
||||
* \see Attribute::Attribute(const Picture& picture)
|
||||
*/
|
||||
class TAGLIB_EXPORT Picture {
|
||||
public:
|
||||
|
||||
/*!
|
||||
* This describes the function or content of the picture.
|
||||
*/
|
||||
enum Type {
|
||||
//! A type not enumerated below
|
||||
Other = 0x00,
|
||||
//! 32x32 PNG image that should be used as the file icon
|
||||
FileIcon = 0x01,
|
||||
//! File icon of a different size or format
|
||||
OtherFileIcon = 0x02,
|
||||
//! Front cover image of the album
|
||||
FrontCover = 0x03,
|
||||
//! Back cover image of the album
|
||||
BackCover = 0x04,
|
||||
//! Inside leaflet page of the album
|
||||
LeafletPage = 0x05,
|
||||
//! Image from the album itself
|
||||
Media = 0x06,
|
||||
//! Picture of the lead artist or soloist
|
||||
LeadArtist = 0x07,
|
||||
//! Picture of the artist or performer
|
||||
Artist = 0x08,
|
||||
//! Picture of the conductor
|
||||
Conductor = 0x09,
|
||||
//! Picture of the band or orchestra
|
||||
Band = 0x0A,
|
||||
//! Picture of the composer
|
||||
Composer = 0x0B,
|
||||
//! Picture of the lyricist or text writer
|
||||
Lyricist = 0x0C,
|
||||
//! Picture of the recording location or studio
|
||||
RecordingLocation = 0x0D,
|
||||
//! Picture of the artists during recording
|
||||
DuringRecording = 0x0E,
|
||||
//! Picture of the artists during performance
|
||||
DuringPerformance = 0x0F,
|
||||
//! Picture from a movie or video related to the track
|
||||
MovieScreenCapture = 0x10,
|
||||
//! Picture of a large, coloured fish
|
||||
ColouredFish = 0x11,
|
||||
//! Illustration related to the track
|
||||
Illustration = 0x12,
|
||||
//! Logo of the band or performer
|
||||
BandLogo = 0x13,
|
||||
//! Logo of the publisher (record company)
|
||||
PublisherLogo = 0x14
|
||||
};
|
||||
|
||||
/*!
|
||||
* Constructs an empty picture.
|
||||
*/
|
||||
Picture();
|
||||
|
||||
/*!
|
||||
* Construct an picture as a copy of \a other.
|
||||
*/
|
||||
Picture(const Picture& other);
|
||||
|
||||
/*!
|
||||
* Destroys the picture.
|
||||
*/
|
||||
virtual ~Picture();
|
||||
|
||||
/*!
|
||||
* Copies the contents of \a other into this picture.
|
||||
*/
|
||||
Picture& operator=(const Picture& other);
|
||||
|
||||
/*!
|
||||
* Returns true if Picture stores valid picture
|
||||
*/
|
||||
bool isValid() const;
|
||||
|
||||
/*!
|
||||
* Returns the mime type of the image. This should in most cases be
|
||||
* "image/png" or "image/jpeg".
|
||||
* \see setMimeType(const String &)
|
||||
* \see picture()
|
||||
* \see setPicture(const ByteArray&)
|
||||
*/
|
||||
String mimeType() const;
|
||||
|
||||
/*!
|
||||
* Sets the mime type of the image. This should in most cases be
|
||||
* "image/png" or "image/jpeg".
|
||||
* \see setMimeType(const String &)
|
||||
* \see picture()
|
||||
* \see setPicture(const ByteArray&)
|
||||
*/
|
||||
void setMimeType(const String &value);
|
||||
|
||||
/*!
|
||||
* Returns the type of the image.
|
||||
*
|
||||
* \see Type
|
||||
* \see setType()
|
||||
*/
|
||||
Type type() const;
|
||||
|
||||
/*!
|
||||
* Sets the type for the image.
|
||||
*
|
||||
* \see Type
|
||||
* \see type()
|
||||
*/
|
||||
void setType(const ASF::Picture::Type& t);
|
||||
|
||||
/*!
|
||||
* Returns a text description of the image.
|
||||
*
|
||||
* \see setDescription()
|
||||
*/
|
||||
String description() const;
|
||||
|
||||
/*!
|
||||
* Sets a textual description of the image to \a desc.
|
||||
*
|
||||
* \see description()
|
||||
*/
|
||||
void setDescription(const String &desc);
|
||||
|
||||
/*!
|
||||
* Returns the image data as a ByteVector.
|
||||
*
|
||||
* \note ByteVector has a data() method that returns a const char * which
|
||||
* should make it easy to export this data to external programs.
|
||||
*
|
||||
* \see setPicture()
|
||||
* \see mimeType()
|
||||
*/
|
||||
ByteVector picture() const;
|
||||
|
||||
/*!
|
||||
* Sets the image data to \a p. \a p should be of the type specified in
|
||||
* this frame's mime-type specification.
|
||||
*
|
||||
* \see picture()
|
||||
* \see mimeType()
|
||||
* \see setMimeType()
|
||||
*/
|
||||
void setPicture(const ByteVector &p);
|
||||
|
||||
/*!
|
||||
* Returns picture as binary raw data \a value
|
||||
*/
|
||||
ByteVector render() const;
|
||||
|
||||
/*!
|
||||
* Returns picture as binary raw data \a value
|
||||
*/
|
||||
int dataSize() const;
|
||||
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
/* THIS IS PRIVATE, DON'T TOUCH IT! */
|
||||
void parse(const ByteVector& );
|
||||
static Picture fromInvalid();
|
||||
friend class Attribute;
|
||||
#endif
|
||||
private:
|
||||
class PicturePrivate;
|
||||
PicturePrivate *d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ASFPICTURE_H
|
|
@ -0,0 +1,115 @@
|
|||
/**************************************************************************
|
||||
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/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <tdebug.h>
|
||||
#include <tstring.h>
|
||||
#include "asfproperties.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class ASF::Properties::PropertiesPrivate
|
||||
{
|
||||
public:
|
||||
PropertiesPrivate(): length(0), bitrate(0), sampleRate(0), channels(0), encrypted(false) {}
|
||||
int length;
|
||||
int bitrate;
|
||||
int sampleRate;
|
||||
int channels;
|
||||
bool encrypted;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ASF::Properties::Properties() : AudioProperties(AudioProperties::Average)
|
||||
{
|
||||
d = new PropertiesPrivate;
|
||||
}
|
||||
|
||||
ASF::Properties::~Properties()
|
||||
{
|
||||
if(d)
|
||||
delete d;
|
||||
}
|
||||
|
||||
int ASF::Properties::length() const
|
||||
{
|
||||
return d->length;
|
||||
}
|
||||
|
||||
int ASF::Properties::bitrate() const
|
||||
{
|
||||
return d->bitrate;
|
||||
}
|
||||
|
||||
int ASF::Properties::sampleRate() const
|
||||
{
|
||||
return d->sampleRate;
|
||||
}
|
||||
|
||||
int ASF::Properties::channels() const
|
||||
{
|
||||
return d->channels;
|
||||
}
|
||||
|
||||
bool ASF::Properties::isEncrypted() const
|
||||
{
|
||||
return d->encrypted;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ASF::Properties::setLength(int length)
|
||||
{
|
||||
d->length = length;
|
||||
}
|
||||
|
||||
void ASF::Properties::setBitrate(int length)
|
||||
{
|
||||
d->bitrate = length;
|
||||
}
|
||||
|
||||
void ASF::Properties::setSampleRate(int length)
|
||||
{
|
||||
d->sampleRate = length;
|
||||
}
|
||||
|
||||
void ASF::Properties::setChannels(int length)
|
||||
{
|
||||
d->channels = length;
|
||||
}
|
||||
|
||||
void ASF::Properties::setEncrypted(bool encrypted)
|
||||
{
|
||||
d->encrypted = encrypted;
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
/**************************************************************************
|
||||
copyright : (C) 2005-2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_ASFPROPERTIES_H
|
||||
#define TAGLIB_ASFPROPERTIES_H
|
||||
|
||||
#include "audioproperties.h"
|
||||
#include "tstring.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ASF {
|
||||
|
||||
//! An implementation of ASF audio properties
|
||||
class TAGLIB_EXPORT Properties : public AudioProperties
|
||||
{
|
||||
public:
|
||||
|
||||
/*!
|
||||
* Create an instance of ASF::Properties.
|
||||
*/
|
||||
Properties();
|
||||
|
||||
/*!
|
||||
* Destroys this ASF::Properties instance.
|
||||
*/
|
||||
virtual ~Properties();
|
||||
|
||||
// Reimplementations.
|
||||
virtual int length() const;
|
||||
virtual int bitrate() const;
|
||||
virtual int sampleRate() const;
|
||||
virtual int channels() const;
|
||||
bool isEncrypted() const;
|
||||
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
void setLength(int value);
|
||||
void setBitrate(int value);
|
||||
void setSampleRate(int value);
|
||||
void setChannels(int value);
|
||||
void setEncrypted(bool value);
|
||||
#endif
|
||||
|
||||
private:
|
||||
class PropertiesPrivate;
|
||||
PropertiesPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,198 @@
|
|||
/**************************************************************************
|
||||
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/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include "asftag.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class ASF::Tag::TagPrivate
|
||||
{
|
||||
public:
|
||||
String title;
|
||||
String artist;
|
||||
String copyright;
|
||||
String comment;
|
||||
String rating;
|
||||
AttributeListMap attributeListMap;
|
||||
};
|
||||
|
||||
ASF::Tag::Tag()
|
||||
: TagLib::Tag()
|
||||
{
|
||||
d = new TagPrivate;
|
||||
}
|
||||
|
||||
ASF::Tag::~Tag()
|
||||
{
|
||||
if(d)
|
||||
delete d;
|
||||
}
|
||||
|
||||
String ASF::Tag::title() const
|
||||
{
|
||||
return d->title;
|
||||
}
|
||||
|
||||
String ASF::Tag::artist() const
|
||||
{
|
||||
return d->artist;
|
||||
}
|
||||
|
||||
String ASF::Tag::album() const
|
||||
{
|
||||
if(d->attributeListMap.contains("WM/AlbumTitle"))
|
||||
return d->attributeListMap["WM/AlbumTitle"][0].toString();
|
||||
return String::null;
|
||||
}
|
||||
|
||||
String ASF::Tag::copyright() const
|
||||
{
|
||||
return d->copyright;
|
||||
}
|
||||
|
||||
String ASF::Tag::comment() const
|
||||
{
|
||||
return d->comment;
|
||||
}
|
||||
|
||||
String ASF::Tag::rating() const
|
||||
{
|
||||
return d->rating;
|
||||
}
|
||||
|
||||
unsigned int ASF::Tag::year() const
|
||||
{
|
||||
if(d->attributeListMap.contains("WM/Year"))
|
||||
return d->attributeListMap["WM/Year"][0].toString().toInt();
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int ASF::Tag::track() const
|
||||
{
|
||||
if(d->attributeListMap.contains("WM/TrackNumber")) {
|
||||
const ASF::Attribute attr = d->attributeListMap["WM/TrackNumber"][0];
|
||||
if(attr.type() == ASF::Attribute::DWordType)
|
||||
return attr.toUInt();
|
||||
else
|
||||
return attr.toString().toInt();
|
||||
}
|
||||
if(d->attributeListMap.contains("WM/Track"))
|
||||
return d->attributeListMap["WM/Track"][0].toUInt();
|
||||
return 0;
|
||||
}
|
||||
|
||||
String ASF::Tag::genre() const
|
||||
{
|
||||
if(d->attributeListMap.contains("WM/Genre"))
|
||||
return d->attributeListMap["WM/Genre"][0].toString();
|
||||
return String::null;
|
||||
}
|
||||
|
||||
void ASF::Tag::setTitle(const String &value)
|
||||
{
|
||||
d->title = value;
|
||||
}
|
||||
|
||||
void ASF::Tag::setArtist(const String &value)
|
||||
{
|
||||
d->artist = value;
|
||||
}
|
||||
|
||||
void ASF::Tag::setCopyright(const String &value)
|
||||
{
|
||||
d->copyright = value;
|
||||
}
|
||||
|
||||
void ASF::Tag::setComment(const String &value)
|
||||
{
|
||||
d->comment = value;
|
||||
}
|
||||
|
||||
void ASF::Tag::setRating(const String &value)
|
||||
{
|
||||
d->rating = value;
|
||||
}
|
||||
|
||||
void ASF::Tag::setAlbum(const String &value)
|
||||
{
|
||||
setAttribute("WM/AlbumTitle", value);
|
||||
}
|
||||
|
||||
void ASF::Tag::setGenre(const String &value)
|
||||
{
|
||||
setAttribute("WM/Genre", value);
|
||||
}
|
||||
|
||||
void ASF::Tag::setYear(uint value)
|
||||
{
|
||||
setAttribute("WM/Year", String::number(value));
|
||||
}
|
||||
|
||||
void ASF::Tag::setTrack(uint value)
|
||||
{
|
||||
setAttribute("WM/TrackNumber", String::number(value));
|
||||
}
|
||||
|
||||
ASF::AttributeListMap& ASF::Tag::attributeListMap()
|
||||
{
|
||||
return d->attributeListMap;
|
||||
}
|
||||
|
||||
void ASF::Tag::removeItem(const String &key)
|
||||
{
|
||||
AttributeListMap::Iterator it = d->attributeListMap.find(key);
|
||||
if(it != d->attributeListMap.end())
|
||||
d->attributeListMap.erase(it);
|
||||
}
|
||||
|
||||
void ASF::Tag::setAttribute(const String &name, const Attribute &attribute)
|
||||
{
|
||||
AttributeList value;
|
||||
value.append(attribute);
|
||||
d->attributeListMap.insert(name, value);
|
||||
}
|
||||
|
||||
void ASF::Tag::addAttribute(const String &name, const Attribute &attribute)
|
||||
{
|
||||
if(d->attributeListMap.contains(name)) {
|
||||
d->attributeListMap[name].append(attribute);
|
||||
}
|
||||
else {
|
||||
setAttribute(name, attribute);
|
||||
}
|
||||
}
|
||||
|
||||
bool ASF::Tag::isEmpty() const
|
||||
{
|
||||
return TagLib::Tag::isEmpty() &&
|
||||
copyright().isEmpty() &&
|
||||
rating().isEmpty() &&
|
||||
d->attributeListMap.isEmpty();
|
||||
}
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
/**************************************************************************
|
||||
copyright : (C) 2005-2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_ASFTAG_H
|
||||
#define TAGLIB_ASFTAG_H
|
||||
|
||||
#include "tag.h"
|
||||
#include "tlist.h"
|
||||
#include "tmap.h"
|
||||
#include "taglib_export.h"
|
||||
#include "asfattribute.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ASF {
|
||||
|
||||
typedef List<Attribute> AttributeList;
|
||||
typedef Map<String, AttributeList> AttributeListMap;
|
||||
|
||||
class TAGLIB_EXPORT Tag : public TagLib::Tag {
|
||||
|
||||
friend class File;
|
||||
|
||||
public:
|
||||
|
||||
Tag();
|
||||
|
||||
virtual ~Tag();
|
||||
|
||||
/*!
|
||||
* Returns the track name.
|
||||
*/
|
||||
virtual String title() const;
|
||||
|
||||
/*!
|
||||
* Returns the artist name.
|
||||
*/
|
||||
virtual String artist() const;
|
||||
|
||||
/*!
|
||||
* Returns the album name; if no album name is present in the tag
|
||||
* String::null will be returned.
|
||||
*/
|
||||
virtual String album() const;
|
||||
|
||||
/*!
|
||||
* Returns the track comment.
|
||||
*/
|
||||
virtual String comment() const;
|
||||
|
||||
/*!
|
||||
* Returns the genre name; if no genre is present in the tag String::null
|
||||
* will be returned.
|
||||
*/
|
||||
virtual String genre() const;
|
||||
|
||||
/*!
|
||||
* Returns the rating.
|
||||
*/
|
||||
virtual String rating() const;
|
||||
|
||||
/*!
|
||||
* Returns the genre name; if no genre is present in the tag String::null
|
||||
* will be returned.
|
||||
*/
|
||||
virtual String copyright() const;
|
||||
|
||||
/*!
|
||||
* Returns the year; if there is no year set, this will return 0.
|
||||
*/
|
||||
virtual uint year() const;
|
||||
|
||||
/*!
|
||||
* Returns the track number; if there is no track number set, this will
|
||||
* return 0.
|
||||
*/
|
||||
virtual uint track() const;
|
||||
|
||||
/*!
|
||||
* Sets the title to \a s.
|
||||
*/
|
||||
virtual void setTitle(const String &s);
|
||||
|
||||
/*!
|
||||
* Sets the artist to \a s.
|
||||
*/
|
||||
virtual void setArtist(const String &s);
|
||||
|
||||
/*!
|
||||
* Sets the album to \a s. If \a s is String::null then this value will be
|
||||
* cleared.
|
||||
*/
|
||||
virtual void setAlbum(const String &s);
|
||||
|
||||
/*!
|
||||
* Sets the comment to \a s.
|
||||
*/
|
||||
virtual void setComment(const String &s);
|
||||
|
||||
/*!
|
||||
* Sets the rating to \a s.
|
||||
*/
|
||||
virtual void setRating(const String &s);
|
||||
|
||||
/*!
|
||||
* Sets the copyright to \a s.
|
||||
*/
|
||||
virtual void setCopyright(const String &s);
|
||||
|
||||
/*!
|
||||
* Sets the genre to \a s.
|
||||
*/
|
||||
virtual void setGenre(const String &s);
|
||||
|
||||
/*!
|
||||
* Sets the year to \a i. If \a s is 0 then this value will be cleared.
|
||||
*/
|
||||
virtual void setYear(uint i);
|
||||
|
||||
/*!
|
||||
* Sets the track to \a i. If \a s is 0 then this value will be cleared.
|
||||
*/
|
||||
virtual void setTrack(uint i);
|
||||
|
||||
/*!
|
||||
* Returns true if the tag does not contain any data. This should be
|
||||
* reimplemented in subclasses that provide more than the basic tagging
|
||||
* abilities in this class.
|
||||
*/
|
||||
virtual bool isEmpty() const;
|
||||
|
||||
/*!
|
||||
* Returns a reference to the item list map. This is an AttributeListMap of
|
||||
* all of the items in the tag.
|
||||
*
|
||||
* This is the most powerfull structure for accessing the items of the tag.
|
||||
*/
|
||||
AttributeListMap &attributeListMap();
|
||||
|
||||
/*!
|
||||
* Removes the \a key attribute from the tag
|
||||
*/
|
||||
void removeItem(const String &name);
|
||||
|
||||
/*!
|
||||
* Sets the \a key attribute to the value of \a attribute. If an attribute
|
||||
* with the \a key is already present, it will be replaced.
|
||||
*/
|
||||
void setAttribute(const String &name, const Attribute &attribute);
|
||||
|
||||
/*!
|
||||
* Sets the \a key attribute to the value of \a attribute. If an attribute
|
||||
* with the \a key is already present, it will be added to the list.
|
||||
*/
|
||||
void addAttribute(const String &name, const Attribute &attribute);
|
||||
|
||||
private:
|
||||
|
||||
class TagPrivate;
|
||||
TagPrivate *d;
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,51 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include "audioproperties.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class AudioProperties::AudioPropertiesPrivate
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AudioProperties::~AudioProperties()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AudioProperties::AudioProperties(ReadStyle)
|
||||
{
|
||||
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_AUDIOPROPERTIES_H
|
||||
#define TAGLIB_AUDIOPROPERTIES_H
|
||||
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
//! A simple, abstract interface to common audio properties
|
||||
|
||||
/*!
|
||||
* The values here are common to most audio formats. For more specific, codec
|
||||
* dependant values, please see see the subclasses APIs. This is meant to
|
||||
* compliment the TagLib::File and TagLib::Tag APIs in providing a simple
|
||||
* interface that is sufficient for most applications.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT AudioProperties
|
||||
{
|
||||
public:
|
||||
|
||||
/*!
|
||||
* Reading audio properties from a file can sometimes be very time consuming
|
||||
* and for the most accurate results can often involve reading the entire
|
||||
* file. Because in many situations speed is critical or the accuracy of the
|
||||
* values is not particularly important this allows the level of desired
|
||||
* accuracy to be set.
|
||||
*/
|
||||
enum ReadStyle {
|
||||
//! Read as little of the file as possible
|
||||
Fast,
|
||||
//! Read more of the file and make better values guesses
|
||||
Average,
|
||||
//! Read as much of the file as needed to report accurate values
|
||||
Accurate
|
||||
};
|
||||
|
||||
/*!
|
||||
* Destroys this AudioProperties instance.
|
||||
*/
|
||||
virtual ~AudioProperties();
|
||||
|
||||
/*!
|
||||
* Returns the length of the file in seconds.
|
||||
*/
|
||||
virtual int length() const = 0;
|
||||
|
||||
/*!
|
||||
* Returns the most appropriate bit rate for the file in kb/s. For constant
|
||||
* bitrate formats this is simply the bitrate of the file. For variable
|
||||
* bitrate formats this is either the average or nominal bitrate.
|
||||
*/
|
||||
virtual int bitrate() const = 0;
|
||||
|
||||
/*!
|
||||
* Returns the sample rate in Hz.
|
||||
*/
|
||||
virtual int sampleRate() const = 0;
|
||||
|
||||
/*!
|
||||
* Returns the number of audio channels.
|
||||
*/
|
||||
virtual int channels() const = 0;
|
||||
|
||||
protected:
|
||||
|
||||
/*!
|
||||
* Construct an audio properties instance. This is protected as this class
|
||||
* should not be instantiated directly, but should be instantiated via its
|
||||
* subclasses and can be fetched from the FileRef or File APIs.
|
||||
*
|
||||
* \see ReadStyle
|
||||
*/
|
||||
AudioProperties(ReadStyle style);
|
||||
|
||||
private:
|
||||
AudioProperties(const AudioProperties &);
|
||||
AudioProperties &operator=(const AudioProperties &);
|
||||
|
||||
class AudioPropertiesPrivate;
|
||||
AudioPropertiesPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,279 @@
|
|||
/***************************************************************************
|
||||
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/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <tfile.h>
|
||||
#include <tstring.h>
|
||||
#include <tdebug.h>
|
||||
|
||||
#include "fileref.h"
|
||||
#include "asffile.h"
|
||||
#include "mpegfile.h"
|
||||
#include "vorbisfile.h"
|
||||
#include "flacfile.h"
|
||||
#include "oggflacfile.h"
|
||||
#include "mpcfile.h"
|
||||
#include "mp4file.h"
|
||||
#include "wavpackfile.h"
|
||||
#include "speexfile.h"
|
||||
#include "trueaudiofile.h"
|
||||
#include "aifffile.h"
|
||||
#include "wavfile.h"
|
||||
#include "apefile.h"
|
||||
#include "modfile.h"
|
||||
#include "s3mfile.h"
|
||||
#include "itfile.h"
|
||||
#include "xmfile.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class FileRef::FileRefPrivate : public RefCounter
|
||||
{
|
||||
public:
|
||||
FileRefPrivate(File *f) : RefCounter(), file(f) {}
|
||||
~FileRefPrivate() {
|
||||
delete file;
|
||||
}
|
||||
|
||||
File *file;
|
||||
static List<const FileTypeResolver *> fileTypeResolvers;
|
||||
};
|
||||
|
||||
List<const FileRef::FileTypeResolver *> FileRef::FileRefPrivate::fileTypeResolvers;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FileRef::FileRef()
|
||||
{
|
||||
d = new FileRefPrivate(0);
|
||||
}
|
||||
|
||||
FileRef::FileRef(FileName fileName, bool readAudioProperties,
|
||||
AudioProperties::ReadStyle audioPropertiesStyle)
|
||||
{
|
||||
d = new FileRefPrivate(create(fileName, readAudioProperties, audioPropertiesStyle));
|
||||
}
|
||||
|
||||
FileRef::FileRef(File *file)
|
||||
{
|
||||
d = new FileRefPrivate(file);
|
||||
}
|
||||
|
||||
FileRef::FileRef(const FileRef &ref) : d(ref.d)
|
||||
{
|
||||
d->ref();
|
||||
}
|
||||
|
||||
FileRef::~FileRef()
|
||||
{
|
||||
if(d->deref())
|
||||
delete d;
|
||||
}
|
||||
|
||||
Tag *FileRef::tag() const
|
||||
{
|
||||
if(isNull()) {
|
||||
debug("FileRef::tag() - Called without a valid file.");
|
||||
return 0;
|
||||
}
|
||||
return d->file->tag();
|
||||
}
|
||||
|
||||
AudioProperties *FileRef::audioProperties() const
|
||||
{
|
||||
if(isNull()) {
|
||||
debug("FileRef::audioProperties() - Called without a valid file.");
|
||||
return 0;
|
||||
}
|
||||
return d->file->audioProperties();
|
||||
}
|
||||
|
||||
File *FileRef::file() const
|
||||
{
|
||||
return d->file;
|
||||
}
|
||||
|
||||
bool FileRef::save()
|
||||
{
|
||||
if(isNull()) {
|
||||
debug("FileRef::save() - Called without a valid file.");
|
||||
return false;
|
||||
}
|
||||
return d->file->save();
|
||||
}
|
||||
|
||||
const FileRef::FileTypeResolver *FileRef::addFileTypeResolver(const FileRef::FileTypeResolver *resolver) // static
|
||||
{
|
||||
FileRefPrivate::fileTypeResolvers.prepend(resolver);
|
||||
return resolver;
|
||||
}
|
||||
|
||||
StringList FileRef::defaultFileExtensions()
|
||||
{
|
||||
StringList l;
|
||||
|
||||
l.append("ogg");
|
||||
l.append("flac");
|
||||
l.append("oga");
|
||||
l.append("mp3");
|
||||
l.append("mpc");
|
||||
l.append("wv");
|
||||
l.append("spx");
|
||||
l.append("tta");
|
||||
l.append("m4a");
|
||||
l.append("m4r");
|
||||
l.append("m4b");
|
||||
l.append("m4p");
|
||||
l.append("3g2");
|
||||
l.append("mp4");
|
||||
l.append("wma");
|
||||
l.append("asf");
|
||||
l.append("aif");
|
||||
l.append("aiff");
|
||||
l.append("wav");
|
||||
l.append("ape");
|
||||
l.append("mod");
|
||||
l.append("module"); // alias for "mod"
|
||||
l.append("nst"); // alias for "mod"
|
||||
l.append("wow"); // alias for "mod"
|
||||
l.append("s3m");
|
||||
l.append("it");
|
||||
l.append("xm");
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
bool FileRef::isNull() const
|
||||
{
|
||||
return !d->file || !d->file->isValid();
|
||||
}
|
||||
|
||||
FileRef &FileRef::operator=(const FileRef &ref)
|
||||
{
|
||||
if(&ref == this)
|
||||
return *this;
|
||||
|
||||
if(d->deref())
|
||||
delete d;
|
||||
|
||||
d = ref.d;
|
||||
d->ref();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool FileRef::operator==(const FileRef &ref) const
|
||||
{
|
||||
return ref.d->file == d->file;
|
||||
}
|
||||
|
||||
bool FileRef::operator!=(const FileRef &ref) const
|
||||
{
|
||||
return ref.d->file != d->file;
|
||||
}
|
||||
|
||||
File *FileRef::create(FileName fileName, bool readAudioProperties,
|
||||
AudioProperties::ReadStyle audioPropertiesStyle) // static
|
||||
{
|
||||
|
||||
List<const FileTypeResolver *>::ConstIterator it = FileRefPrivate::fileTypeResolvers.begin();
|
||||
|
||||
for(; it != FileRefPrivate::fileTypeResolvers.end(); ++it) {
|
||||
File *file = (*it)->createFile(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(file)
|
||||
return file;
|
||||
}
|
||||
|
||||
// Ok, this is really dumb for now, but it works for testing.
|
||||
|
||||
String s;
|
||||
|
||||
#ifdef _WIN32
|
||||
s = (wcslen((const wchar_t *) fileName) > 0) ? String((const wchar_t *) fileName) : String((const char *) fileName);
|
||||
#else
|
||||
s = fileName;
|
||||
#endif
|
||||
|
||||
// If this list is updated, the method defaultFileExtensions() should also be
|
||||
// updated. However at some point that list should be created at the same time
|
||||
// that a default file type resolver is created.
|
||||
|
||||
int pos = s.rfind(".");
|
||||
if(pos != -1) {
|
||||
String ext = s.substr(pos + 1).upper();
|
||||
if(ext == "MP3")
|
||||
return new MPEG::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "OGG")
|
||||
return new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "OGA") {
|
||||
/* .oga can be any audio in the Ogg container. First try FLAC, then Vorbis. */
|
||||
File *file = new Ogg::FLAC::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if (file->isValid())
|
||||
return file;
|
||||
delete file;
|
||||
return new Ogg::Vorbis::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
}
|
||||
if(ext == "FLAC")
|
||||
return new FLAC::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "MPC")
|
||||
return new MPC::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "WV")
|
||||
return new WavPack::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "SPX")
|
||||
return new Ogg::Speex::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "TTA")
|
||||
return new TrueAudio::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "M4A" || ext == "M4R" || ext == "M4B" || ext == "M4P" || ext == "MP4" || ext == "3G2")
|
||||
return new MP4::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "WMA" || ext == "ASF")
|
||||
return new ASF::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "AIF" || ext == "AIFF")
|
||||
return new RIFF::AIFF::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "WAV")
|
||||
return new RIFF::WAV::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "APE")
|
||||
return new APE::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
// module, nst and wow are possible but uncommon extensions
|
||||
if(ext == "MOD" || ext == "MODULE" || ext == "NST" || ext == "WOW")
|
||||
return new Mod::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "S3M")
|
||||
return new S3M::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "IT")
|
||||
return new IT::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
if(ext == "XM")
|
||||
return new XM::File(fileName, readAudioProperties, audioPropertiesStyle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,263 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_FILEREF_H
|
||||
#define TAGLIB_FILEREF_H
|
||||
|
||||
#include "tfile.h"
|
||||
#include "tstringlist.h"
|
||||
|
||||
#include "taglib_export.h"
|
||||
#include "audioproperties.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
class Tag;
|
||||
|
||||
//! This class provides a simple abstraction for creating and handling files
|
||||
|
||||
/*!
|
||||
* FileRef exists to provide a minimal, generic and value-based wrapper around
|
||||
* a File. It is lightweight and implicitly shared, and as such suitable for
|
||||
* pass-by-value use. This hides some of the uglier details of TagLib::File
|
||||
* and the non-generic portions of the concrete file implementations.
|
||||
*
|
||||
* This class is useful in a "simple usage" situation where it is desirable
|
||||
* to be able to get and set some of the tag information that is similar
|
||||
* across file types.
|
||||
*
|
||||
* Also note that it is probably a good idea to plug this into your mime
|
||||
* type system rather than using the constructor that accepts a file name using
|
||||
* the FileTypeResolver.
|
||||
*
|
||||
* \see FileTypeResolver
|
||||
* \see addFileTypeResolver()
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT FileRef
|
||||
{
|
||||
public:
|
||||
|
||||
//! A class for pluggable file type resolution.
|
||||
|
||||
/*!
|
||||
* This class is used to add extend TagLib's very basic file name based file
|
||||
* type resolution.
|
||||
*
|
||||
* This can be accomplished with:
|
||||
*
|
||||
* \code
|
||||
*
|
||||
* class MyFileTypeResolver : FileTypeResolver
|
||||
* {
|
||||
* TagLib::File *createFile(TagLib::FileName *fileName, bool, AudioProperties::ReadStyle)
|
||||
* {
|
||||
* if(someCheckForAnMP3File(fileName))
|
||||
* return new TagLib::MPEG::File(fileName);
|
||||
* return 0;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* FileRef::addFileTypeResolver(new MyFileTypeResolver);
|
||||
*
|
||||
* \endcode
|
||||
*
|
||||
* Naturally a less contrived example would be slightly more complex. This
|
||||
* can be used to plug in mime-type detection systems or to add new file types
|
||||
* to TagLib.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT FileTypeResolver
|
||||
{
|
||||
TAGLIB_IGNORE_MISSING_DESTRUCTOR
|
||||
public:
|
||||
/*!
|
||||
* This method must be overridden to provide an additional file type
|
||||
* resolver. If the resolver is able to determine the file type it should
|
||||
* return a valid File object; if not it should return 0.
|
||||
*
|
||||
* \note The created file is then owned by the FileRef and should not be
|
||||
* deleted. Deletion will happen automatically when the FileRef passes
|
||||
* out of scope.
|
||||
*/
|
||||
virtual File *createFile(FileName fileName,
|
||||
bool readAudioProperties = true,
|
||||
AudioProperties::ReadStyle
|
||||
audioPropertiesStyle = AudioProperties::Average) const = 0;
|
||||
};
|
||||
|
||||
/*!
|
||||
* Creates a null FileRef.
|
||||
*/
|
||||
FileRef();
|
||||
|
||||
/*!
|
||||
* Create a FileRef from \a fileName. If \a readAudioProperties is true then
|
||||
* the audio properties will be read using \a audioPropertiesStyle. If
|
||||
* \a readAudioProperties is false then \a audioPropertiesStyle will be
|
||||
* ignored.
|
||||
*
|
||||
* Also see the note in the class documentation about why you may not want to
|
||||
* use this method in your application.
|
||||
*/
|
||||
explicit FileRef(FileName fileName,
|
||||
bool readAudioProperties = true,
|
||||
AudioProperties::ReadStyle
|
||||
audioPropertiesStyle = AudioProperties::Average);
|
||||
|
||||
/*!
|
||||
* Contruct a FileRef using \a file. The FileRef now takes ownership of the
|
||||
* pointer and will delete the File when it passes out of scope.
|
||||
*/
|
||||
explicit FileRef(File *file);
|
||||
|
||||
/*!
|
||||
* Make a copy of \a ref.
|
||||
*/
|
||||
FileRef(const FileRef &ref);
|
||||
|
||||
/*!
|
||||
* Destroys this FileRef instance.
|
||||
*/
|
||||
virtual ~FileRef();
|
||||
|
||||
/*!
|
||||
* Returns a pointer to represented file's tag.
|
||||
*
|
||||
* \warning This pointer will become invalid when this FileRef and all
|
||||
* copies pass out of scope.
|
||||
*
|
||||
* \warning Do not cast it to any subclasses of \class Tag.
|
||||
* Use tag returning methods of appropriate subclasses of \class File instead.
|
||||
*
|
||||
* \see File::tag()
|
||||
*/
|
||||
Tag *tag() const;
|
||||
|
||||
/*!
|
||||
* Returns the audio properties for this FileRef. If no audio properties
|
||||
* were read then this will returns a null pointer.
|
||||
*/
|
||||
AudioProperties *audioProperties() const;
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the file represented by this handler class.
|
||||
*
|
||||
* As a general rule this call should be avoided since if you need to work
|
||||
* with file objects directly, you are probably better served instantiating
|
||||
* the File subclasses (i.e. MPEG::File) manually and working with their APIs.
|
||||
*
|
||||
* This <i>handle</i> exists to provide a minimal, generic and value-based
|
||||
* wrapper around a File. Accessing the file directly generally indicates
|
||||
* a moving away from this simplicity (and into things beyond the scope of
|
||||
* FileRef).
|
||||
*
|
||||
* \warning This pointer will become invalid when this FileRef and all
|
||||
* copies pass out of scope.
|
||||
*/
|
||||
File *file() const;
|
||||
|
||||
/*!
|
||||
* Saves the file. Returns true on success.
|
||||
*/
|
||||
bool save();
|
||||
|
||||
/*!
|
||||
* Adds a FileTypeResolver to the list of those used by TagLib. Each
|
||||
* additional FileTypeResolver is added to the front of a list of resolvers
|
||||
* that are tried. If the FileTypeResolver returns zero the next resolver
|
||||
* is tried.
|
||||
*
|
||||
* Returns a pointer to the added resolver (the same one that's passed in --
|
||||
* this is mostly so that static inialializers have something to use for
|
||||
* assignment).
|
||||
*
|
||||
* \see FileTypeResolver
|
||||
*/
|
||||
static const FileTypeResolver *addFileTypeResolver(const FileTypeResolver *resolver);
|
||||
|
||||
/*!
|
||||
* As is mentioned elsewhere in this class's documentation, the default file
|
||||
* type resolution code provided by TagLib only works by comparing file
|
||||
* extensions.
|
||||
*
|
||||
* This method returns the list of file extensions that are used by default.
|
||||
*
|
||||
* The extensions are all returned in lowercase, though the comparison used
|
||||
* by TagLib for resolution is case-insensitive.
|
||||
*
|
||||
* \note This does not account for any additional file type resolvers that
|
||||
* are plugged in. Also note that this is not intended to replace a propper
|
||||
* mime-type resolution system, but is just here for reference.
|
||||
*
|
||||
* \see FileTypeResolver
|
||||
*/
|
||||
static StringList defaultFileExtensions();
|
||||
|
||||
/*!
|
||||
* Returns true if the file (and as such other pointers) are null.
|
||||
*/
|
||||
bool isNull() const;
|
||||
|
||||
/*!
|
||||
* Assign the file pointed to by \a ref to this FileRef.
|
||||
*/
|
||||
FileRef &operator=(const FileRef &ref);
|
||||
|
||||
/*!
|
||||
* Returns true if this FileRef and \a ref point to the same File object.
|
||||
*/
|
||||
bool operator==(const FileRef &ref) const;
|
||||
|
||||
/*!
|
||||
* Returns true if this FileRef and \a ref do not point to the same File
|
||||
* object.
|
||||
*/
|
||||
bool operator!=(const FileRef &ref) const;
|
||||
|
||||
/*!
|
||||
* A simple implementation of file type guessing. If \a readAudioProperties
|
||||
* is true then the audio properties will be read using
|
||||
* \a audioPropertiesStyle. If \a readAudioProperties is false then
|
||||
* \a audioPropertiesStyle will be ignored.
|
||||
*
|
||||
* \note You generally shouldn't use this method, but instead the constructor
|
||||
* directly.
|
||||
*
|
||||
* \deprecated
|
||||
*/
|
||||
static File *create(FileName fileName,
|
||||
bool readAudioProperties = true,
|
||||
AudioProperties::ReadStyle audioPropertiesStyle = AudioProperties::Average);
|
||||
|
||||
|
||||
private:
|
||||
class FileRefPrivate;
|
||||
FileRefPrivate *d;
|
||||
};
|
||||
|
||||
} // namespace TagLib
|
||||
|
||||
#endif
|
|
@ -0,0 +1,557 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2003-2004 by Allan Sandfeld Jensen
|
||||
email : kde@carewolf.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tbytevector.h>
|
||||
#include <tstring.h>
|
||||
#include <tlist.h>
|
||||
#include <tdebug.h>
|
||||
#include <tagunion.h>
|
||||
#include <tpropertymap.h>
|
||||
|
||||
#include <id3v2header.h>
|
||||
#include <id3v2tag.h>
|
||||
#include <id3v1tag.h>
|
||||
#include <xiphcomment.h>
|
||||
|
||||
#include "flacpicture.h"
|
||||
#include "flacfile.h"
|
||||
#include "flacmetadatablock.h"
|
||||
#include "flacunknownmetadatablock.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
namespace
|
||||
{
|
||||
enum { FlacXiphIndex = 0, FlacID3v2Index = 1, FlacID3v1Index = 2 };
|
||||
enum { MinPaddingLength = 4096 };
|
||||
enum { LastBlockFlag = 0x80 };
|
||||
}
|
||||
|
||||
class FLAC::File::FilePrivate
|
||||
{
|
||||
public:
|
||||
FilePrivate() :
|
||||
ID3v2FrameFactory(ID3v2::FrameFactory::instance()),
|
||||
ID3v2Location(-1),
|
||||
ID3v2OriginalSize(0),
|
||||
ID3v1Location(-1),
|
||||
properties(0),
|
||||
flacStart(0),
|
||||
streamStart(0),
|
||||
streamLength(0),
|
||||
scanned(false),
|
||||
hasXiphComment(false),
|
||||
hasID3v2(false),
|
||||
hasID3v1(false)
|
||||
{
|
||||
}
|
||||
|
||||
~FilePrivate()
|
||||
{
|
||||
for(uint i = 0; i < blocks.size(); i++) {
|
||||
delete blocks[i];
|
||||
}
|
||||
delete properties;
|
||||
}
|
||||
|
||||
const ID3v2::FrameFactory *ID3v2FrameFactory;
|
||||
long ID3v2Location;
|
||||
uint ID3v2OriginalSize;
|
||||
|
||||
long ID3v1Location;
|
||||
|
||||
TagUnion tag;
|
||||
|
||||
Properties *properties;
|
||||
ByteVector streamInfoData;
|
||||
ByteVector xiphCommentData;
|
||||
List<MetadataBlock *> blocks;
|
||||
|
||||
long flacStart;
|
||||
long streamStart;
|
||||
long streamLength;
|
||||
bool scanned;
|
||||
|
||||
bool hasXiphComment;
|
||||
bool hasID3v2;
|
||||
bool hasID3v1;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FLAC::File::File(FileName file, bool readProperties,
|
||||
Properties::ReadStyle propertiesStyle) :
|
||||
TagLib::File(file)
|
||||
{
|
||||
d = new FilePrivate;
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
FLAC::File::File(FileName file, ID3v2::FrameFactory *frameFactory,
|
||||
bool readProperties, Properties::ReadStyle propertiesStyle) :
|
||||
TagLib::File(file)
|
||||
{
|
||||
d = new FilePrivate;
|
||||
d->ID3v2FrameFactory = frameFactory;
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
FLAC::File::File(IOStream *stream, ID3v2::FrameFactory *frameFactory,
|
||||
bool readProperties, Properties::ReadStyle propertiesStyle) :
|
||||
TagLib::File(stream)
|
||||
{
|
||||
d = new FilePrivate;
|
||||
d->ID3v2FrameFactory = frameFactory;
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
FLAC::File::~File()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
TagLib::Tag *FLAC::File::tag() const
|
||||
{
|
||||
return &d->tag;
|
||||
}
|
||||
|
||||
PropertyMap FLAC::File::properties() const
|
||||
{
|
||||
// once Tag::properties() is virtual, this case distinction could actually be done
|
||||
// within TagUnion.
|
||||
if(d->hasXiphComment)
|
||||
return d->tag.access<Ogg::XiphComment>(FlacXiphIndex, false)->properties();
|
||||
if(d->hasID3v2)
|
||||
return d->tag.access<ID3v2::Tag>(FlacID3v2Index, false)->properties();
|
||||
if(d->hasID3v1)
|
||||
return d->tag.access<ID3v1::Tag>(FlacID3v1Index, false)->properties();
|
||||
return PropertyMap();
|
||||
}
|
||||
|
||||
void FLAC::File::removeUnsupportedProperties(const StringList &unsupported)
|
||||
{
|
||||
if(d->hasXiphComment)
|
||||
d->tag.access<Ogg::XiphComment>(FlacXiphIndex, false)->removeUnsupportedProperties(unsupported);
|
||||
if(d->hasID3v2)
|
||||
d->tag.access<ID3v2::Tag>(FlacID3v2Index, false)->removeUnsupportedProperties(unsupported);
|
||||
if(d->hasID3v1)
|
||||
d->tag.access<ID3v1::Tag>(FlacID3v1Index, false)->removeUnsupportedProperties(unsupported);
|
||||
}
|
||||
|
||||
PropertyMap FLAC::File::setProperties(const PropertyMap &properties)
|
||||
{
|
||||
if(d->hasXiphComment)
|
||||
return d->tag.access<Ogg::XiphComment>(FlacXiphIndex, false)->setProperties(properties);
|
||||
else if(d->hasID3v2)
|
||||
return d->tag.access<ID3v2::Tag>(FlacID3v2Index, false)->setProperties(properties);
|
||||
else if(d->hasID3v1)
|
||||
return d->tag.access<ID3v1::Tag>(FlacID3v1Index, false)->setProperties(properties);
|
||||
else
|
||||
return d->tag.access<Ogg::XiphComment>(FlacXiphIndex, true)->setProperties(properties);
|
||||
}
|
||||
|
||||
FLAC::Properties *FLAC::File::audioProperties() const
|
||||
{
|
||||
return d->properties;
|
||||
}
|
||||
|
||||
|
||||
bool FLAC::File::save()
|
||||
{
|
||||
if(readOnly()) {
|
||||
debug("FLAC::File::save() - Cannot save to a read only file.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!isValid()) {
|
||||
debug("FLAC::File::save() -- Trying to save invalid file.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create new vorbis comments
|
||||
|
||||
Tag::duplicate(&d->tag, xiphComment(true), false);
|
||||
|
||||
d->xiphCommentData = xiphComment()->render(false);
|
||||
|
||||
// Replace metadata blocks
|
||||
|
||||
bool foundVorbisCommentBlock = false;
|
||||
List<MetadataBlock *> newBlocks;
|
||||
for(uint i = 0; i < d->blocks.size(); i++) {
|
||||
MetadataBlock *block = d->blocks[i];
|
||||
if(block->code() == MetadataBlock::VorbisComment) {
|
||||
// Set the new Vorbis Comment block
|
||||
delete block;
|
||||
block = new UnknownMetadataBlock(MetadataBlock::VorbisComment, d->xiphCommentData);
|
||||
foundVorbisCommentBlock = true;
|
||||
}
|
||||
if(block->code() == MetadataBlock::Padding) {
|
||||
delete block;
|
||||
continue;
|
||||
}
|
||||
newBlocks.append(block);
|
||||
}
|
||||
if(!foundVorbisCommentBlock) {
|
||||
newBlocks.append(new UnknownMetadataBlock(MetadataBlock::VorbisComment, d->xiphCommentData));
|
||||
foundVorbisCommentBlock = true;
|
||||
}
|
||||
d->blocks = newBlocks;
|
||||
|
||||
// Render data for the metadata blocks
|
||||
|
||||
ByteVector data;
|
||||
for(uint i = 0; i < newBlocks.size(); i++) {
|
||||
FLAC::MetadataBlock *block = newBlocks[i];
|
||||
ByteVector blockData = block->render();
|
||||
ByteVector blockHeader = ByteVector::fromUInt(blockData.size());
|
||||
blockHeader[0] = block->code();
|
||||
data.append(blockHeader);
|
||||
data.append(blockData);
|
||||
}
|
||||
|
||||
// Adjust the padding block(s)
|
||||
|
||||
long originalLength = d->streamStart - d->flacStart;
|
||||
int paddingLength = originalLength - data.size() - 4;
|
||||
if (paddingLength < 0) {
|
||||
paddingLength = MinPaddingLength;
|
||||
}
|
||||
ByteVector padding = ByteVector::fromUInt(paddingLength);
|
||||
padding.resize(paddingLength + 4);
|
||||
padding[0] = (char)(FLAC::MetadataBlock::Padding | LastBlockFlag);
|
||||
data.append(padding);
|
||||
|
||||
// Write the data to the file
|
||||
|
||||
insert(data, d->flacStart, originalLength);
|
||||
d->hasXiphComment = true;
|
||||
|
||||
// Update ID3 tags
|
||||
|
||||
if(ID3v2Tag()) {
|
||||
if(d->hasID3v2) {
|
||||
if(d->ID3v2Location < d->flacStart)
|
||||
debug("FLAC::File::save() -- This can't be right -- an ID3v2 tag after the "
|
||||
"start of the FLAC bytestream? Not writing the ID3v2 tag.");
|
||||
else
|
||||
insert(ID3v2Tag()->render(), d->ID3v2Location, d->ID3v2OriginalSize);
|
||||
}
|
||||
else
|
||||
insert(ID3v2Tag()->render(), 0, 0);
|
||||
}
|
||||
|
||||
if(ID3v1Tag()) {
|
||||
seek(-128, End);
|
||||
writeBlock(ID3v1Tag()->render());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ID3v2::Tag *FLAC::File::ID3v2Tag(bool create)
|
||||
{
|
||||
if(!create || d->tag[FlacID3v2Index])
|
||||
return static_cast<ID3v2::Tag *>(d->tag[FlacID3v2Index]);
|
||||
|
||||
d->tag.set(FlacID3v2Index, new ID3v2::Tag);
|
||||
return static_cast<ID3v2::Tag *>(d->tag[FlacID3v2Index]);
|
||||
}
|
||||
|
||||
ID3v1::Tag *FLAC::File::ID3v1Tag(bool create)
|
||||
{
|
||||
return d->tag.access<ID3v1::Tag>(FlacID3v1Index, create);
|
||||
}
|
||||
|
||||
Ogg::XiphComment *FLAC::File::xiphComment(bool create)
|
||||
{
|
||||
return d->tag.access<Ogg::XiphComment>(FlacXiphIndex, create);
|
||||
}
|
||||
|
||||
void FLAC::File::setID3v2FrameFactory(const ID3v2::FrameFactory *factory)
|
||||
{
|
||||
d->ID3v2FrameFactory = factory;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void FLAC::File::read(bool readProperties, Properties::ReadStyle propertiesStyle)
|
||||
{
|
||||
// Look for an ID3v2 tag
|
||||
|
||||
d->ID3v2Location = findID3v2();
|
||||
|
||||
if(d->ID3v2Location >= 0) {
|
||||
|
||||
d->tag.set(FlacID3v2Index, new ID3v2::Tag(this, d->ID3v2Location, d->ID3v2FrameFactory));
|
||||
|
||||
d->ID3v2OriginalSize = ID3v2Tag()->header()->completeTagSize();
|
||||
|
||||
if(ID3v2Tag()->header()->tagSize() <= 0)
|
||||
d->tag.set(FlacID3v2Index, 0);
|
||||
else
|
||||
d->hasID3v2 = true;
|
||||
}
|
||||
|
||||
// Look for an ID3v1 tag
|
||||
|
||||
d->ID3v1Location = findID3v1();
|
||||
|
||||
if(d->ID3v1Location >= 0) {
|
||||
d->tag.set(FlacID3v1Index, new ID3v1::Tag(this, d->ID3v1Location));
|
||||
d->hasID3v1 = true;
|
||||
}
|
||||
|
||||
// Look for FLAC metadata, including vorbis comments
|
||||
|
||||
scan();
|
||||
|
||||
if(!isValid())
|
||||
return;
|
||||
|
||||
if(d->hasXiphComment)
|
||||
d->tag.set(FlacXiphIndex, new Ogg::XiphComment(xiphCommentData()));
|
||||
else
|
||||
d->tag.set(FlacXiphIndex, new Ogg::XiphComment);
|
||||
|
||||
if(readProperties)
|
||||
d->properties = new Properties(streamInfoData(), streamLength(), propertiesStyle);
|
||||
}
|
||||
|
||||
ByteVector FLAC::File::streamInfoData()
|
||||
{
|
||||
return isValid() ? d->streamInfoData : ByteVector();
|
||||
}
|
||||
|
||||
ByteVector FLAC::File::xiphCommentData() const
|
||||
{
|
||||
return (isValid() && d->hasXiphComment) ? d->xiphCommentData : ByteVector();
|
||||
}
|
||||
|
||||
long FLAC::File::streamLength()
|
||||
{
|
||||
return d->streamLength;
|
||||
}
|
||||
|
||||
void FLAC::File::scan()
|
||||
{
|
||||
// Scan the metadata pages
|
||||
|
||||
if(d->scanned)
|
||||
return;
|
||||
|
||||
if(!isValid())
|
||||
return;
|
||||
|
||||
long nextBlockOffset;
|
||||
|
||||
if(d->hasID3v2)
|
||||
nextBlockOffset = find("fLaC", d->ID3v2Location + d->ID3v2OriginalSize);
|
||||
else
|
||||
nextBlockOffset = find("fLaC");
|
||||
|
||||
if(nextBlockOffset < 0) {
|
||||
debug("FLAC::File::scan() -- FLAC stream not found");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
nextBlockOffset += 4;
|
||||
d->flacStart = nextBlockOffset;
|
||||
|
||||
seek(nextBlockOffset);
|
||||
|
||||
ByteVector header = readBlock(4);
|
||||
|
||||
// Header format (from spec):
|
||||
// <1> Last-metadata-block flag
|
||||
// <7> BLOCK_TYPE
|
||||
// 0 : STREAMINFO
|
||||
// 1 : PADDING
|
||||
// ..
|
||||
// 4 : VORBIS_COMMENT
|
||||
// ..
|
||||
// <24> Length of metadata to follow
|
||||
|
||||
char blockType = header[0] & 0x7f;
|
||||
bool isLastBlock = (header[0] & 0x80) != 0;
|
||||
uint length = header.mid(1, 3).toUInt();
|
||||
|
||||
// First block should be the stream_info metadata
|
||||
|
||||
if(blockType != MetadataBlock::StreamInfo) {
|
||||
debug("FLAC::File::scan() -- invalid FLAC stream");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
d->streamInfoData = readBlock(length);
|
||||
d->blocks.append(new UnknownMetadataBlock(blockType, d->streamInfoData));
|
||||
nextBlockOffset += length + 4;
|
||||
|
||||
// Search through the remaining metadata
|
||||
while(!isLastBlock) {
|
||||
|
||||
header = readBlock(4);
|
||||
blockType = header[0] & 0x7f;
|
||||
isLastBlock = (header[0] & 0x80) != 0;
|
||||
length = header.mid(1, 3).toUInt();
|
||||
|
||||
ByteVector data = readBlock(length);
|
||||
if(data.size() != length) {
|
||||
debug("FLAC::File::scan() -- FLAC stream corrupted");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
MetadataBlock *block = 0;
|
||||
|
||||
// Found the vorbis-comment
|
||||
if(blockType == MetadataBlock::VorbisComment) {
|
||||
if(!d->hasXiphComment) {
|
||||
d->xiphCommentData = data;
|
||||
d->hasXiphComment = true;
|
||||
}
|
||||
else {
|
||||
debug("FLAC::File::scan() -- multiple Vorbis Comment blocks found, using the first one");
|
||||
}
|
||||
}
|
||||
else if(blockType == MetadataBlock::Picture) {
|
||||
FLAC::Picture *picture = new FLAC::Picture();
|
||||
if(picture->parse(data)) {
|
||||
block = picture;
|
||||
}
|
||||
else {
|
||||
debug("FLAC::File::scan() -- invalid picture found, discarting");
|
||||
delete picture;
|
||||
}
|
||||
}
|
||||
|
||||
if(!block) {
|
||||
block = new UnknownMetadataBlock(blockType, data);
|
||||
}
|
||||
if(block->code() != MetadataBlock::Padding) {
|
||||
d->blocks.append(block);
|
||||
}
|
||||
else {
|
||||
delete block;
|
||||
}
|
||||
|
||||
nextBlockOffset += length + 4;
|
||||
|
||||
if(nextBlockOffset >= File::length()) {
|
||||
debug("FLAC::File::scan() -- FLAC stream corrupted");
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
seek(nextBlockOffset);
|
||||
}
|
||||
|
||||
// End of metadata, now comes the datastream
|
||||
|
||||
d->streamStart = nextBlockOffset;
|
||||
d->streamLength = File::length() - d->streamStart;
|
||||
|
||||
if(d->hasID3v1)
|
||||
d->streamLength -= 128;
|
||||
|
||||
d->scanned = true;
|
||||
}
|
||||
|
||||
long FLAC::File::findID3v1()
|
||||
{
|
||||
if(!isValid())
|
||||
return -1;
|
||||
|
||||
seek(-128, End);
|
||||
long p = tell();
|
||||
|
||||
if(readBlock(3) == ID3v1::Tag::fileIdentifier())
|
||||
return p;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
long FLAC::File::findID3v2()
|
||||
{
|
||||
if(!isValid())
|
||||
return -1;
|
||||
|
||||
seek(0);
|
||||
|
||||
if(readBlock(3) == ID3v2::Header::fileIdentifier())
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
List<FLAC::Picture *> FLAC::File::pictureList()
|
||||
{
|
||||
List<Picture *> pictures;
|
||||
for(uint i = 0; i < d->blocks.size(); i++) {
|
||||
Picture *picture = dynamic_cast<Picture *>(d->blocks[i]);
|
||||
if(picture) {
|
||||
pictures.append(picture);
|
||||
}
|
||||
}
|
||||
return pictures;
|
||||
}
|
||||
|
||||
void FLAC::File::addPicture(Picture *picture)
|
||||
{
|
||||
d->blocks.append(picture);
|
||||
}
|
||||
|
||||
void FLAC::File::removePicture(Picture *picture, bool del)
|
||||
{
|
||||
MetadataBlock *block = picture;
|
||||
List<MetadataBlock *>::Iterator it = d->blocks.find(block);
|
||||
if(it != d->blocks.end())
|
||||
d->blocks.erase(it);
|
||||
|
||||
if(del)
|
||||
delete picture;
|
||||
}
|
||||
|
||||
void FLAC::File::removePictures()
|
||||
{
|
||||
List<MetadataBlock *> newBlocks;
|
||||
for(uint i = 0; i < d->blocks.size(); i++) {
|
||||
Picture *picture = dynamic_cast<Picture *>(d->blocks[i]);
|
||||
if(picture) {
|
||||
delete picture;
|
||||
}
|
||||
else {
|
||||
newBlocks.append(d->blocks[i]);
|
||||
}
|
||||
}
|
||||
d->blocks = newBlocks;
|
||||
}
|
||||
|
|
@ -0,0 +1,261 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2003 by Allan Sandfeld Jensen
|
||||
email : kde@carewolf.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_FLACFILE_H
|
||||
#define TAGLIB_FLACFILE_H
|
||||
|
||||
#include "taglib_export.h"
|
||||
#include "tfile.h"
|
||||
#include "tlist.h"
|
||||
#include "tag.h"
|
||||
|
||||
#include "flacpicture.h"
|
||||
#include "flacproperties.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
class Tag;
|
||||
namespace ID3v2 { class FrameFactory; class Tag; }
|
||||
namespace ID3v1 { class Tag; }
|
||||
namespace Ogg { class XiphComment; }
|
||||
|
||||
//! An implementation of FLAC metadata
|
||||
|
||||
/*!
|
||||
* This is implementation of FLAC metadata for non-Ogg FLAC files. At some
|
||||
* point when Ogg / FLAC is more common there will be a similar implementation
|
||||
* under the Ogg hiearchy.
|
||||
*
|
||||
* This supports ID3v1, ID3v2 and Xiph style comments as well as reading stream
|
||||
* properties from the file.
|
||||
*/
|
||||
|
||||
namespace FLAC {
|
||||
|
||||
//! An implementation of TagLib::File with FLAC specific methods
|
||||
|
||||
/*!
|
||||
* This implements and provides an interface for FLAC files to the
|
||||
* TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing
|
||||
* the abstract TagLib::File API as well as providing some additional
|
||||
* information specific to FLAC files.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT File : public TagLib::File
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* Contructs a FLAC file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*
|
||||
* \deprecated This constructor will be dropped in favor of the one below
|
||||
* in a future version.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Contructs a FLAC file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*
|
||||
* If this file contains and ID3v2 tag the frames will be created using
|
||||
* \a frameFactory.
|
||||
*/
|
||||
// BIC: merge with the above constructor
|
||||
File(FileName file, ID3v2::FrameFactory *frameFactory,
|
||||
bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Contructs a FLAC file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*
|
||||
* If this file contains and ID3v2 tag the frames will be created using
|
||||
* \a frameFactory.
|
||||
*
|
||||
* \note TagLib will *not* take ownership of the stream, the caller is
|
||||
* responsible for deleting it after the File object.
|
||||
*/
|
||||
// BIC: merge with the above constructor
|
||||
File(IOStream *stream, ID3v2::FrameFactory *frameFactory,
|
||||
bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
virtual ~File();
|
||||
|
||||
/*!
|
||||
* Returns the Tag for this file. This will be a union of XiphComment,
|
||||
* ID3v1 and ID3v2 tags.
|
||||
*
|
||||
* \see ID3v2Tag()
|
||||
* \see ID3v1Tag()
|
||||
* \see XiphComment()
|
||||
*/
|
||||
virtual TagLib::Tag *tag() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- export function.
|
||||
* If the file contains more than one tag (e.g. XiphComment and ID3v1),
|
||||
* only the first one (in the order XiphComment, ID3v2, ID3v1) will be
|
||||
* converted to the PropertyMap.
|
||||
*/
|
||||
PropertyMap properties() const;
|
||||
|
||||
void removeUnsupportedProperties(const StringList &);
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- import function.
|
||||
* As with the export, only one tag is taken into account. If the file
|
||||
* has no tag at all, a XiphComment will be created.
|
||||
*/
|
||||
PropertyMap setProperties(const PropertyMap &);
|
||||
|
||||
/*!
|
||||
* Returns the FLAC::Properties for this file. If no audio properties
|
||||
* were read then this will return a null pointer.
|
||||
*/
|
||||
virtual Properties *audioProperties() const;
|
||||
|
||||
/*!
|
||||
* Save the file. This will primarily save the XiphComment, but
|
||||
* will also keep any old ID3-tags up to date. If the file
|
||||
* has no XiphComment, one will be constructed from the ID3-tags.
|
||||
*
|
||||
* This returns true if the save was successful.
|
||||
*/
|
||||
virtual bool save();
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the ID3v2 tag of the file.
|
||||
*
|
||||
* If \a create is false (the default) this will return a null pointer
|
||||
* if there is no valid ID3v2 tag. If \a create is true it will create
|
||||
* an ID3v2 tag if one does not exist.
|
||||
*
|
||||
* \note The Tag <b>is still</b> owned by the FLAC::File and should not be
|
||||
* deleted by the user. It will be deleted when the file (object) is
|
||||
* destroyed.
|
||||
*/
|
||||
ID3v2::Tag *ID3v2Tag(bool create = false);
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the ID3v1 tag of the file.
|
||||
*
|
||||
* If \a create is false (the default) this will return a null pointer
|
||||
* if there is no valid ID3v1 tag. If \a create is true it will create
|
||||
* an ID3v1 tag if one does not exist.
|
||||
*
|
||||
* \note The Tag <b>is still</b> owned by the FLAC::File and should not be
|
||||
* deleted by the user. It will be deleted when the file (object) is
|
||||
* destroyed.
|
||||
*/
|
||||
ID3v1::Tag *ID3v1Tag(bool create = false);
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the XiphComment for the file.
|
||||
*
|
||||
* If \a create is false (the default) this will return a null pointer
|
||||
* if there is no valid XiphComment. If \a create is true it will create
|
||||
* a XiphComment if one does not exist.
|
||||
*
|
||||
* \note The Tag <b>is still</b> owned by the FLAC::File and should not be
|
||||
* deleted by the user. It will be deleted when the file (object) is
|
||||
* destroyed.
|
||||
*/
|
||||
Ogg::XiphComment *xiphComment(bool create = false);
|
||||
|
||||
/*!
|
||||
* Set the ID3v2::FrameFactory to something other than the default. This
|
||||
* can be used to specify the way that ID3v2 frames will be interpreted
|
||||
* when
|
||||
*
|
||||
* \see ID3v2FrameFactory
|
||||
*/
|
||||
void setID3v2FrameFactory(const ID3v2::FrameFactory *factory);
|
||||
|
||||
/*!
|
||||
* Returns the block of data used by FLAC::Properties for parsing the
|
||||
* stream properties.
|
||||
*
|
||||
* \deprecated This method will not be public in a future release.
|
||||
*/
|
||||
ByteVector streamInfoData(); // BIC: remove
|
||||
|
||||
/*!
|
||||
* Returns the length of the audio-stream, used by FLAC::Properties for
|
||||
* calculating the bitrate.
|
||||
*
|
||||
* \deprecated This method will not be public in a future release.
|
||||
*/
|
||||
long streamLength(); // BIC: remove
|
||||
|
||||
/*!
|
||||
* Returns a list of pictures attached to the FLAC file.
|
||||
*/
|
||||
List<Picture *> pictureList();
|
||||
|
||||
/*!
|
||||
* Removes an attached picture. If \a del is true the picture's memory
|
||||
* will be freed; if it is false, it must be deleted by the user.
|
||||
*/
|
||||
void removePicture(Picture *picture, bool del = true);
|
||||
|
||||
/*!
|
||||
* Remove all attached images.
|
||||
*/
|
||||
void removePictures();
|
||||
|
||||
/*!
|
||||
* Add a new picture to the file. The file takes ownership of the
|
||||
* picture and will handle freeing its memory.
|
||||
*
|
||||
* \note The file will be saved only after calling save().
|
||||
*/
|
||||
void addPicture(Picture *picture);
|
||||
|
||||
private:
|
||||
File(const File &);
|
||||
File &operator=(const File &);
|
||||
|
||||
void read(bool readProperties, Properties::ReadStyle propertiesStyle);
|
||||
void scan();
|
||||
long findID3v2();
|
||||
long findID3v1();
|
||||
ByteVector xiphCommentData() const;
|
||||
long findPaddingBreak(long nextPageOffset, long targetOffset, bool *isLast);
|
||||
|
||||
class FilePrivate;
|
||||
FilePrivate *d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,51 @@
|
|||
/**************************************************************************
|
||||
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/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <taglib.h>
|
||||
#include <tdebug.h>
|
||||
#include "flacmetadatablock.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class FLAC::MetadataBlock::MetadataBlockPrivate
|
||||
{
|
||||
public:
|
||||
MetadataBlockPrivate() {}
|
||||
|
||||
};
|
||||
|
||||
FLAC::MetadataBlock::MetadataBlock()
|
||||
{
|
||||
d = 0;
|
||||
}
|
||||
|
||||
FLAC::MetadataBlock::~MetadataBlock()
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
/**************************************************************************
|
||||
copyright : (C) 2010 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_FLACMETADATABLOCK_H
|
||||
#define TAGLIB_FLACMETADATABLOCK_H
|
||||
|
||||
#include "tlist.h"
|
||||
#include "tbytevector.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace FLAC {
|
||||
|
||||
class TAGLIB_EXPORT MetadataBlock
|
||||
{
|
||||
public:
|
||||
MetadataBlock();
|
||||
virtual ~MetadataBlock();
|
||||
|
||||
enum BlockType {
|
||||
StreamInfo = 0,
|
||||
Padding,
|
||||
Application,
|
||||
SeekTable,
|
||||
VorbisComment,
|
||||
CueSheet,
|
||||
Picture
|
||||
};
|
||||
|
||||
/*!
|
||||
* Returns the FLAC metadata block type.
|
||||
*/
|
||||
virtual int code() const = 0;
|
||||
|
||||
/*!
|
||||
* Render the content of the block.
|
||||
*/
|
||||
virtual ByteVector render() const = 0;
|
||||
|
||||
private:
|
||||
MetadataBlock(const MetadataBlock &item);
|
||||
MetadataBlock &operator=(const MetadataBlock &item);
|
||||
|
||||
class MetadataBlockPrivate;
|
||||
MetadataBlockPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,221 @@
|
|||
/**************************************************************************
|
||||
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/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <taglib.h>
|
||||
#include <tdebug.h>
|
||||
#include "flacpicture.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class FLAC::Picture::PicturePrivate
|
||||
{
|
||||
public:
|
||||
PicturePrivate() :
|
||||
type(FLAC::Picture::Other),
|
||||
width(0),
|
||||
height(0),
|
||||
colorDepth(0),
|
||||
numColors(0)
|
||||
{}
|
||||
|
||||
Type type;
|
||||
String mimeType;
|
||||
String description;
|
||||
int width;
|
||||
int height;
|
||||
int colorDepth;
|
||||
int numColors;
|
||||
ByteVector data;
|
||||
};
|
||||
|
||||
FLAC::Picture::Picture()
|
||||
{
|
||||
d = new PicturePrivate;
|
||||
}
|
||||
|
||||
FLAC::Picture::Picture(const ByteVector &data)
|
||||
{
|
||||
d = new PicturePrivate;
|
||||
parse(data);
|
||||
}
|
||||
|
||||
FLAC::Picture::~Picture()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
int FLAC::Picture::code() const
|
||||
{
|
||||
return FLAC::MetadataBlock::Picture;
|
||||
}
|
||||
|
||||
bool FLAC::Picture::parse(const ByteVector &data)
|
||||
{
|
||||
if(data.size() < 32) {
|
||||
debug("A picture block must contain at least 5 bytes.");
|
||||
return false;
|
||||
}
|
||||
|
||||
int pos = 0;
|
||||
d->type = FLAC::Picture::Type(data.mid(pos, 4).toUInt());
|
||||
pos += 4;
|
||||
uint mimeTypeLength = data.mid(pos, 4).toUInt();
|
||||
pos += 4;
|
||||
if(pos + mimeTypeLength + 24 > data.size()) {
|
||||
debug("Invalid picture block.");
|
||||
return false;
|
||||
}
|
||||
d->mimeType = String(data.mid(pos, mimeTypeLength), String::UTF8);
|
||||
pos += mimeTypeLength;
|
||||
uint descriptionLength = data.mid(pos, 4).toUInt();
|
||||
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.mid(pos, 4).toUInt();
|
||||
pos += 4;
|
||||
d->height = data.mid(pos, 4).toUInt();
|
||||
pos += 4;
|
||||
d->colorDepth = data.mid(pos, 4).toUInt();
|
||||
pos += 4;
|
||||
d->numColors = data.mid(pos, 4).toUInt();
|
||||
pos += 4;
|
||||
uint dataLength = data.mid(pos, 4).toUInt();
|
||||
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;
|
||||
}
|
||||
|
|
@ -0,0 +1,208 @@
|
|||
/**************************************************************************
|
||||
copyright : (C) 2010 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_FLACPICTURE_H
|
||||
#define TAGLIB_FLACPICTURE_H
|
||||
|
||||
#include "tlist.h"
|
||||
#include "tstring.h"
|
||||
#include "tbytevector.h"
|
||||
#include "taglib_export.h"
|
||||
#include "flacmetadatablock.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace FLAC {
|
||||
|
||||
class TAGLIB_EXPORT Picture : public MetadataBlock
|
||||
{
|
||||
public:
|
||||
|
||||
/*!
|
||||
* This describes the function or content of the picture.
|
||||
*/
|
||||
enum Type {
|
||||
//! A type not enumerated below
|
||||
Other = 0x00,
|
||||
//! 32x32 PNG image that should be used as the file icon
|
||||
FileIcon = 0x01,
|
||||
//! File icon of a different size or format
|
||||
OtherFileIcon = 0x02,
|
||||
//! Front cover image of the album
|
||||
FrontCover = 0x03,
|
||||
//! Back cover image of the album
|
||||
BackCover = 0x04,
|
||||
//! Inside leaflet page of the album
|
||||
LeafletPage = 0x05,
|
||||
//! Image from the album itself
|
||||
Media = 0x06,
|
||||
//! Picture of the lead artist or soloist
|
||||
LeadArtist = 0x07,
|
||||
//! Picture of the artist or performer
|
||||
Artist = 0x08,
|
||||
//! Picture of the conductor
|
||||
Conductor = 0x09,
|
||||
//! Picture of the band or orchestra
|
||||
Band = 0x0A,
|
||||
//! Picture of the composer
|
||||
Composer = 0x0B,
|
||||
//! Picture of the lyricist or text writer
|
||||
Lyricist = 0x0C,
|
||||
//! Picture of the recording location or studio
|
||||
RecordingLocation = 0x0D,
|
||||
//! Picture of the artists during recording
|
||||
DuringRecording = 0x0E,
|
||||
//! Picture of the artists during performance
|
||||
DuringPerformance = 0x0F,
|
||||
//! Picture from a movie or video related to the track
|
||||
MovieScreenCapture = 0x10,
|
||||
//! Picture of a large, coloured fish
|
||||
ColouredFish = 0x11,
|
||||
//! Illustration related to the track
|
||||
Illustration = 0x12,
|
||||
//! Logo of the band or performer
|
||||
BandLogo = 0x13,
|
||||
//! Logo of the publisher (record company)
|
||||
PublisherLogo = 0x14
|
||||
};
|
||||
|
||||
Picture();
|
||||
Picture(const ByteVector &data);
|
||||
~Picture();
|
||||
|
||||
/*!
|
||||
* Returns the type of the image.
|
||||
*/
|
||||
Type type() const;
|
||||
|
||||
/*!
|
||||
* Sets the type of the image.
|
||||
*/
|
||||
void setType(Type type);
|
||||
|
||||
/*!
|
||||
* Returns the mime type of the image. This should in most cases be
|
||||
* "image/png" or "image/jpeg".
|
||||
*/
|
||||
String mimeType() const;
|
||||
|
||||
/*!
|
||||
* Sets the mime type of the image. This should in most cases be
|
||||
* "image/png" or "image/jpeg".
|
||||
*/
|
||||
void setMimeType(const String &m);
|
||||
|
||||
/*!
|
||||
* Returns a text description of the image.
|
||||
*/
|
||||
|
||||
String description() const;
|
||||
|
||||
/*!
|
||||
* Sets a textual description of the image to \a desc.
|
||||
*/
|
||||
|
||||
void setDescription(const String &desc);
|
||||
|
||||
/*!
|
||||
* Returns the width of the image.
|
||||
*/
|
||||
int width() const;
|
||||
|
||||
/*!
|
||||
* Sets the width of the image.
|
||||
*/
|
||||
void setWidth(int w);
|
||||
|
||||
/*!
|
||||
* Returns the height of the image.
|
||||
*/
|
||||
int height() const;
|
||||
|
||||
/*!
|
||||
* Sets the height of the image.
|
||||
*/
|
||||
void setHeight(int h);
|
||||
|
||||
/*!
|
||||
* Returns the color depth (in bits-per-pixel) of the image.
|
||||
*/
|
||||
int colorDepth() const;
|
||||
|
||||
/*!
|
||||
* Sets the color depth (in bits-per-pixel) of the image.
|
||||
*/
|
||||
void setColorDepth(int depth);
|
||||
|
||||
/*!
|
||||
* Returns the number of colors used on the image..
|
||||
*/
|
||||
int numColors() const;
|
||||
|
||||
/*!
|
||||
* Sets the number of colors used on the image (for indexed images).
|
||||
*/
|
||||
void setNumColors(int numColors);
|
||||
|
||||
/*!
|
||||
* Returns the image data.
|
||||
*/
|
||||
ByteVector data() const;
|
||||
|
||||
/*!
|
||||
* Sets the image data.
|
||||
*/
|
||||
void setData(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Returns the FLAC metadata block type.
|
||||
*/
|
||||
int code() const;
|
||||
|
||||
/*!
|
||||
* Render the content to the FLAC picture block format.
|
||||
*/
|
||||
ByteVector render() const;
|
||||
|
||||
/*!
|
||||
* Parse the picture data in the FLAC picture block format.
|
||||
*/
|
||||
bool parse(const ByteVector &rawData);
|
||||
|
||||
private:
|
||||
Picture(const Picture &item);
|
||||
Picture &operator=(const Picture &item);
|
||||
|
||||
class PicturePrivate;
|
||||
PicturePrivate *d;
|
||||
};
|
||||
|
||||
typedef List<Picture> PictureList;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,169 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2003 by Allan Sandfeld Jensen
|
||||
email : kde@carewolf.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tstring.h>
|
||||
#include <tdebug.h>
|
||||
|
||||
#include "flacproperties.h"
|
||||
#include "flacfile.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class FLAC::Properties::PropertiesPrivate
|
||||
{
|
||||
public:
|
||||
PropertiesPrivate(ByteVector d, long st, ReadStyle s) :
|
||||
data(d),
|
||||
streamLength(st),
|
||||
style(s),
|
||||
length(0),
|
||||
bitrate(0),
|
||||
sampleRate(0),
|
||||
sampleWidth(0),
|
||||
channels(0),
|
||||
sampleFrames(0) {}
|
||||
|
||||
ByteVector data;
|
||||
long streamLength;
|
||||
ReadStyle style;
|
||||
int length;
|
||||
int bitrate;
|
||||
int sampleRate;
|
||||
int sampleWidth;
|
||||
int channels;
|
||||
unsigned long long sampleFrames;
|
||||
ByteVector signature;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
FLAC::Properties::Properties(ByteVector data, long streamLength, ReadStyle style) : AudioProperties(style)
|
||||
{
|
||||
d = new PropertiesPrivate(data, streamLength, style);
|
||||
read();
|
||||
}
|
||||
|
||||
FLAC::Properties::Properties(File *file, ReadStyle style) : AudioProperties(style)
|
||||
{
|
||||
d = new PropertiesPrivate(file->streamInfoData(), file->streamLength(), style);
|
||||
read();
|
||||
}
|
||||
|
||||
FLAC::Properties::~Properties()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
int FLAC::Properties::length() const
|
||||
{
|
||||
return d->length;
|
||||
}
|
||||
|
||||
int FLAC::Properties::bitrate() const
|
||||
{
|
||||
return d->bitrate;
|
||||
}
|
||||
|
||||
int FLAC::Properties::sampleRate() const
|
||||
{
|
||||
return d->sampleRate;
|
||||
}
|
||||
|
||||
int FLAC::Properties::sampleWidth() const
|
||||
{
|
||||
return d->sampleWidth;
|
||||
}
|
||||
|
||||
int FLAC::Properties::channels() const
|
||||
{
|
||||
return d->channels;
|
||||
}
|
||||
|
||||
unsigned long long FLAC::Properties::sampleFrames() const
|
||||
{
|
||||
return d->sampleFrames;
|
||||
}
|
||||
|
||||
ByteVector FLAC::Properties::signature() const
|
||||
{
|
||||
return d->signature;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void FLAC::Properties::read()
|
||||
{
|
||||
if(d->data.size() < 18) {
|
||||
debug("FLAC::Properties::read() - FLAC properties must contain at least 18 bytes.");
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
uint flags = d->data.mid(pos, 4).toUInt(true);
|
||||
pos += 4;
|
||||
|
||||
d->sampleRate = flags >> 12;
|
||||
d->channels = ((flags >> 9) & 7) + 1;
|
||||
d->sampleWidth = ((flags >> 4) & 31) + 1;
|
||||
|
||||
// The last 4 bits are the most significant 4 bits for the 36 bit
|
||||
// stream length in samples. (Audio files measured in days)
|
||||
|
||||
unsigned long long hi = flags & 0xf;
|
||||
unsigned long long lo = d->data.mid(pos, 4).toUInt(true);
|
||||
pos += 4;
|
||||
|
||||
d->sampleFrames = (hi << 32) | lo;
|
||||
|
||||
if(d->sampleRate > 0)
|
||||
d->length = int(d->sampleFrames / d->sampleRate);
|
||||
|
||||
// Uncompressed bitrate:
|
||||
|
||||
//d->bitrate = ((d->sampleRate * d->channels) / 1000) * d->sampleWidth;
|
||||
|
||||
// Real bitrate:
|
||||
|
||||
d->bitrate = d->length > 0 ? ((d->streamLength * 8UL) / d->length) / 1000 : 0;
|
||||
|
||||
d->signature = d->data.mid(pos, 32);
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2003 by Allan Sandfeld Jensen
|
||||
email : kde@carewolf.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_FLACPROPERTIES_H
|
||||
#define TAGLIB_FLACPROPERTIES_H
|
||||
|
||||
#include "taglib_export.h"
|
||||
#include "audioproperties.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace FLAC {
|
||||
|
||||
class File;
|
||||
|
||||
//! An implementation of audio property reading for FLAC
|
||||
|
||||
/*!
|
||||
* This reads the data from an FLAC stream found in the AudioProperties
|
||||
* API.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT Properties : public AudioProperties
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* Create an instance of FLAC::Properties with the data read from the
|
||||
* ByteVector \a data.
|
||||
*/
|
||||
// BIC: switch to const reference
|
||||
Properties(ByteVector data, long streamLength, ReadStyle style = Average);
|
||||
|
||||
/*!
|
||||
* Create an instance of FLAC::Properties with the data read from the
|
||||
* FLAC::File \a file.
|
||||
*/
|
||||
// BIC: remove
|
||||
Properties(File *file, ReadStyle style = Average);
|
||||
|
||||
/*!
|
||||
* Destroys this FLAC::Properties instance.
|
||||
*/
|
||||
virtual ~Properties();
|
||||
|
||||
// Reimplementations.
|
||||
|
||||
virtual int length() const;
|
||||
virtual int bitrate() const;
|
||||
virtual int sampleRate() const;
|
||||
virtual int channels() const;
|
||||
|
||||
/*!
|
||||
* Returns the sample width as read from the FLAC identification
|
||||
* header.
|
||||
*/
|
||||
int sampleWidth() const;
|
||||
|
||||
/*!
|
||||
* Return the number of sample frames
|
||||
*/
|
||||
unsigned long long sampleFrames() const;
|
||||
|
||||
/*!
|
||||
* Returns the MD5 signature of the uncompressed audio stream as read
|
||||
* from the stream info header header.
|
||||
*/
|
||||
ByteVector signature() const;
|
||||
|
||||
private:
|
||||
Properties(const Properties &);
|
||||
Properties &operator=(const Properties &);
|
||||
|
||||
void read();
|
||||
|
||||
class PropertiesPrivate;
|
||||
PropertiesPrivate *d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,83 @@
|
|||
/**************************************************************************
|
||||
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/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <taglib.h>
|
||||
#include <tdebug.h>
|
||||
#include <tstring.h>
|
||||
#include "flacunknownmetadatablock.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class FLAC::UnknownMetadataBlock::UnknownMetadataBlockPrivate
|
||||
{
|
||||
public:
|
||||
UnknownMetadataBlockPrivate() : code(0) {}
|
||||
|
||||
int code;
|
||||
ByteVector data;
|
||||
};
|
||||
|
||||
FLAC::UnknownMetadataBlock::UnknownMetadataBlock(int code, const ByteVector &data)
|
||||
{
|
||||
d = new UnknownMetadataBlockPrivate;
|
||||
d->code = code;
|
||||
//debug(String(data.toHex()));
|
||||
d->data = data;
|
||||
}
|
||||
|
||||
FLAC::UnknownMetadataBlock::~UnknownMetadataBlock()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
int FLAC::UnknownMetadataBlock::code() const
|
||||
{
|
||||
return d->code;
|
||||
}
|
||||
|
||||
void FLAC::UnknownMetadataBlock::setCode(int code)
|
||||
{
|
||||
d->code = code;
|
||||
}
|
||||
|
||||
ByteVector FLAC::UnknownMetadataBlock::data() const
|
||||
{
|
||||
return d->data;
|
||||
}
|
||||
|
||||
void FLAC::UnknownMetadataBlock::setData(const ByteVector &data)
|
||||
{
|
||||
d->data = data;
|
||||
}
|
||||
|
||||
ByteVector FLAC::UnknownMetadataBlock::render() const
|
||||
{
|
||||
return d->data;
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
/**************************************************************************
|
||||
copyright : (C) 2010 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_FLACUNKNOWNMETADATABLOCK_H
|
||||
#define TAGLIB_FLACUNKNOWNMETADATABLOCK_H
|
||||
|
||||
#include "tlist.h"
|
||||
#include "tbytevector.h"
|
||||
#include "taglib_export.h"
|
||||
#include "flacmetadatablock.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace FLAC {
|
||||
|
||||
class TAGLIB_EXPORT UnknownMetadataBlock : public MetadataBlock
|
||||
{
|
||||
public:
|
||||
UnknownMetadataBlock(int blockType, const ByteVector &data);
|
||||
~UnknownMetadataBlock();
|
||||
|
||||
/*!
|
||||
* Returns the FLAC metadata block type.
|
||||
*/
|
||||
int code() const;
|
||||
|
||||
/*!
|
||||
* Sets the FLAC metadata block type.
|
||||
*/
|
||||
void setCode(int code);
|
||||
|
||||
/*!
|
||||
* Returns the FLAC metadata block type.
|
||||
*/
|
||||
ByteVector data() const;
|
||||
|
||||
/*!
|
||||
* Sets the FLAC metadata block type.
|
||||
*/
|
||||
void setData(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Render the content of the block.
|
||||
*/
|
||||
ByteVector render() const;
|
||||
|
||||
private:
|
||||
UnknownMetadataBlock(const MetadataBlock &item);
|
||||
UnknownMetadataBlock &operator=(const MetadataBlock &item);
|
||||
|
||||
class UnknownMetadataBlockPrivate;
|
||||
UnknownMetadataBlockPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,328 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2011 by Mathias Panzenböck
|
||||
email : grosser.meister.morti@gmx.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
|
||||
* MA 02110-1301 USA *
|
||||
***************************************************************************/
|
||||
|
||||
#include "tstringlist.h"
|
||||
#include "itfile.h"
|
||||
#include "tdebug.h"
|
||||
#include "modfileprivate.h"
|
||||
#include "tpropertymap.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace IT;
|
||||
|
||||
class IT::File::FilePrivate
|
||||
{
|
||||
public:
|
||||
FilePrivate(AudioProperties::ReadStyle propertiesStyle)
|
||||
: tag(), properties(propertiesStyle)
|
||||
{
|
||||
}
|
||||
|
||||
Mod::Tag tag;
|
||||
IT::Properties properties;
|
||||
};
|
||||
|
||||
IT::File::File(FileName file, bool readProperties,
|
||||
AudioProperties::ReadStyle propertiesStyle) :
|
||||
Mod::FileBase(file),
|
||||
d(new FilePrivate(propertiesStyle))
|
||||
{
|
||||
read(readProperties);
|
||||
}
|
||||
|
||||
IT::File::File(IOStream *stream, bool readProperties,
|
||||
AudioProperties::ReadStyle propertiesStyle) :
|
||||
Mod::FileBase(stream),
|
||||
d(new FilePrivate(propertiesStyle))
|
||||
{
|
||||
read(readProperties);
|
||||
}
|
||||
|
||||
IT::File::~File()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
Mod::Tag *IT::File::tag() const
|
||||
{
|
||||
return &d->tag;
|
||||
}
|
||||
|
||||
PropertyMap IT::File::properties() const
|
||||
{
|
||||
return d->tag.properties();
|
||||
}
|
||||
|
||||
PropertyMap IT::File::setProperties(const PropertyMap &properties)
|
||||
{
|
||||
return d->tag.setProperties(properties);
|
||||
}
|
||||
|
||||
IT::Properties *IT::File::audioProperties() const
|
||||
{
|
||||
return &d->properties;
|
||||
}
|
||||
|
||||
bool IT::File::save()
|
||||
{
|
||||
if(readOnly())
|
||||
{
|
||||
debug("IT::File::save() - Cannot save to a read only file.");
|
||||
return false;
|
||||
}
|
||||
seek(4);
|
||||
writeString(d->tag.title(), 25);
|
||||
writeByte(0);
|
||||
|
||||
seek(2, Current);
|
||||
|
||||
ushort length = 0;
|
||||
ushort instrumentCount = 0;
|
||||
ushort sampleCount = 0;
|
||||
|
||||
if(!readU16L(length) || !readU16L(instrumentCount) || !readU16L(sampleCount))
|
||||
return false;
|
||||
|
||||
seek(15, Current);
|
||||
|
||||
// write comment as instrument and sample names:
|
||||
StringList lines = d->tag.comment().split("\n");
|
||||
for(ushort i = 0; i < instrumentCount; ++ i) {
|
||||
seek(192L + length + ((long)i << 2));
|
||||
ulong instrumentOffset = 0;
|
||||
if(!readU32L(instrumentOffset))
|
||||
return false;
|
||||
|
||||
seek(instrumentOffset + 32);
|
||||
|
||||
if(i < lines.size())
|
||||
writeString(lines[i], 25);
|
||||
else
|
||||
writeString(String::null, 25);
|
||||
writeByte(0);
|
||||
}
|
||||
|
||||
for(ushort i = 0; i < sampleCount; ++ i) {
|
||||
seek(192L + length + ((long)instrumentCount << 2) + ((long)i << 2));
|
||||
ulong sampleOffset = 0;
|
||||
if(!readU32L(sampleOffset))
|
||||
return false;
|
||||
|
||||
seek(sampleOffset + 20);
|
||||
|
||||
if((TagLib::uint)(i + instrumentCount) < lines.size())
|
||||
writeString(lines[i + instrumentCount], 25);
|
||||
else
|
||||
writeString(String::null, 25);
|
||||
writeByte(0);
|
||||
}
|
||||
|
||||
// write rest as message:
|
||||
StringList messageLines;
|
||||
for(uint i = instrumentCount + sampleCount; i < lines.size(); ++ i)
|
||||
messageLines.append(lines[i]);
|
||||
ByteVector message = messageLines.toString("\r").data(String::Latin1);
|
||||
|
||||
// it's actually not really stated if the message needs a
|
||||
// terminating NUL but it does not hurt to add one:
|
||||
if(message.size() > 7999)
|
||||
message.resize(7999);
|
||||
message.append((char)0);
|
||||
|
||||
ushort special = 0;
|
||||
ushort messageLength = 0;
|
||||
ulong messageOffset = 0;
|
||||
|
||||
seek(46);
|
||||
if(!readU16L(special))
|
||||
return false;
|
||||
|
||||
ulong fileSize = File::length();
|
||||
if(special & Properties::MessageAttached) {
|
||||
seek(54);
|
||||
if(!readU16L(messageLength) || !readU32L(messageOffset))
|
||||
return false;
|
||||
|
||||
if(messageLength == 0)
|
||||
messageOffset = fileSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
messageOffset = fileSize;
|
||||
seek(46);
|
||||
writeU16L(special | 0x1);
|
||||
}
|
||||
|
||||
if(messageOffset + messageLength >= fileSize) {
|
||||
// append new message
|
||||
seek(54);
|
||||
writeU16L(message.size());
|
||||
writeU32L(messageOffset);
|
||||
seek(messageOffset);
|
||||
writeBlock(message);
|
||||
truncate(messageOffset + message.size());
|
||||
}
|
||||
else {
|
||||
// Only overwrite existing message.
|
||||
// I'd need to parse (understand!) the whole file for more.
|
||||
// Although I could just move the message to the end of file
|
||||
// and let the existing one be, but that would waste space.
|
||||
message.resize(messageLength, 0);
|
||||
seek(messageOffset);
|
||||
writeBlock(message);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void IT::File::read(bool)
|
||||
{
|
||||
if(!isOpen())
|
||||
return;
|
||||
|
||||
seek(0);
|
||||
READ_ASSERT(readBlock(4) == "IMPM");
|
||||
READ_STRING(d->tag.setTitle, 26);
|
||||
|
||||
seek(2, Current);
|
||||
|
||||
READ_U16L_AS(length);
|
||||
READ_U16L_AS(instrumentCount);
|
||||
READ_U16L_AS(sampleCount);
|
||||
|
||||
d->properties.setInstrumentCount(instrumentCount);
|
||||
d->properties.setSampleCount(sampleCount);
|
||||
READ_U16L(d->properties.setPatternCount);
|
||||
READ_U16L(d->properties.setVersion);
|
||||
READ_U16L(d->properties.setCompatibleVersion);
|
||||
READ_U16L(d->properties.setFlags);
|
||||
READ_U16L_AS(special);
|
||||
d->properties.setSpecial(special);
|
||||
READ_BYTE(d->properties.setGlobalVolume);
|
||||
READ_BYTE(d->properties.setMixVolume);
|
||||
READ_BYTE(d->properties.setBpmSpeed);
|
||||
READ_BYTE(d->properties.setTempo);
|
||||
READ_BYTE(d->properties.setPanningSeparation);
|
||||
READ_BYTE(d->properties.setPitchWheelDepth);
|
||||
|
||||
// IT supports some kind of comment tag. Still, the
|
||||
// sample/instrument names are abused as comments so
|
||||
// I just add all together.
|
||||
String message;
|
||||
if(special & Properties::MessageAttached) {
|
||||
READ_U16L_AS(messageLength);
|
||||
READ_U32L_AS(messageOffset);
|
||||
seek(messageOffset);
|
||||
ByteVector messageBytes = readBlock(messageLength);
|
||||
READ_ASSERT(messageBytes.size() == messageLength);
|
||||
int index = messageBytes.find((char) 0);
|
||||
if(index > -1)
|
||||
messageBytes.resize(index, 0);
|
||||
messageBytes.replace('\r', '\n');
|
||||
message = messageBytes;
|
||||
}
|
||||
|
||||
seek(64);
|
||||
|
||||
ByteVector pannings = readBlock(64);
|
||||
ByteVector volumes = readBlock(64);
|
||||
READ_ASSERT(pannings.size() == 64 && volumes.size() == 64);
|
||||
int channels = 0;
|
||||
for(int i = 0; i < 64; ++ i) {
|
||||
// Strictly speaking an IT file has always 64 channels, but
|
||||
// I don't count disabled and muted channels.
|
||||
// But this always gives 64 channels for all my files anyway.
|
||||
// Strangely VLC does report other values. I wonder how VLC
|
||||
// gets it's values.
|
||||
if((unsigned char) pannings[i] < 128 && volumes[i] > 0)
|
||||
++channels;
|
||||
}
|
||||
d->properties.setChannels(channels);
|
||||
|
||||
// real length might be shorter because of skips and terminator
|
||||
ushort realLength = 0;
|
||||
for(ushort i = 0; i < length; ++ i) {
|
||||
READ_BYTE_AS(order);
|
||||
if(order == 255) break;
|
||||
if(order != 254) ++ realLength;
|
||||
}
|
||||
d->properties.setLengthInPatterns(realLength);
|
||||
|
||||
StringList comment;
|
||||
// Note: I found files that have nil characters somewhere
|
||||
// in the instrument/sample names and more characters
|
||||
// afterwards. The spec does not mention such a case.
|
||||
// Currently I just discard anything after a nil, but
|
||||
// e.g. VLC seems to interprete a nil as a space. I
|
||||
// don't know what is the proper behaviour.
|
||||
for(ushort i = 0; i < instrumentCount; ++ i) {
|
||||
seek(192L + length + ((long)i << 2));
|
||||
READ_U32L_AS(instrumentOffset);
|
||||
seek(instrumentOffset);
|
||||
|
||||
ByteVector instrumentMagic = readBlock(4);
|
||||
READ_ASSERT(instrumentMagic == "IMPI");
|
||||
|
||||
READ_STRING_AS(dosFileName, 13);
|
||||
|
||||
seek(15, Current);
|
||||
|
||||
READ_STRING_AS(instrumentName, 26);
|
||||
comment.append(instrumentName);
|
||||
}
|
||||
|
||||
for(ushort i = 0; i < sampleCount; ++ i) {
|
||||
seek(192L + length + ((long)instrumentCount << 2) + ((long)i << 2));
|
||||
READ_U32L_AS(sampleOffset);
|
||||
|
||||
seek(sampleOffset);
|
||||
|
||||
ByteVector sampleMagic = readBlock(4);
|
||||
READ_ASSERT(sampleMagic == "IMPS");
|
||||
|
||||
READ_STRING_AS(dosFileName, 13);
|
||||
READ_BYTE_AS(globalVolume);
|
||||
READ_BYTE_AS(sampleFlags);
|
||||
READ_BYTE_AS(sampleVolume);
|
||||
READ_STRING_AS(sampleName, 26);
|
||||
/*
|
||||
READ_BYTE_AS(sampleCvt);
|
||||
READ_BYTE_AS(samplePanning);
|
||||
READ_U32L_AS(sampleLength);
|
||||
READ_U32L_AS(loopStart);
|
||||
READ_U32L_AS(loopStop);
|
||||
READ_U32L_AS(c5speed);
|
||||
READ_U32L_AS(sustainLoopStart);
|
||||
READ_U32L_AS(sustainLoopEnd);
|
||||
READ_U32L_AS(sampleDataOffset);
|
||||
READ_BYTE_AS(vibratoSpeed);
|
||||
READ_BYTE_AS(vibratoDepth);
|
||||
READ_BYTE_AS(vibratoRate);
|
||||
READ_BYTE_AS(vibratoType);
|
||||
*/
|
||||
|
||||
comment.append(sampleName);
|
||||
}
|
||||
|
||||
if(message.size() > 0)
|
||||
comment.append(message);
|
||||
d->tag.setComment(comment.toString("\n"));
|
||||
d->tag.setTrackerName("Impulse Tracker");
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2011 by Mathias Panzenböck
|
||||
email : grosser.meister.morti@gmx.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
|
||||
* MA 02110-1301 USA *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_ITFILE_H
|
||||
#define TAGLIB_ITFILE_H
|
||||
|
||||
#include "tfile.h"
|
||||
#include "audioproperties.h"
|
||||
#include "taglib_export.h"
|
||||
#include "modfilebase.h"
|
||||
#include "modtag.h"
|
||||
#include "itproperties.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace IT {
|
||||
|
||||
class TAGLIB_EXPORT File : public Mod::FileBase {
|
||||
public:
|
||||
/*!
|
||||
* Contructs a Impulse Tracker file from \a file. If \a readProperties
|
||||
* is true the file's audio properties will also be read using
|
||||
* \a propertiesStyle. If false, \a propertiesStyle is ignored.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true,
|
||||
AudioProperties::ReadStyle propertiesStyle =
|
||||
AudioProperties::Average);
|
||||
|
||||
/*!
|
||||
* Contructs a Impulse Tracker file from \a stream. If \a readProperties
|
||||
* is true the file's audio properties will also be read using
|
||||
* \a propertiesStyle. If false, \a propertiesStyle is ignored.
|
||||
*
|
||||
* \note TagLib will *not* take ownership of the stream, the caller is
|
||||
* responsible for deleting it after the File object.
|
||||
*/
|
||||
File(IOStream *stram, bool readProperties = true,
|
||||
AudioProperties::ReadStyle propertiesStyle =
|
||||
AudioProperties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
virtual ~File();
|
||||
|
||||
Mod::Tag *tag() const;
|
||||
|
||||
/*!
|
||||
* Forwards to Mod::Tag::properties().
|
||||
* BIC: will be removed once File::toDict() is made virtual
|
||||
*/
|
||||
PropertyMap properties() const;
|
||||
|
||||
/*!
|
||||
* Forwards to Mod::Tag::setProperties().
|
||||
* BIC: will be removed once File::setProperties() is made virtual
|
||||
*/
|
||||
PropertyMap setProperties(const PropertyMap &);
|
||||
|
||||
/*!
|
||||
* Returns the IT::Properties for this file. If no audio properties
|
||||
* were read then this will return a null pointer.
|
||||
*/
|
||||
IT::Properties *audioProperties() const;
|
||||
|
||||
/*!
|
||||
* Save the file.
|
||||
* This is the same as calling save(AllTags);
|
||||
*
|
||||
* \note Saving Impulse Tracker tags is not supported.
|
||||
*/
|
||||
bool save();
|
||||
|
||||
|
||||
private:
|
||||
File(const File &);
|
||||
File &operator=(const File &);
|
||||
|
||||
void read(bool readProperties);
|
||||
|
||||
class FilePrivate;
|
||||
FilePrivate *d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,245 @@
|
|||
/***************************************************************************
|
||||
copyright :(C) 2011 by Mathias Panzenböck
|
||||
email : grosser.meister.morti@gmx.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
|
||||
* MA 02110-1301 USA *
|
||||
***************************************************************************/
|
||||
|
||||
#include "itproperties.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace IT;
|
||||
|
||||
class IT::Properties::PropertiesPrivate
|
||||
{
|
||||
public:
|
||||
PropertiesPrivate() :
|
||||
channels(0),
|
||||
lengthInPatterns(0),
|
||||
instrumentCount(0),
|
||||
sampleCount(0),
|
||||
patternCount(0),
|
||||
version(0),
|
||||
compatibleVersion(0),
|
||||
flags(0),
|
||||
special(0),
|
||||
globalVolume(0),
|
||||
mixVolume(0),
|
||||
tempo(0),
|
||||
bpmSpeed(0),
|
||||
panningSeparation(0),
|
||||
pitchWheelDepth(0)
|
||||
{
|
||||
}
|
||||
|
||||
int channels;
|
||||
ushort lengthInPatterns;
|
||||
ushort instrumentCount;
|
||||
ushort sampleCount;
|
||||
ushort patternCount;
|
||||
ushort version;
|
||||
ushort compatibleVersion;
|
||||
ushort flags;
|
||||
ushort special;
|
||||
uchar globalVolume;
|
||||
uchar mixVolume;
|
||||
uchar tempo;
|
||||
uchar bpmSpeed;
|
||||
uchar panningSeparation;
|
||||
uchar pitchWheelDepth;
|
||||
};
|
||||
|
||||
IT::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) :
|
||||
AudioProperties(propertiesStyle),
|
||||
d(new PropertiesPrivate)
|
||||
{
|
||||
}
|
||||
|
||||
IT::Properties::~Properties()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
int IT::Properties::length() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IT::Properties::bitrate() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IT::Properties::sampleRate() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IT::Properties::channels() const
|
||||
{
|
||||
return d->channels;
|
||||
}
|
||||
|
||||
TagLib::ushort IT::Properties::lengthInPatterns() const
|
||||
{
|
||||
return d->lengthInPatterns;
|
||||
}
|
||||
|
||||
bool IT::Properties::stereo() const
|
||||
{
|
||||
return d->flags & Stereo;
|
||||
}
|
||||
|
||||
TagLib::ushort IT::Properties::instrumentCount() const
|
||||
{
|
||||
return d->instrumentCount;
|
||||
}
|
||||
|
||||
TagLib::ushort IT::Properties::sampleCount() const
|
||||
{
|
||||
return d->sampleCount;
|
||||
}
|
||||
|
||||
TagLib::ushort IT::Properties::patternCount() const
|
||||
{
|
||||
return d->patternCount;
|
||||
}
|
||||
|
||||
TagLib::ushort IT::Properties::version() const
|
||||
{
|
||||
return d->version;
|
||||
}
|
||||
|
||||
TagLib::ushort IT::Properties::compatibleVersion() const
|
||||
{
|
||||
return d->compatibleVersion;
|
||||
}
|
||||
|
||||
TagLib::ushort IT::Properties::flags() const
|
||||
{
|
||||
return d->flags;
|
||||
}
|
||||
|
||||
TagLib::ushort IT::Properties::special() const
|
||||
{
|
||||
return d->special;
|
||||
}
|
||||
|
||||
uchar IT::Properties::globalVolume() const
|
||||
{
|
||||
return d->globalVolume;
|
||||
}
|
||||
|
||||
uchar IT::Properties::mixVolume() const
|
||||
{
|
||||
return d->mixVolume;
|
||||
}
|
||||
|
||||
uchar IT::Properties::tempo() const
|
||||
{
|
||||
return d->tempo;
|
||||
}
|
||||
|
||||
uchar IT::Properties::bpmSpeed() const
|
||||
{
|
||||
return d->bpmSpeed;
|
||||
}
|
||||
|
||||
uchar IT::Properties::panningSeparation() const
|
||||
{
|
||||
return d->panningSeparation;
|
||||
}
|
||||
|
||||
uchar IT::Properties::pitchWheelDepth() const
|
||||
{
|
||||
return d->pitchWheelDepth;
|
||||
}
|
||||
|
||||
void IT::Properties::setChannels(int channels)
|
||||
{
|
||||
d->channels = channels;
|
||||
}
|
||||
|
||||
void IT::Properties::setLengthInPatterns(ushort lengthInPatterns)
|
||||
{
|
||||
d->lengthInPatterns = lengthInPatterns;
|
||||
}
|
||||
|
||||
void IT::Properties::setInstrumentCount(ushort instrumentCount)
|
||||
{
|
||||
d->instrumentCount = instrumentCount;
|
||||
}
|
||||
|
||||
void IT::Properties::setSampleCount(ushort sampleCount)
|
||||
{
|
||||
d->sampleCount = sampleCount;
|
||||
}
|
||||
|
||||
void IT::Properties::setPatternCount(ushort patternCount)
|
||||
{
|
||||
d->patternCount = patternCount;
|
||||
}
|
||||
|
||||
void IT::Properties::setFlags(ushort flags)
|
||||
{
|
||||
d->flags = flags;
|
||||
}
|
||||
|
||||
void IT::Properties::setSpecial(ushort special)
|
||||
{
|
||||
d->special = special;
|
||||
}
|
||||
|
||||
void IT::Properties::setCompatibleVersion(ushort compatibleVersion)
|
||||
{
|
||||
d->compatibleVersion = compatibleVersion;
|
||||
}
|
||||
|
||||
void IT::Properties::setVersion(ushort version)
|
||||
{
|
||||
d->version = version;
|
||||
}
|
||||
|
||||
void IT::Properties::setGlobalVolume(uchar globalVolume)
|
||||
{
|
||||
d->globalVolume = globalVolume;
|
||||
}
|
||||
|
||||
void IT::Properties::setMixVolume(uchar mixVolume)
|
||||
{
|
||||
d->mixVolume = mixVolume;
|
||||
}
|
||||
|
||||
void IT::Properties::setTempo(uchar tempo)
|
||||
{
|
||||
d->tempo = tempo;
|
||||
}
|
||||
|
||||
void IT::Properties::setBpmSpeed(uchar bpmSpeed)
|
||||
{
|
||||
d->bpmSpeed = bpmSpeed;
|
||||
}
|
||||
|
||||
void IT::Properties::setPanningSeparation(uchar panningSeparation)
|
||||
{
|
||||
d->panningSeparation = panningSeparation;
|
||||
}
|
||||
|
||||
void IT::Properties::setPitchWheelDepth(uchar pitchWheelDepth)
|
||||
{
|
||||
d->pitchWheelDepth = pitchWheelDepth;
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2011 by Mathias Panzenböck
|
||||
email : grosser.meister.morti@gmx.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
|
||||
* MA 02110-1301 USA *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_ITPROPERTIES_H
|
||||
#define TAGLIB_ITPROPERTIES_H
|
||||
|
||||
#include "taglib.h"
|
||||
#include "audioproperties.h"
|
||||
|
||||
namespace TagLib {
|
||||
namespace IT {
|
||||
class TAGLIB_EXPORT Properties : public AudioProperties {
|
||||
friend class File;
|
||||
public:
|
||||
/*! Flag bits. */
|
||||
enum {
|
||||
Stereo = 1,
|
||||
Vol0MixOptimizations = 2,
|
||||
UseInstruments = 4,
|
||||
LinearSlides = 8,
|
||||
OldEffects = 16,
|
||||
LinkEffects = 32,
|
||||
UseMidiPitchController = 64,
|
||||
RequestEmbeddedMidiConf = 128
|
||||
};
|
||||
|
||||
/*! Special bits. */
|
||||
enum {
|
||||
MessageAttached = 1,
|
||||
MidiConfEmbedded = 8
|
||||
};
|
||||
|
||||
Properties(AudioProperties::ReadStyle propertiesStyle);
|
||||
virtual ~Properties();
|
||||
|
||||
int length() const;
|
||||
int bitrate() const;
|
||||
int sampleRate() const;
|
||||
int channels() const;
|
||||
|
||||
ushort lengthInPatterns() const;
|
||||
bool stereo() const;
|
||||
ushort instrumentCount() const;
|
||||
ushort sampleCount() const;
|
||||
ushort patternCount() const;
|
||||
ushort version() const;
|
||||
ushort compatibleVersion() const;
|
||||
ushort flags() const;
|
||||
ushort special() const;
|
||||
uchar globalVolume() const;
|
||||
uchar mixVolume() const;
|
||||
uchar tempo() const;
|
||||
uchar bpmSpeed() const;
|
||||
uchar panningSeparation() const;
|
||||
uchar pitchWheelDepth() const;
|
||||
|
||||
void setChannels(int channels);
|
||||
void setLengthInPatterns(ushort lengthInPatterns);
|
||||
void setInstrumentCount(ushort instrumentCount);
|
||||
void setSampleCount (ushort sampleCount);
|
||||
void setPatternCount(ushort patternCount);
|
||||
void setVersion (ushort version);
|
||||
void setCompatibleVersion(ushort compatibleVersion);
|
||||
void setFlags (ushort flags);
|
||||
void setSpecial (ushort special);
|
||||
void setGlobalVolume(uchar globalVolume);
|
||||
void setMixVolume (uchar mixVolume);
|
||||
void setTempo (uchar tempo);
|
||||
void setBpmSpeed (uchar bpmSpeed);
|
||||
void setPanningSeparation(uchar panningSeparation);
|
||||
void setPitchWheelDepth (uchar pitchWheelDepth);
|
||||
|
||||
private:
|
||||
Properties(const Properties&);
|
||||
Properties &operator=(const Properties&);
|
||||
|
||||
class PropertiesPrivate;
|
||||
PropertiesPrivate *d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,185 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2011 by Mathias Panzenböck
|
||||
email : grosser.meister.morti@gmx.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
|
||||
* MA 02110-1301 USA *
|
||||
***************************************************************************/
|
||||
|
||||
#include "modfile.h"
|
||||
#include "tstringlist.h"
|
||||
#include "tdebug.h"
|
||||
#include "modfileprivate.h"
|
||||
#include "tpropertymap.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace Mod;
|
||||
|
||||
class Mod::File::FilePrivate
|
||||
{
|
||||
public:
|
||||
FilePrivate(AudioProperties::ReadStyle propertiesStyle)
|
||||
: properties(propertiesStyle)
|
||||
{
|
||||
}
|
||||
|
||||
Mod::Tag tag;
|
||||
Mod::Properties properties;
|
||||
};
|
||||
|
||||
Mod::File::File(FileName file, bool readProperties,
|
||||
AudioProperties::ReadStyle propertiesStyle) :
|
||||
Mod::FileBase(file),
|
||||
d(new FilePrivate(propertiesStyle))
|
||||
{
|
||||
read(readProperties);
|
||||
}
|
||||
|
||||
Mod::File::File(IOStream *stream, bool readProperties,
|
||||
AudioProperties::ReadStyle propertiesStyle) :
|
||||
Mod::FileBase(stream),
|
||||
d(new FilePrivate(propertiesStyle))
|
||||
{
|
||||
read(readProperties);
|
||||
}
|
||||
|
||||
Mod::File::~File()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
Mod::Tag *Mod::File::tag() const
|
||||
{
|
||||
return &d->tag;
|
||||
}
|
||||
|
||||
Mod::Properties *Mod::File::audioProperties() const
|
||||
{
|
||||
return &d->properties;
|
||||
}
|
||||
|
||||
PropertyMap Mod::File::properties() const
|
||||
{
|
||||
return d->tag.properties();
|
||||
}
|
||||
|
||||
PropertyMap Mod::File::setProperties(const PropertyMap &properties)
|
||||
{
|
||||
return d->tag.setProperties(properties);
|
||||
}
|
||||
|
||||
bool Mod::File::save()
|
||||
{
|
||||
if(readOnly()) {
|
||||
debug("Mod::File::save() - Cannot save to a read only file.");
|
||||
return false;
|
||||
}
|
||||
seek(0);
|
||||
writeString(d->tag.title(), 20);
|
||||
StringList lines = d->tag.comment().split("\n");
|
||||
uint n = std::min(lines.size(), d->properties.instrumentCount());
|
||||
for(uint i = 0; i < n; ++ i) {
|
||||
writeString(lines[i], 22);
|
||||
seek(8, Current);
|
||||
}
|
||||
|
||||
for(uint i = n; i < d->properties.instrumentCount(); ++ i) {
|
||||
writeString(String::null, 22);
|
||||
seek(8, Current);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Mod::File::read(bool)
|
||||
{
|
||||
if(!isOpen())
|
||||
return;
|
||||
|
||||
seek(1080);
|
||||
ByteVector modId = readBlock(4);
|
||||
READ_ASSERT(modId.size() == 4);
|
||||
|
||||
int channels = 4;
|
||||
uint instruments = 31;
|
||||
if(modId == "M.K." || modId == "M!K!" || modId == "M&K!" || modId == "N.T.") {
|
||||
d->tag.setTrackerName("ProTracker");
|
||||
channels = 4;
|
||||
}
|
||||
else if(modId.startsWith("FLT") || modId.startsWith("TDZ")) {
|
||||
d->tag.setTrackerName("StarTrekker");
|
||||
char digit = modId[3];
|
||||
READ_ASSERT(digit >= '0' && digit <= '9');
|
||||
channels = digit - '0';
|
||||
}
|
||||
else if(modId.endsWith("CHN")) {
|
||||
d->tag.setTrackerName("StarTrekker");
|
||||
char digit = modId[0];
|
||||
READ_ASSERT(digit >= '0' && digit <= '9');
|
||||
channels = digit - '0';
|
||||
}
|
||||
else if(modId == "CD81" || modId == "OKTA") {
|
||||
d->tag.setTrackerName("Atari Oktalyzer");
|
||||
channels = 8;
|
||||
}
|
||||
else if(modId.endsWith("CH") || modId.endsWith("CN")) {
|
||||
d->tag.setTrackerName("TakeTracker");
|
||||
char digit = modId[0];
|
||||
READ_ASSERT(digit >= '0' && digit <= '9');
|
||||
channels = (digit - '0') * 10;
|
||||
digit = modId[1];
|
||||
READ_ASSERT(digit >= '0' && digit <= '9');
|
||||
channels += digit - '0';
|
||||
}
|
||||
else {
|
||||
// Not sure if this is correct. I'd need a file
|
||||
// created with NoiseTracker to check this.
|
||||
d->tag.setTrackerName("NoiseTracker"); // probably
|
||||
channels = 4;
|
||||
instruments = 15;
|
||||
}
|
||||
d->properties.setChannels(channels);
|
||||
d->properties.setInstrumentCount(instruments);
|
||||
|
||||
seek(0);
|
||||
READ_STRING(d->tag.setTitle, 20);
|
||||
|
||||
StringList comment;
|
||||
for(uint i = 0; i < instruments; ++ i) {
|
||||
READ_STRING_AS(instrumentName, 22);
|
||||
// value in words, * 2 (<< 1) for bytes:
|
||||
READ_U16B_AS(sampleLength);
|
||||
|
||||
READ_BYTE_AS(fineTuneByte);
|
||||
int fineTune = fineTuneByte & 0xF;
|
||||
// > 7 means negative value
|
||||
if(fineTune > 7) fineTune -= 16;
|
||||
|
||||
READ_BYTE_AS(volume);
|
||||
if(volume > 64) volume = 64;
|
||||
// volume in decibels: 20 * log10(volume / 64)
|
||||
|
||||
// value in words, * 2 (<< 1) for bytes:
|
||||
READ_U16B_AS(repeatStart);
|
||||
// value in words, * 2 (<< 1) for bytes:
|
||||
READ_U16B_AS(repatLength);
|
||||
|
||||
comment.append(instrumentName);
|
||||
}
|
||||
|
||||
READ_BYTE(d->properties.setLengthInPatterns);
|
||||
|
||||
d->tag.setComment(comment.toString("\n"));
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2011 by Mathias Panzenböck
|
||||
email : grosser.meister.morti@gmx.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
|
||||
* MA 02110-1301 USA *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_MODFILE_H
|
||||
#define TAGLIB_MODFILE_H
|
||||
|
||||
#include "tfile.h"
|
||||
#include "audioproperties.h"
|
||||
#include "taglib_export.h"
|
||||
#include "modfilebase.h"
|
||||
#include "modtag.h"
|
||||
#include "modproperties.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace Mod {
|
||||
|
||||
class TAGLIB_EXPORT File : public TagLib::Mod::FileBase
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* Contructs a Protracker file from \a file. If \a readProperties
|
||||
* is true the file's audio properties will also be read using
|
||||
* \a propertiesStyle. If false, \a propertiesStyle is ignored.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true,
|
||||
AudioProperties::ReadStyle propertiesStyle =
|
||||
AudioProperties::Average);
|
||||
|
||||
/*!
|
||||
* Contructs a Protracker file from \a stream. If \a readProperties
|
||||
* is true the file's audio properties will also be read using
|
||||
* \a propertiesStyle. If false, \a propertiesStyle is ignored.
|
||||
*
|
||||
* \note TagLib will *not* take ownership of the stream, the caller is
|
||||
* responsible for deleting it after the File object.
|
||||
*/
|
||||
File(IOStream *stream, bool readProperties = true,
|
||||
AudioProperties::ReadStyle propertiesStyle =
|
||||
AudioProperties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
virtual ~File();
|
||||
|
||||
Mod::Tag *tag() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- export function.
|
||||
* Forwards to Mod::Tag::properties().
|
||||
*/
|
||||
PropertyMap properties() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- import function.
|
||||
* Forwards to Mod::Tag::setProperties().
|
||||
*/
|
||||
PropertyMap setProperties(const PropertyMap &);
|
||||
/*!
|
||||
* Returns the Mod::Properties for this file. If no audio properties
|
||||
* were read then this will return a null pointer.
|
||||
*/
|
||||
Mod::Properties *audioProperties() const;
|
||||
|
||||
/*!
|
||||
* Save the file.
|
||||
* This is the same as calling save(AllTags);
|
||||
*
|
||||
* \note Saving Protracker tags is not supported.
|
||||
*/
|
||||
bool save();
|
||||
|
||||
private:
|
||||
File(const File &);
|
||||
File &operator=(const File &);
|
||||
|
||||
void read(bool readProperties);
|
||||
|
||||
class FilePrivate;
|
||||
FilePrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,120 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2011 by Mathias Panzenböck
|
||||
email : grosser.meister.morti@gmx.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
|
||||
* MA 02110-1301 USA *
|
||||
***************************************************************************/
|
||||
|
||||
#include "tdebug.h"
|
||||
#include "modfilebase.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace Mod;
|
||||
|
||||
Mod::FileBase::FileBase(FileName file) : TagLib::File(file)
|
||||
{
|
||||
}
|
||||
|
||||
Mod::FileBase::FileBase(IOStream *stream) : TagLib::File(stream)
|
||||
{
|
||||
}
|
||||
|
||||
void Mod::FileBase::writeString(const String &s, ulong size, char padding)
|
||||
{
|
||||
ByteVector data(s.data(String::Latin1));
|
||||
data.resize(size, padding);
|
||||
writeBlock(data);
|
||||
}
|
||||
|
||||
bool Mod::FileBase::readString(String &s, ulong size)
|
||||
{
|
||||
ByteVector data(readBlock(size));
|
||||
if(data.size() < size) return false;
|
||||
int index = data.find((char) 0);
|
||||
if(index > -1)
|
||||
{
|
||||
data.resize(index);
|
||||
}
|
||||
data.replace((char) 0xff, ' ');
|
||||
|
||||
s = data;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Mod::FileBase::writeByte(uchar byte)
|
||||
{
|
||||
ByteVector data(1, byte);
|
||||
writeBlock(data);
|
||||
}
|
||||
|
||||
void Mod::FileBase::writeU16L(ushort number)
|
||||
{
|
||||
writeBlock(ByteVector::fromShort(number, false));
|
||||
}
|
||||
|
||||
void Mod::FileBase::writeU32L(ulong number)
|
||||
{
|
||||
writeBlock(ByteVector::fromUInt(number, false));
|
||||
}
|
||||
|
||||
void Mod::FileBase::writeU16B(ushort number)
|
||||
{
|
||||
writeBlock(ByteVector::fromShort(number, true));
|
||||
}
|
||||
|
||||
void Mod::FileBase::writeU32B(ulong number)
|
||||
{
|
||||
writeBlock(ByteVector::fromUInt(number, true));
|
||||
}
|
||||
|
||||
bool Mod::FileBase::readByte(uchar &byte)
|
||||
{
|
||||
ByteVector data(readBlock(1));
|
||||
if(data.size() < 1) return false;
|
||||
byte = data[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Mod::FileBase::readU16L(ushort &number)
|
||||
{
|
||||
ByteVector data(readBlock(2));
|
||||
if(data.size() < 2) return false;
|
||||
number = data.toUShort(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Mod::FileBase::readU32L(ulong &number) {
|
||||
ByteVector data(readBlock(4));
|
||||
if(data.size() < 4) return false;
|
||||
number = data.toUInt(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Mod::FileBase::readU16B(ushort &number)
|
||||
{
|
||||
ByteVector data(readBlock(2));
|
||||
if(data.size() < 2) return false;
|
||||
number = data.toUShort(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Mod::FileBase::readU32B(ulong &number) {
|
||||
ByteVector data(readBlock(4));
|
||||
if(data.size() < 4) return false;
|
||||
number = data.toUInt(true);
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2011 by Mathias Panzenböck
|
||||
email : grosser.meister.morti@gmx.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
|
||||
* MA 02110-1301 USA *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_MODFILEBASE_H
|
||||
#define TAGLIB_MODFILEBASE_H
|
||||
|
||||
#include "taglib.h"
|
||||
#include "tfile.h"
|
||||
#include "tstring.h"
|
||||
#include "tlist.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace Mod {
|
||||
|
||||
class TAGLIB_EXPORT FileBase : public TagLib::File
|
||||
{
|
||||
protected:
|
||||
FileBase(FileName file);
|
||||
FileBase(IOStream *stream);
|
||||
|
||||
void writeString(const String &s, ulong size, char padding = 0);
|
||||
void writeByte(uchar byte);
|
||||
void writeU16L(ushort number);
|
||||
void writeU32L(ulong number);
|
||||
void writeU16B(ushort number);
|
||||
void writeU32B(ulong number);
|
||||
|
||||
bool readString(String &s, ulong size);
|
||||
bool readByte(uchar &byte);
|
||||
bool readU16L(ushort &number);
|
||||
bool readU32L(ulong &number);
|
||||
bool readU16B(ushort &number);
|
||||
bool readU32B(ulong &number);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,67 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2011 by Mathias Panzenböck
|
||||
email : grosser.meister.morti@gmx.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
|
||||
* MA 02110-1301 USA *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_MODFILEPRIVATE_H
|
||||
#define TAGLIB_MODFILEPRIVATE_H
|
||||
|
||||
// some helper-macros only used internally by (s3m|it|xm)file.cpp
|
||||
#define READ_ASSERT(cond) \
|
||||
if(!(cond)) \
|
||||
{ \
|
||||
setValid(false); \
|
||||
return; \
|
||||
}
|
||||
|
||||
#define READ(setter,type,read) \
|
||||
{ \
|
||||
type number; \
|
||||
READ_ASSERT(read(number)); \
|
||||
setter(number); \
|
||||
}
|
||||
|
||||
#define READ_BYTE(setter) READ(setter,uchar,readByte)
|
||||
#define READ_U16L(setter) READ(setter,ushort,readU16L)
|
||||
#define READ_U32L(setter) READ(setter,ulong,readU32L)
|
||||
#define READ_U16B(setter) READ(setter,ushort,readU16B)
|
||||
#define READ_U32B(setter) READ(setter,ulong,readU32B)
|
||||
|
||||
#define READ_STRING(setter,size) \
|
||||
{ \
|
||||
String s; \
|
||||
READ_ASSERT(readString(s, size)); \
|
||||
setter(s); \
|
||||
}
|
||||
|
||||
#define READ_AS(type,name,read) \
|
||||
type name = 0; \
|
||||
READ_ASSERT(read(name));
|
||||
|
||||
#define READ_BYTE_AS(name) READ_AS(uchar,name,readByte)
|
||||
#define READ_U16L_AS(name) READ_AS(ushort,name,readU16L)
|
||||
#define READ_U32L_AS(name) READ_AS(ulong,name,readU32L)
|
||||
#define READ_U16B_AS(name) READ_AS(ushort,name,readU16B)
|
||||
#define READ_U32B_AS(name) READ_AS(ulong,name,readU32B)
|
||||
|
||||
#define READ_STRING_AS(name,size) \
|
||||
String name; \
|
||||
READ_ASSERT(readString(name, size));
|
||||
|
||||
#endif
|
|
@ -0,0 +1,96 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2011 by Mathias Panzenböck
|
||||
email : grosser.meister.morti@gmx.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
|
||||
* MA 02110-1301 USA *
|
||||
***************************************************************************/
|
||||
|
||||
#include "modproperties.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace Mod;
|
||||
|
||||
class Mod::Properties::PropertiesPrivate
|
||||
{
|
||||
public:
|
||||
PropertiesPrivate() :
|
||||
channels(0),
|
||||
instrumentCount(0),
|
||||
lengthInPatterns(0)
|
||||
{
|
||||
}
|
||||
|
||||
int channels;
|
||||
uint instrumentCount;
|
||||
uchar lengthInPatterns;
|
||||
};
|
||||
|
||||
Mod::Properties::Properties(AudioProperties::ReadStyle propertiesStyle) :
|
||||
AudioProperties(propertiesStyle),
|
||||
d(new PropertiesPrivate)
|
||||
{
|
||||
}
|
||||
|
||||
Mod::Properties::~Properties()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
int Mod::Properties::length() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Mod::Properties::bitrate() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Mod::Properties::sampleRate() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Mod::Properties::channels() const
|
||||
{
|
||||
return d->channels;
|
||||
}
|
||||
|
||||
TagLib::uint Mod::Properties::instrumentCount() const
|
||||
{
|
||||
return d->instrumentCount;
|
||||
}
|
||||
|
||||
uchar Mod::Properties::lengthInPatterns() const
|
||||
{
|
||||
return d->lengthInPatterns;
|
||||
}
|
||||
|
||||
void Mod::Properties::setChannels(int channels)
|
||||
{
|
||||
d->channels = channels;
|
||||
}
|
||||
|
||||
void Mod::Properties::setInstrumentCount(uint instrumentCount)
|
||||
{
|
||||
d->instrumentCount = instrumentCount;
|
||||
}
|
||||
|
||||
void Mod::Properties::setLengthInPatterns(uchar lengthInPatterns)
|
||||
{
|
||||
d->lengthInPatterns = lengthInPatterns;
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2011 by Mathias Panzenböck
|
||||
email : grosser.meister.morti@gmx.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
|
||||
* MA 02110-1301 USA *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_MODPROPERTIES_H
|
||||
#define TAGLIB_MODPROPERTIES_H
|
||||
|
||||
#include "taglib.h"
|
||||
#include "audioproperties.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace Mod {
|
||||
|
||||
class TAGLIB_EXPORT Properties : public AudioProperties
|
||||
{
|
||||
public:
|
||||
Properties(AudioProperties::ReadStyle propertiesStyle);
|
||||
virtual ~Properties();
|
||||
|
||||
int length() const;
|
||||
int bitrate() const;
|
||||
int sampleRate() const;
|
||||
int channels() const;
|
||||
|
||||
uint instrumentCount() const;
|
||||
uchar lengthInPatterns() const;
|
||||
|
||||
void setChannels(int channels);
|
||||
|
||||
void setInstrumentCount(uint sampleCount);
|
||||
void setLengthInPatterns(uchar lengthInPatterns);
|
||||
|
||||
private:
|
||||
friend class File;
|
||||
|
||||
Properties(const Properties&);
|
||||
Properties &operator=(const Properties&);
|
||||
|
||||
class PropertiesPrivate;
|
||||
PropertiesPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,168 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2011 by Mathias Panzenböck
|
||||
email : grosser.meister.morti@gmx.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
|
||||
* MA 02110-1301 USA *
|
||||
***************************************************************************/
|
||||
|
||||
#include "modtag.h"
|
||||
#include "tstringlist.h"
|
||||
#include "tpropertymap.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace Mod;
|
||||
|
||||
class Mod::Tag::TagPrivate
|
||||
{
|
||||
public:
|
||||
TagPrivate()
|
||||
{
|
||||
}
|
||||
|
||||
String title;
|
||||
String comment;
|
||||
String trackerName;
|
||||
};
|
||||
|
||||
Mod::Tag::Tag() : TagLib::Tag()
|
||||
{
|
||||
d = new TagPrivate;
|
||||
}
|
||||
|
||||
Mod::Tag::~Tag()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String Mod::Tag::title() const
|
||||
{
|
||||
return d->title;
|
||||
}
|
||||
|
||||
String Mod::Tag::artist() const
|
||||
{
|
||||
return String::null;
|
||||
}
|
||||
|
||||
String Mod::Tag::album() const
|
||||
{
|
||||
return String::null;
|
||||
}
|
||||
|
||||
String Mod::Tag::comment() const
|
||||
{
|
||||
return d->comment;
|
||||
}
|
||||
|
||||
String Mod::Tag::genre() const
|
||||
{
|
||||
return String::null;
|
||||
}
|
||||
|
||||
TagLib::uint Mod::Tag::year() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
TagLib::uint Mod::Tag::track() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
String Mod::Tag::trackerName() const
|
||||
{
|
||||
return d->trackerName;
|
||||
}
|
||||
|
||||
void Mod::Tag::setTitle(const String &title)
|
||||
{
|
||||
d->title = title;
|
||||
}
|
||||
|
||||
void Mod::Tag::setArtist(const String &)
|
||||
{
|
||||
}
|
||||
|
||||
void Mod::Tag::setAlbum(const String &)
|
||||
{
|
||||
}
|
||||
|
||||
void Mod::Tag::setComment(const String &comment)
|
||||
{
|
||||
d->comment = comment;
|
||||
}
|
||||
|
||||
void Mod::Tag::setGenre(const String &)
|
||||
{
|
||||
}
|
||||
|
||||
void Mod::Tag::setYear(uint)
|
||||
{
|
||||
}
|
||||
|
||||
void Mod::Tag::setTrack(uint)
|
||||
{
|
||||
}
|
||||
|
||||
void Mod::Tag::setTrackerName(const String &trackerName)
|
||||
{
|
||||
d->trackerName = trackerName;
|
||||
}
|
||||
|
||||
PropertyMap Mod::Tag::properties() const
|
||||
{
|
||||
PropertyMap properties;
|
||||
properties["TITLE"] = d->title;
|
||||
properties["COMMENT"] = d->comment;
|
||||
if(!(d->trackerName.isNull()))
|
||||
properties["TRACKERNAME"] = d->trackerName;
|
||||
return properties;
|
||||
}
|
||||
|
||||
PropertyMap Mod::Tag::setProperties(const PropertyMap &origProps)
|
||||
{
|
||||
PropertyMap properties(origProps);
|
||||
properties.removeEmpty();
|
||||
StringList oneValueSet;
|
||||
if(properties.contains("TITLE")) {
|
||||
d->title = properties["TITLE"].front();
|
||||
oneValueSet.append("TITLE");
|
||||
} else
|
||||
d->title = String::null;
|
||||
|
||||
if(properties.contains("COMMENT")) {
|
||||
d->comment = properties["COMMENT"].front();
|
||||
oneValueSet.append("COMMENT");
|
||||
} else
|
||||
d->comment = String::null;
|
||||
|
||||
if(properties.contains("TRACKERNAME")) {
|
||||
d->trackerName = properties["TRACKERNAME"].front();
|
||||
oneValueSet.append("TRACKERNAME");
|
||||
} else
|
||||
d->trackerName = String::null;
|
||||
|
||||
// for each tag that has been set above, remove the first entry in the corresponding
|
||||
// value list. The others will be returned as unsupported by this format.
|
||||
for(StringList::Iterator it = oneValueSet.begin(); it != oneValueSet.end(); ++it) {
|
||||
if(properties[*it].size() == 1)
|
||||
properties.erase(*it);
|
||||
else
|
||||
properties[*it].erase( properties[*it].begin() );
|
||||
}
|
||||
return properties;
|
||||
}
|
|
@ -0,0 +1,190 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2011 by Mathias Panzenböck
|
||||
email : grosser.meister.morti@gmx.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
|
||||
* MA 02110-1301 USA *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_MODTAG_H
|
||||
#define TAGLIB_MODTAG_H
|
||||
|
||||
#include "tag.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace Mod {
|
||||
|
||||
/*!
|
||||
* Tags for module files (Mod, S3M, IT, XM).
|
||||
*
|
||||
* Note that only the \a title is supported as such by most
|
||||
* module file formats. Except for XM files the \a trackerName
|
||||
* is derived from the file format or the flavour of the file
|
||||
* format. For XM files it is stored in the file.
|
||||
*
|
||||
* The \a comment tag is not strictly supported by module files,
|
||||
* but it is common practice to abuse instrument/sample/pattern
|
||||
* names as multiline comments. TagLib does so as well.
|
||||
*/
|
||||
class TAGLIB_EXPORT Tag : public TagLib::Tag
|
||||
{
|
||||
public:
|
||||
Tag();
|
||||
virtual ~Tag();
|
||||
|
||||
/*!
|
||||
* Returns the track name; if no track name is present in the tag
|
||||
* String::null will be returned.
|
||||
*/
|
||||
String title() const;
|
||||
|
||||
/*!
|
||||
* Not supported by module files. Therefore always returns String::null.
|
||||
*/
|
||||
String artist() const;
|
||||
|
||||
/*!
|
||||
* Not supported by module files. Therefore always returns String::null.
|
||||
*/
|
||||
String album() const;
|
||||
|
||||
/*!
|
||||
* Returns the track comment derived from the instrument/sample/pattern
|
||||
* names; if no comment is present in the tag String::null will be
|
||||
* returned.
|
||||
*/
|
||||
String comment() const;
|
||||
|
||||
/*!
|
||||
* Not supported by module files. Therefore always returns String::null.
|
||||
*/
|
||||
String genre() const;
|
||||
|
||||
/*!
|
||||
* Not supported by module files. Therefore always returns 0.
|
||||
*/
|
||||
uint year() const;
|
||||
|
||||
/*!
|
||||
* Not supported by module files. Therefore always returns 0.
|
||||
*/
|
||||
uint track() const;
|
||||
|
||||
/*!
|
||||
* Returns the name of the tracker used to create/edit the module file.
|
||||
* Only XM files store this tag to the file as such, for other formats
|
||||
* (Mod, S3M, IT) this is derived from the file type or the flavour of
|
||||
* the file type. Therefore only XM files might have an empty
|
||||
* (String::null) tracker name.
|
||||
*/
|
||||
String trackerName() const;
|
||||
|
||||
/*!
|
||||
* Sets the title to \a title. If \a title is String::null then this
|
||||
* value will be cleared.
|
||||
*
|
||||
* The length limits per file type are (1 characetr = 1 byte):
|
||||
* Mod 20 characters, S3M 27 characters, IT 25 characters and XM 20
|
||||
* characters.
|
||||
*/
|
||||
void setTitle(const String &title);
|
||||
|
||||
/*!
|
||||
* Not supported by module files and therefore ignored.
|
||||
*/
|
||||
void setArtist(const String &artist);
|
||||
|
||||
/*!
|
||||
* Not supported by module files and therefore ignored.
|
||||
*/
|
||||
void setAlbum(const String &album);
|
||||
|
||||
/*!
|
||||
* Sets the comment to \a comment. If \a comment is String::null then
|
||||
* this value will be cleared.
|
||||
*
|
||||
* Note that module file formats don't actually support a comment tag.
|
||||
* Instead the names of instruments/patterns/samples are abused as
|
||||
* a multiline comment. Because of this the number of lines in a
|
||||
* module file is fixed to the number of instruments/patterns/samples.
|
||||
*
|
||||
* Also note that the instrument/pattern/sample name length is limited
|
||||
* an thus the line length in comments are limited. Too big comments
|
||||
* will be truncated.
|
||||
*
|
||||
* The line length limits per file type are (1 characetr = 1 byte):
|
||||
* Mod 22 characters, S3M 27 characters, IT 25 characters and XM 22
|
||||
* characters.
|
||||
*/
|
||||
void setComment(const String &comment);
|
||||
|
||||
/*!
|
||||
* Not supported by module files and therefore ignored.
|
||||
*/
|
||||
void setGenre(const String &genre);
|
||||
|
||||
/*!
|
||||
* Not supported by module files and therefore ignored.
|
||||
*/
|
||||
void setYear(uint year);
|
||||
|
||||
/*!
|
||||
* Not supported by module files and therefore ignored.
|
||||
*/
|
||||
void setTrack(uint track);
|
||||
|
||||
/*!
|
||||
* Sets the tracker name to \a trackerName. If \a trackerName is
|
||||
* String::null then this value will be cleared.
|
||||
*
|
||||
* Note that only XM files support this tag. Setting the
|
||||
* tracker name for other module file formats will be ignored.
|
||||
*
|
||||
* The length of this tag is limited to 20 characters (1 character
|
||||
* = 1 byte).
|
||||
*/
|
||||
void setTrackerName(const String &trackerName);
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- export function.
|
||||
* Since the module tag is very limited, the exported map is as well.
|
||||
*/
|
||||
PropertyMap properties() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- import function.
|
||||
* Because of the limitations of the module file tag, any tags besides
|
||||
* COMMENT, TITLE and, if it is an XM file, TRACKERNAME, will be
|
||||
* returened. Additionally, if the map contains tags with multiple values,
|
||||
* all but the first will be contained in the returned map of unsupported
|
||||
* properties.
|
||||
*/
|
||||
PropertyMap setProperties(const PropertyMap &);
|
||||
|
||||
private:
|
||||
Tag(const Tag &);
|
||||
Tag &operator=(const Tag &);
|
||||
|
||||
class TagPrivate;
|
||||
TagPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,198 @@
|
|||
/**************************************************************************
|
||||
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/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <tdebug.h>
|
||||
#include <tstring.h>
|
||||
#include "mp4atom.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
const char *MP4::Atom::containers[11] = {
|
||||
"moov", "udta", "mdia", "meta", "ilst",
|
||||
"stbl", "minf", "moof", "traf", "trak",
|
||||
"stsd"
|
||||
};
|
||||
|
||||
MP4::Atom::Atom(File *file)
|
||||
{
|
||||
offset = file->tell();
|
||||
ByteVector header = file->readBlock(8);
|
||||
if (header.size() != 8) {
|
||||
// The atom header must be 8 bytes long, otherwise there is either
|
||||
// trailing garbage or the file is truncated
|
||||
debug("MP4: Couldn't read 8 bytes of data for atom header");
|
||||
length = 0;
|
||||
file->seek(0, File::End);
|
||||
return;
|
||||
}
|
||||
|
||||
length = header.mid(0, 4).toUInt();
|
||||
|
||||
if (length == 1) {
|
||||
long long longLength = file->readBlock(8).toLongLong();
|
||||
if (longLength >= 8 && longLength <= 0xFFFFFFFF) {
|
||||
// The atom has a 64-bit length, but it's actually a 32-bit value
|
||||
length = (long)longLength;
|
||||
}
|
||||
else {
|
||||
debug("MP4: 64-bit atoms are not supported");
|
||||
length = 0;
|
||||
file->seek(0, File::End);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (length < 8) {
|
||||
debug("MP4: Invalid atom size");
|
||||
length = 0;
|
||||
file->seek(0, File::End);
|
||||
return;
|
||||
}
|
||||
|
||||
name = header.mid(4, 4);
|
||||
|
||||
for(int i = 0; i < numContainers; i++) {
|
||||
if(name == containers[i]) {
|
||||
if(name == "meta") {
|
||||
file->seek(4, File::Current);
|
||||
}
|
||||
else if(name == "stsd") {
|
||||
file->seek(8, File::Current);
|
||||
}
|
||||
while(file->tell() < offset + length) {
|
||||
MP4::Atom *child = new MP4::Atom(file);
|
||||
children.append(child);
|
||||
if (child->length == 0)
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
file->seek(offset + length);
|
||||
}
|
||||
|
||||
MP4::Atom::~Atom()
|
||||
{
|
||||
for(unsigned int i = 0; i < children.size(); i++) {
|
||||
delete children[i];
|
||||
}
|
||||
children.clear();
|
||||
}
|
||||
|
||||
MP4::Atom *
|
||||
MP4::Atom::find(const char *name1, const char *name2, const char *name3, const char *name4)
|
||||
{
|
||||
if(name1 == 0) {
|
||||
return this;
|
||||
}
|
||||
for(unsigned int i = 0; i < children.size(); i++) {
|
||||
if(children[i]->name == name1) {
|
||||
return children[i]->find(name2, name3, name4);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MP4::AtomList
|
||||
MP4::Atom::findall(const char *name, bool recursive)
|
||||
{
|
||||
MP4::AtomList result;
|
||||
for(unsigned int i = 0; i < children.size(); i++) {
|
||||
if(children[i]->name == name) {
|
||||
result.append(children[i]);
|
||||
}
|
||||
if(recursive) {
|
||||
result.append(children[i]->findall(name, recursive));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
MP4::Atom::path(MP4::AtomList &path, const char *name1, const char *name2, const char *name3)
|
||||
{
|
||||
path.append(this);
|
||||
if(name1 == 0) {
|
||||
return true;
|
||||
}
|
||||
for(unsigned int i = 0; i < children.size(); i++) {
|
||||
if(children[i]->name == name1) {
|
||||
return children[i]->path(path, name2, name3);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
MP4::Atoms::Atoms(File *file)
|
||||
{
|
||||
file->seek(0, File::End);
|
||||
long end = file->tell();
|
||||
file->seek(0);
|
||||
while(file->tell() + 8 <= end) {
|
||||
MP4::Atom *atom = new MP4::Atom(file);
|
||||
atoms.append(atom);
|
||||
if (atom->length == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MP4::Atoms::~Atoms()
|
||||
{
|
||||
for(unsigned int i = 0; i < atoms.size(); i++) {
|
||||
delete atoms[i];
|
||||
}
|
||||
atoms.clear();
|
||||
}
|
||||
|
||||
MP4::Atom *
|
||||
MP4::Atoms::find(const char *name1, const char *name2, const char *name3, const char *name4)
|
||||
{
|
||||
for(unsigned int i = 0; i < atoms.size(); i++) {
|
||||
if(atoms[i]->name == name1) {
|
||||
return atoms[i]->find(name2, name3, name4);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MP4::AtomList
|
||||
MP4::Atoms::path(const char *name1, const char *name2, const char *name3, const char *name4)
|
||||
{
|
||||
MP4::AtomList path;
|
||||
for(unsigned int i = 0; i < atoms.size(); i++) {
|
||||
if(atoms[i]->name == name1) {
|
||||
if(!atoms[i]->path(path, name2, name3, name4)) {
|
||||
path.clear();
|
||||
}
|
||||
return path;
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
/**************************************************************************
|
||||
copyright : (C) 2007,2011 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
// This file is not part of the public API!
|
||||
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
|
||||
#ifndef TAGLIB_MP4ATOM_H
|
||||
#define TAGLIB_MP4ATOM_H
|
||||
|
||||
#include "tfile.h"
|
||||
#include "tlist.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace MP4 {
|
||||
|
||||
class Atom;
|
||||
typedef TagLib::List<Atom *> AtomList;
|
||||
|
||||
enum AtomDataType
|
||||
{
|
||||
TypeImplicit = 0, // for use with tags for which no type needs to be indicated because only one type is allowed
|
||||
TypeUTF8 = 1, // without any count or null terminator
|
||||
TypeUTF16 = 2, // also known as UTF-16BE
|
||||
TypeSJIS = 3, // deprecated unless it is needed for special Japanese characters
|
||||
TypeHTML = 6, // the HTML file header specifies which HTML version
|
||||
TypeXML = 7, // the XML header must identify the DTD or schemas
|
||||
TypeUUID = 8, // also known as GUID; stored as 16 bytes in binary (valid as an ID)
|
||||
TypeISRC = 9, // stored as UTF-8 text (valid as an ID)
|
||||
TypeMI3P = 10, // stored as UTF-8 text (valid as an ID)
|
||||
TypeGIF = 12, // (deprecated) a GIF image
|
||||
TypeJPEG = 13, // a JPEG image
|
||||
TypePNG = 14, // a PNG image
|
||||
TypeURL = 15, // absolute, in UTF-8 characters
|
||||
TypeDuration = 16, // in milliseconds, 32-bit integer
|
||||
TypeDateTime = 17, // in UTC, counting seconds since midnight, January 1, 1904; 32 or 64-bits
|
||||
TypeGenred = 18, // a list of enumerated values
|
||||
TypeInteger = 21, // a signed big-endian integer with length one of { 1,2,3,4,8 } bytes
|
||||
TypeRIAAPA = 24, // RIAA parental advisory; { -1=no, 1=yes, 0=unspecified }, 8-bit ingteger
|
||||
TypeUPC = 25, // Universal Product Code, in text UTF-8 format (valid as an ID)
|
||||
TypeBMP = 27, // Windows bitmap image
|
||||
TypeUndefined = 255 // undefined
|
||||
};
|
||||
|
||||
struct AtomData {
|
||||
AtomData(AtomDataType type, ByteVector data) : type(type), locale(0), data(data) {}
|
||||
AtomDataType type;
|
||||
int locale;
|
||||
ByteVector data;
|
||||
};
|
||||
|
||||
typedef TagLib::List<AtomData> AtomDataList;
|
||||
|
||||
class Atom
|
||||
{
|
||||
public:
|
||||
Atom(File *file);
|
||||
~Atom();
|
||||
Atom *find(const char *name1, const char *name2 = 0, const char *name3 = 0, const char *name4 = 0);
|
||||
bool path(AtomList &path, const char *name1, const char *name2 = 0, const char *name3 = 0);
|
||||
AtomList findall(const char *name, bool recursive = false);
|
||||
long offset;
|
||||
long length;
|
||||
TagLib::ByteVector name;
|
||||
AtomList children;
|
||||
private:
|
||||
static const int numContainers = 11;
|
||||
static const char *containers[11];
|
||||
};
|
||||
|
||||
//! Root-level atoms
|
||||
class Atoms
|
||||
{
|
||||
public:
|
||||
Atoms(File *file);
|
||||
~Atoms();
|
||||
Atom *find(const char *name1, const char *name2 = 0, const char *name3 = 0, const char *name4 = 0);
|
||||
AtomList path(const char *name1, const char *name2 = 0, const char *name3 = 0, const char *name4 = 0);
|
||||
AtomList atoms;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,86 @@
|
|||
/**************************************************************************
|
||||
copyright : (C) 2009 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <taglib.h>
|
||||
#include <tdebug.h>
|
||||
#include "mp4coverart.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class MP4::CoverArt::CoverArtPrivate : public RefCounter
|
||||
{
|
||||
public:
|
||||
CoverArtPrivate() : RefCounter(), format(MP4::CoverArt::JPEG) {}
|
||||
|
||||
Format format;
|
||||
ByteVector data;
|
||||
};
|
||||
|
||||
MP4::CoverArt::CoverArt(Format format, const ByteVector &data)
|
||||
{
|
||||
d = new CoverArtPrivate;
|
||||
d->format = format;
|
||||
d->data = data;
|
||||
}
|
||||
|
||||
MP4::CoverArt::CoverArt(const CoverArt &item) : d(item.d)
|
||||
{
|
||||
d->ref();
|
||||
}
|
||||
|
||||
MP4::CoverArt &
|
||||
MP4::CoverArt::operator=(const CoverArt &item)
|
||||
{
|
||||
if(d->deref()) {
|
||||
delete d;
|
||||
}
|
||||
d = item.d;
|
||||
d->ref();
|
||||
return *this;
|
||||
}
|
||||
|
||||
MP4::CoverArt::~CoverArt()
|
||||
{
|
||||
if(d->deref()) {
|
||||
delete d;
|
||||
}
|
||||
}
|
||||
|
||||
MP4::CoverArt::Format
|
||||
MP4::CoverArt::format() const
|
||||
{
|
||||
return d->format;
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::CoverArt::data() const
|
||||
{
|
||||
return d->data;
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
/**************************************************************************
|
||||
copyright : (C) 2009 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_MP4COVERART_H
|
||||
#define TAGLIB_MP4COVERART_H
|
||||
|
||||
#include "tlist.h"
|
||||
#include "tbytevector.h"
|
||||
#include "taglib_export.h"
|
||||
#include "mp4atom.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace MP4 {
|
||||
|
||||
class TAGLIB_EXPORT CoverArt
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* This describes the image type.
|
||||
*/
|
||||
enum Format {
|
||||
JPEG = TypeJPEG,
|
||||
PNG = TypePNG,
|
||||
BMP = TypeBMP,
|
||||
GIF = TypeGIF
|
||||
};
|
||||
|
||||
CoverArt(Format format, const ByteVector &data);
|
||||
~CoverArt();
|
||||
|
||||
CoverArt(const CoverArt &item);
|
||||
CoverArt &operator=(const CoverArt &item);
|
||||
|
||||
//! Format of the image
|
||||
Format format() const;
|
||||
|
||||
//! The image data
|
||||
ByteVector data() const;
|
||||
|
||||
private:
|
||||
class CoverArtPrivate;
|
||||
CoverArtPrivate *d;
|
||||
};
|
||||
|
||||
typedef List<CoverArt> CoverArtList;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,149 @@
|
|||
/**************************************************************************
|
||||
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/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <tdebug.h>
|
||||
#include <tstring.h>
|
||||
#include "mp4atom.h"
|
||||
#include "mp4tag.h"
|
||||
#include "mp4file.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class MP4::File::FilePrivate
|
||||
{
|
||||
public:
|
||||
FilePrivate() : tag(0), atoms(0), properties(0)
|
||||
{
|
||||
}
|
||||
|
||||
~FilePrivate()
|
||||
{
|
||||
if(atoms) {
|
||||
delete atoms;
|
||||
atoms = 0;
|
||||
}
|
||||
if(tag) {
|
||||
delete tag;
|
||||
tag = 0;
|
||||
}
|
||||
if(properties) {
|
||||
delete properties;
|
||||
properties = 0;
|
||||
}
|
||||
}
|
||||
|
||||
MP4::Tag *tag;
|
||||
MP4::Atoms *atoms;
|
||||
MP4::Properties *properties;
|
||||
};
|
||||
|
||||
MP4::File::File(FileName file, bool readProperties, AudioProperties::ReadStyle audioPropertiesStyle)
|
||||
: TagLib::File(file)
|
||||
{
|
||||
d = new FilePrivate;
|
||||
read(readProperties, audioPropertiesStyle);
|
||||
}
|
||||
|
||||
MP4::File::File(IOStream *stream, bool readProperties, AudioProperties::ReadStyle audioPropertiesStyle)
|
||||
: TagLib::File(stream)
|
||||
{
|
||||
d = new FilePrivate;
|
||||
read(readProperties, audioPropertiesStyle);
|
||||
}
|
||||
|
||||
MP4::File::~File()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
MP4::Tag *
|
||||
MP4::File::tag() const
|
||||
{
|
||||
return d->tag;
|
||||
}
|
||||
|
||||
MP4::Properties *
|
||||
MP4::File::audioProperties() const
|
||||
{
|
||||
return d->properties;
|
||||
}
|
||||
|
||||
bool
|
||||
MP4::File::checkValid(const MP4::AtomList &list)
|
||||
{
|
||||
for(uint i = 0; i < list.size(); i++) {
|
||||
if(list[i]->length == 0)
|
||||
return false;
|
||||
if(!checkValid(list[i]->children))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
MP4::File::read(bool readProperties, Properties::ReadStyle audioPropertiesStyle)
|
||||
{
|
||||
if(!isValid())
|
||||
return;
|
||||
|
||||
d->atoms = new Atoms(this);
|
||||
if (!checkValid(d->atoms->atoms)) {
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// must have a moov atom, otherwise consider it invalid
|
||||
MP4::Atom *moov = d->atoms->find("moov");
|
||||
if(!moov) {
|
||||
setValid(false);
|
||||
return;
|
||||
}
|
||||
|
||||
d->tag = new Tag(this, d->atoms);
|
||||
if(readProperties) {
|
||||
d->properties = new Properties(this, d->atoms, audioPropertiesStyle);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
MP4::File::save()
|
||||
{
|
||||
if(readOnly()) {
|
||||
debug("MP4::File::save() -- File is read only.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!isValid()) {
|
||||
debug("MP4::File::save() -- Trying to save invalid file.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return d->tag->save();
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
/**************************************************************************
|
||||
copyright : (C) 2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_MP4FILE_H
|
||||
#define TAGLIB_MP4FILE_H
|
||||
|
||||
#include "tag.h"
|
||||
#include "tfile.h"
|
||||
#include "taglib_export.h"
|
||||
#include "mp4properties.h"
|
||||
#include "mp4tag.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
//! An implementation of MP4 (AAC, ALAC, ...) metadata
|
||||
namespace MP4 {
|
||||
|
||||
class Atoms;
|
||||
|
||||
/*!
|
||||
* This implements and provides an interface for MP4 files to the
|
||||
* TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing
|
||||
* the abstract TagLib::File API as well as providing some additional
|
||||
* information specific to MP4 files.
|
||||
*/
|
||||
class TAGLIB_EXPORT File : public TagLib::File
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* Contructs a MP4 file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*
|
||||
* \note In the current implementation, both \a readProperties and
|
||||
* \a propertiesStyle are ignored.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true, Properties::ReadStyle audioPropertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Contructs a MP4 file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*
|
||||
* \note In the current implementation, both \a readProperties and
|
||||
* \a propertiesStyle are ignored.
|
||||
*
|
||||
* \note TagLib will *not* take ownership of the stream, the caller is
|
||||
* responsible for deleting it after the File object.
|
||||
*/
|
||||
File(IOStream *stream, bool readProperties = true, Properties::ReadStyle audioPropertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
virtual ~File();
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the MP4 tag of the file.
|
||||
*
|
||||
* MP4::Tag implements the tag interface, so this serves as the
|
||||
* reimplementation of TagLib::File::tag().
|
||||
*
|
||||
* \note The Tag <b>is still</b> owned by the MP4::File and should not be
|
||||
* deleted by the user. It will be deleted when the file (object) is
|
||||
* destroyed.
|
||||
*/
|
||||
Tag *tag() const;
|
||||
|
||||
/*!
|
||||
* Returns the MP4 audio properties for this file.
|
||||
*/
|
||||
Properties *audioProperties() const;
|
||||
|
||||
/*!
|
||||
* Save the file.
|
||||
*
|
||||
* This returns true if the save was successful.
|
||||
*/
|
||||
bool save();
|
||||
|
||||
private:
|
||||
|
||||
void read(bool readProperties, Properties::ReadStyle audioPropertiesStyle);
|
||||
bool checkValid(const MP4::AtomList &list);
|
||||
|
||||
class FilePrivate;
|
||||
FilePrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,209 @@
|
|||
/**************************************************************************
|
||||
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/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <taglib.h>
|
||||
#include <tdebug.h>
|
||||
#include "mp4item.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class MP4::Item::ItemPrivate : public RefCounter
|
||||
{
|
||||
public:
|
||||
ItemPrivate() : RefCounter(), valid(true), atomDataType(TypeUndefined) {}
|
||||
|
||||
bool valid;
|
||||
AtomDataType atomDataType;
|
||||
union {
|
||||
bool m_bool;
|
||||
int m_int;
|
||||
IntPair m_intPair;
|
||||
uchar m_byte;
|
||||
uint m_uint;
|
||||
long long m_longlong;
|
||||
};
|
||||
StringList m_stringList;
|
||||
ByteVectorList m_byteVectorList;
|
||||
MP4::CoverArtList m_coverArtList;
|
||||
};
|
||||
|
||||
MP4::Item::Item()
|
||||
{
|
||||
d = new ItemPrivate;
|
||||
d->valid = false;
|
||||
}
|
||||
|
||||
MP4::Item::Item(const Item &item) : d(item.d)
|
||||
{
|
||||
d->ref();
|
||||
}
|
||||
|
||||
MP4::Item &
|
||||
MP4::Item::operator=(const Item &item)
|
||||
{
|
||||
if(d->deref()) {
|
||||
delete d;
|
||||
}
|
||||
d = item.d;
|
||||
d->ref();
|
||||
return *this;
|
||||
}
|
||||
|
||||
MP4::Item::~Item()
|
||||
{
|
||||
if(d->deref()) {
|
||||
delete d;
|
||||
}
|
||||
}
|
||||
|
||||
MP4::Item::Item(bool value)
|
||||
{
|
||||
d = new ItemPrivate;
|
||||
d->m_bool = value;
|
||||
}
|
||||
|
||||
MP4::Item::Item(int value)
|
||||
{
|
||||
d = new ItemPrivate;
|
||||
d->m_int = value;
|
||||
}
|
||||
|
||||
MP4::Item::Item(uchar value)
|
||||
{
|
||||
d = new ItemPrivate;
|
||||
d->m_byte = value;
|
||||
}
|
||||
|
||||
MP4::Item::Item(uint value)
|
||||
{
|
||||
d = new ItemPrivate;
|
||||
d->m_uint = value;
|
||||
}
|
||||
|
||||
MP4::Item::Item(long long value)
|
||||
{
|
||||
d = new ItemPrivate;
|
||||
d->m_longlong = value;
|
||||
}
|
||||
|
||||
MP4::Item::Item(int value1, int value2)
|
||||
{
|
||||
d = new ItemPrivate;
|
||||
d->m_intPair.first = value1;
|
||||
d->m_intPair.second = value2;
|
||||
}
|
||||
|
||||
MP4::Item::Item(const ByteVectorList &value)
|
||||
{
|
||||
d = new ItemPrivate;
|
||||
d->m_byteVectorList = value;
|
||||
}
|
||||
|
||||
MP4::Item::Item(const StringList &value)
|
||||
{
|
||||
d = new ItemPrivate;
|
||||
d->m_stringList = value;
|
||||
}
|
||||
|
||||
MP4::Item::Item(const MP4::CoverArtList &value)
|
||||
{
|
||||
d = new ItemPrivate;
|
||||
d->m_coverArtList = value;
|
||||
}
|
||||
|
||||
void MP4::Item::setAtomDataType(MP4::AtomDataType type)
|
||||
{
|
||||
d->atomDataType = type;
|
||||
}
|
||||
|
||||
MP4::AtomDataType MP4::Item::atomDataType() const
|
||||
{
|
||||
return d->atomDataType;
|
||||
}
|
||||
|
||||
bool
|
||||
MP4::Item::toBool() const
|
||||
{
|
||||
return d->m_bool;
|
||||
}
|
||||
|
||||
int
|
||||
MP4::Item::toInt() const
|
||||
{
|
||||
return d->m_int;
|
||||
}
|
||||
|
||||
uchar
|
||||
MP4::Item::toByte() const
|
||||
{
|
||||
return d->m_byte;
|
||||
}
|
||||
|
||||
TagLib::uint
|
||||
MP4::Item::toUInt() const
|
||||
{
|
||||
return d->m_uint;
|
||||
}
|
||||
|
||||
long long
|
||||
MP4::Item::toLongLong() const
|
||||
{
|
||||
return d->m_longlong;
|
||||
}
|
||||
|
||||
MP4::Item::IntPair
|
||||
MP4::Item::toIntPair() const
|
||||
{
|
||||
return d->m_intPair;
|
||||
}
|
||||
|
||||
StringList
|
||||
MP4::Item::toStringList() const
|
||||
{
|
||||
return d->m_stringList;
|
||||
}
|
||||
|
||||
ByteVectorList
|
||||
MP4::Item::toByteVectorList() const
|
||||
{
|
||||
return d->m_byteVectorList;
|
||||
}
|
||||
|
||||
MP4::CoverArtList
|
||||
MP4::Item::toCoverArtList() const
|
||||
{
|
||||
return d->m_coverArtList;
|
||||
}
|
||||
|
||||
bool
|
||||
MP4::Item::isValid() const
|
||||
{
|
||||
return d->valid;
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/**************************************************************************
|
||||
copyright : (C) 2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_MP4ITEM_H
|
||||
#define TAGLIB_MP4ITEM_H
|
||||
|
||||
#include "tstringlist.h"
|
||||
#include "mp4coverart.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace MP4 {
|
||||
|
||||
class TAGLIB_EXPORT Item
|
||||
{
|
||||
public:
|
||||
struct IntPair {
|
||||
int first, second;
|
||||
};
|
||||
|
||||
Item();
|
||||
Item(const Item &item);
|
||||
Item &operator=(const Item &item);
|
||||
~Item();
|
||||
|
||||
Item(int value);
|
||||
Item(uchar value);
|
||||
Item(uint value);
|
||||
Item(long long value);
|
||||
Item(bool value);
|
||||
Item(int first, int second);
|
||||
Item(const StringList &value);
|
||||
Item(const ByteVectorList &value);
|
||||
Item(const CoverArtList &value);
|
||||
|
||||
void setAtomDataType(AtomDataType type);
|
||||
AtomDataType atomDataType() const;
|
||||
|
||||
int toInt() const;
|
||||
uchar toByte() const;
|
||||
uint toUInt() const;
|
||||
long long toLongLong() const;
|
||||
bool toBool() const;
|
||||
IntPair toIntPair() const;
|
||||
StringList toStringList() const;
|
||||
ByteVectorList toByteVectorList() const;
|
||||
CoverArtList toCoverArtList() const;
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
private:
|
||||
class ItemPrivate;
|
||||
ItemPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,195 @@
|
|||
/**************************************************************************
|
||||
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/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <tdebug.h>
|
||||
#include <tstring.h>
|
||||
#include "mp4file.h"
|
||||
#include "mp4atom.h"
|
||||
#include "mp4properties.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class MP4::Properties::PropertiesPrivate
|
||||
{
|
||||
public:
|
||||
PropertiesPrivate() : length(0), bitrate(0), sampleRate(0), channels(0), bitsPerSample(0), encrypted(false) {}
|
||||
|
||||
int length;
|
||||
int bitrate;
|
||||
int sampleRate;
|
||||
int channels;
|
||||
int bitsPerSample;
|
||||
bool encrypted;
|
||||
};
|
||||
|
||||
MP4::Properties::Properties(File *file, MP4::Atoms *atoms, ReadStyle style)
|
||||
: AudioProperties(style)
|
||||
{
|
||||
d = new PropertiesPrivate;
|
||||
|
||||
MP4::Atom *moov = atoms->find("moov");
|
||||
if(!moov) {
|
||||
debug("MP4: Atom 'moov' not found");
|
||||
return;
|
||||
}
|
||||
|
||||
MP4::Atom *trak = 0;
|
||||
ByteVector data;
|
||||
|
||||
MP4::AtomList trakList = moov->findall("trak");
|
||||
for (unsigned int i = 0; i < trakList.size(); i++) {
|
||||
trak = trakList[i];
|
||||
MP4::Atom *hdlr = trak->find("mdia", "hdlr");
|
||||
if(!hdlr) {
|
||||
debug("MP4: Atom 'trak.mdia.hdlr' not found");
|
||||
return;
|
||||
}
|
||||
file->seek(hdlr->offset);
|
||||
data = file->readBlock(hdlr->length);
|
||||
if(data.mid(16, 4) == "soun") {
|
||||
break;
|
||||
}
|
||||
trak = 0;
|
||||
}
|
||||
if (!trak) {
|
||||
debug("MP4: No audio tracks");
|
||||
return;
|
||||
}
|
||||
|
||||
MP4::Atom *mdhd = trak->find("mdia", "mdhd");
|
||||
if(!mdhd) {
|
||||
debug("MP4: Atom 'trak.mdia.mdhd' not found");
|
||||
return;
|
||||
}
|
||||
|
||||
file->seek(mdhd->offset);
|
||||
data = file->readBlock(mdhd->length);
|
||||
uint version = data[8];
|
||||
if(version == 1) {
|
||||
if (data.size() < 36 + 8) {
|
||||
debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected");
|
||||
return;
|
||||
}
|
||||
long long unit = data.mid(28, 8).toLongLong();
|
||||
long long length = data.mid(36, 8).toLongLong();
|
||||
d->length = unit ? int(length / unit) : 0;
|
||||
}
|
||||
else {
|
||||
if (data.size() < 24 + 4) {
|
||||
debug("MP4: Atom 'trak.mdia.mdhd' is smaller than expected");
|
||||
return;
|
||||
}
|
||||
unsigned int unit = data.mid(20, 4).toUInt();
|
||||
unsigned int length = data.mid(24, 4).toUInt();
|
||||
d->length = unit ? length / unit : 0;
|
||||
}
|
||||
|
||||
MP4::Atom *atom = trak->find("mdia", "minf", "stbl", "stsd");
|
||||
if(!atom) {
|
||||
return;
|
||||
}
|
||||
|
||||
file->seek(atom->offset);
|
||||
data = file->readBlock(atom->length);
|
||||
if(data.mid(20, 4) == "mp4a") {
|
||||
d->channels = data.mid(40, 2).toShort();
|
||||
d->bitsPerSample = data.mid(42, 2).toShort();
|
||||
d->sampleRate = data.mid(46, 4).toUInt();
|
||||
if(data.mid(56, 4) == "esds" && data[64] == 0x03) {
|
||||
long pos = 65;
|
||||
if(data.mid(pos, 3) == "\x80\x80\x80") {
|
||||
pos += 3;
|
||||
}
|
||||
pos += 4;
|
||||
if(data[pos] == 0x04) {
|
||||
pos += 1;
|
||||
if(data.mid(pos, 3) == "\x80\x80\x80") {
|
||||
pos += 3;
|
||||
}
|
||||
pos += 10;
|
||||
d->bitrate = (data.mid(pos, 4).toUInt() + 500) / 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (data.mid(20, 4) == "alac") {
|
||||
if (atom->length == 88 && data.mid(56, 4) == "alac") {
|
||||
d->bitsPerSample = data.at(69);
|
||||
d->channels = data.at(73);
|
||||
d->bitrate = data.mid(80, 4).toUInt() / 1000;
|
||||
d->sampleRate = data.mid(84, 4).toUInt();
|
||||
}
|
||||
}
|
||||
|
||||
MP4::Atom *drms = atom->find("drms");
|
||||
if(drms) {
|
||||
d->encrypted = true;
|
||||
}
|
||||
}
|
||||
|
||||
MP4::Properties::~Properties()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
int
|
||||
MP4::Properties::channels() const
|
||||
{
|
||||
return d->channels;
|
||||
}
|
||||
|
||||
int
|
||||
MP4::Properties::sampleRate() const
|
||||
{
|
||||
return d->sampleRate;
|
||||
}
|
||||
|
||||
int
|
||||
MP4::Properties::length() const
|
||||
{
|
||||
return d->length;
|
||||
}
|
||||
|
||||
int
|
||||
MP4::Properties::bitrate() const
|
||||
{
|
||||
return d->bitrate;
|
||||
}
|
||||
|
||||
int
|
||||
MP4::Properties::bitsPerSample() const
|
||||
{
|
||||
return d->bitsPerSample;
|
||||
}
|
||||
|
||||
bool
|
||||
MP4::Properties::isEncrypted() const
|
||||
{
|
||||
return d->encrypted;
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/**************************************************************************
|
||||
copyright : (C) 2007 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_MP4PROPERTIES_H
|
||||
#define TAGLIB_MP4PROPERTIES_H
|
||||
|
||||
#include "taglib_export.h"
|
||||
#include "audioproperties.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace MP4 {
|
||||
|
||||
class Atoms;
|
||||
class File;
|
||||
|
||||
//! An implementation of MP4 audio properties
|
||||
class TAGLIB_EXPORT Properties : public AudioProperties
|
||||
{
|
||||
public:
|
||||
Properties(File *file, Atoms *atoms, ReadStyle style = Average);
|
||||
virtual ~Properties();
|
||||
|
||||
virtual int length() const;
|
||||
virtual int bitrate() const;
|
||||
virtual int sampleRate() const;
|
||||
virtual int channels() const;
|
||||
virtual int bitsPerSample() const;
|
||||
bool isEncrypted() const;
|
||||
|
||||
private:
|
||||
class PropertiesPrivate;
|
||||
PropertiesPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,758 @@
|
|||
/**************************************************************************
|
||||
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/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <tdebug.h>
|
||||
#include <tstring.h>
|
||||
#include "mp4atom.h"
|
||||
#include "mp4tag.h"
|
||||
#include "id3v1genres.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class MP4::Tag::TagPrivate
|
||||
{
|
||||
public:
|
||||
TagPrivate() : file(0), atoms(0) {}
|
||||
~TagPrivate() {}
|
||||
TagLib::File *file;
|
||||
Atoms *atoms;
|
||||
ItemListMap items;
|
||||
};
|
||||
|
||||
MP4::Tag::Tag()
|
||||
{
|
||||
d = new TagPrivate;
|
||||
}
|
||||
|
||||
MP4::Tag::Tag(TagLib::File *file, MP4::Atoms *atoms)
|
||||
{
|
||||
d = new TagPrivate;
|
||||
d->file = file;
|
||||
d->atoms = atoms;
|
||||
|
||||
MP4::Atom *ilst = atoms->find("moov", "udta", "meta", "ilst");
|
||||
if(!ilst) {
|
||||
//debug("Atom moov.udta.meta.ilst not found.");
|
||||
return;
|
||||
}
|
||||
|
||||
for(unsigned int i = 0; i < ilst->children.size(); i++) {
|
||||
MP4::Atom *atom = ilst->children[i];
|
||||
file->seek(atom->offset + 8);
|
||||
if(atom->name == "----") {
|
||||
parseFreeForm(atom, file);
|
||||
}
|
||||
else if(atom->name == "trkn" || atom->name == "disk") {
|
||||
parseIntPair(atom, file);
|
||||
}
|
||||
else if(atom->name == "cpil" || atom->name == "pgap" || atom->name == "pcst" ||
|
||||
atom->name == "hdvd") {
|
||||
parseBool(atom, file);
|
||||
}
|
||||
else if(atom->name == "tmpo") {
|
||||
parseInt(atom, file);
|
||||
}
|
||||
else if(atom->name == "tvsn" || atom->name == "tves" || atom->name == "cnID" ||
|
||||
atom->name == "sfID" || atom->name == "atID" || atom->name == "geID") {
|
||||
parseUInt(atom, file);
|
||||
}
|
||||
else if(atom->name == "plID") {
|
||||
parseLongLong(atom, file);
|
||||
}
|
||||
else if(atom->name == "stik" || atom->name == "rtng" || atom->name == "akID") {
|
||||
parseByte(atom, file);
|
||||
}
|
||||
else if(atom->name == "gnre") {
|
||||
parseGnre(atom, file);
|
||||
}
|
||||
else if(atom->name == "covr") {
|
||||
parseCovr(atom, file);
|
||||
}
|
||||
else {
|
||||
parseText(atom, file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MP4::Tag::~Tag()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
MP4::AtomDataList
|
||||
MP4::Tag::parseData2(MP4::Atom *atom, TagLib::File *file, int expectedFlags, bool freeForm)
|
||||
{
|
||||
AtomDataList result;
|
||||
ByteVector data = file->readBlock(atom->length - 8);
|
||||
int i = 0;
|
||||
unsigned int pos = 0;
|
||||
while(pos < data.size()) {
|
||||
int length = data.mid(pos, 4).toUInt();
|
||||
ByteVector name = data.mid(pos + 4, 4);
|
||||
int flags = data.mid(pos + 8, 4).toUInt();
|
||||
if(freeForm && i < 2) {
|
||||
if(i == 0 && name != "mean") {
|
||||
debug("MP4: Unexpected atom \"" + name + "\", expecting \"mean\"");
|
||||
return result;
|
||||
}
|
||||
else if(i == 1 && name != "name") {
|
||||
debug("MP4: Unexpected atom \"" + name + "\", expecting \"name\"");
|
||||
return result;
|
||||
}
|
||||
result.append(AtomData(AtomDataType(flags), data.mid(pos + 12, length - 12)));
|
||||
}
|
||||
else {
|
||||
if(name != "data") {
|
||||
debug("MP4: Unexpected atom \"" + name + "\", expecting \"data\"");
|
||||
return result;
|
||||
}
|
||||
if(expectedFlags == -1 || flags == expectedFlags) {
|
||||
result.append(AtomData(AtomDataType(flags), data.mid(pos + 16, length - 16)));
|
||||
}
|
||||
}
|
||||
pos += length;
|
||||
i++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ByteVectorList
|
||||
MP4::Tag::parseData(MP4::Atom *atom, TagLib::File *file, int expectedFlags, bool freeForm)
|
||||
{
|
||||
AtomDataList data = parseData2(atom, file, expectedFlags, freeForm);
|
||||
ByteVectorList result;
|
||||
for(uint i = 0; i < data.size(); i++) {
|
||||
result.append(data[i].data);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::parseInt(MP4::Atom *atom, TagLib::File *file)
|
||||
{
|
||||
ByteVectorList data = parseData(atom, file);
|
||||
if(data.size()) {
|
||||
d->items.insert(atom->name, (int)data[0].toShort());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::parseUInt(MP4::Atom *atom, TagLib::File *file)
|
||||
{
|
||||
ByteVectorList data = parseData(atom, file);
|
||||
if(data.size()) {
|
||||
d->items.insert(atom->name, data[0].toUInt());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::parseLongLong(MP4::Atom *atom, TagLib::File *file)
|
||||
{
|
||||
ByteVectorList data = parseData(atom, file);
|
||||
if(data.size()) {
|
||||
d->items.insert(atom->name, data[0].toLongLong());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::parseByte(MP4::Atom *atom, TagLib::File *file)
|
||||
{
|
||||
ByteVectorList data = parseData(atom, file);
|
||||
if(data.size()) {
|
||||
d->items.insert(atom->name, (uchar)data[0].at(0));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::parseGnre(MP4::Atom *atom, TagLib::File *file)
|
||||
{
|
||||
ByteVectorList data = parseData(atom, file);
|
||||
if(data.size()) {
|
||||
int idx = (int)data[0].toShort();
|
||||
if(!d->items.contains("\251gen") && idx > 0) {
|
||||
d->items.insert("\251gen", StringList(ID3v1::genre(idx - 1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::parseIntPair(MP4::Atom *atom, TagLib::File *file)
|
||||
{
|
||||
ByteVectorList data = parseData(atom, file);
|
||||
if(data.size()) {
|
||||
int a = data[0].mid(2, 2).toShort();
|
||||
int b = data[0].mid(4, 2).toShort();
|
||||
d->items.insert(atom->name, MP4::Item(a, b));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::parseBool(MP4::Atom *atom, TagLib::File *file)
|
||||
{
|
||||
ByteVectorList data = parseData(atom, file);
|
||||
if(data.size()) {
|
||||
bool value = data[0].size() ? data[0][0] != '\0' : false;
|
||||
d->items.insert(atom->name, value);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::parseText(MP4::Atom *atom, TagLib::File *file, int expectedFlags)
|
||||
{
|
||||
ByteVectorList data = parseData(atom, file, expectedFlags);
|
||||
if(data.size()) {
|
||||
StringList value;
|
||||
for(unsigned int i = 0; i < data.size(); i++) {
|
||||
value.append(String(data[i], String::UTF8));
|
||||
}
|
||||
d->items.insert(atom->name, value);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::parseFreeForm(MP4::Atom *atom, TagLib::File *file)
|
||||
{
|
||||
AtomDataList data = parseData2(atom, file, -1, true);
|
||||
if(data.size() > 2) {
|
||||
String name = "----:" + String(data[0].data, String::UTF8) + ':' + String(data[1].data, String::UTF8);
|
||||
AtomDataType type = data[2].type;
|
||||
for(uint i = 2; i < data.size(); i++) {
|
||||
if(data[i].type != type) {
|
||||
debug("MP4: We currently don't support values with multiple types");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(type == TypeUTF8) {
|
||||
StringList value;
|
||||
for(uint i = 2; i < data.size(); i++) {
|
||||
value.append(String(data[i].data, String::UTF8));
|
||||
}
|
||||
Item item(value);
|
||||
item.setAtomDataType(type);
|
||||
d->items.insert(name, item);
|
||||
}
|
||||
else {
|
||||
ByteVectorList value;
|
||||
for(uint i = 2; i < data.size(); i++) {
|
||||
value.append(data[i].data);
|
||||
}
|
||||
Item item(value);
|
||||
item.setAtomDataType(type);
|
||||
d->items.insert(name, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::parseCovr(MP4::Atom *atom, TagLib::File *file)
|
||||
{
|
||||
MP4::CoverArtList value;
|
||||
ByteVector data = file->readBlock(atom->length - 8);
|
||||
unsigned int pos = 0;
|
||||
while(pos < data.size()) {
|
||||
int length = data.mid(pos, 4).toUInt();
|
||||
ByteVector name = data.mid(pos + 4, 4);
|
||||
int flags = data.mid(pos + 8, 4).toUInt();
|
||||
if(name != "data") {
|
||||
debug("MP4: Unexpected atom \"" + name + "\", expecting \"data\"");
|
||||
break;
|
||||
}
|
||||
if(flags == TypeJPEG || flags == TypePNG || flags == TypeBMP || flags == TypeGIF) {
|
||||
value.append(MP4::CoverArt(MP4::CoverArt::Format(flags),
|
||||
data.mid(pos + 16, length - 16)));
|
||||
}
|
||||
pos += length;
|
||||
}
|
||||
if(value.size() > 0)
|
||||
d->items.insert(atom->name, value);
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::padIlst(const ByteVector &data, int length)
|
||||
{
|
||||
if (length == -1) {
|
||||
length = ((data.size() + 1023) & ~1023) - data.size();
|
||||
}
|
||||
return renderAtom("free", ByteVector(length, '\1'));
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderAtom(const ByteVector &name, const ByteVector &data)
|
||||
{
|
||||
return ByteVector::fromUInt(data.size() + 8) + name + data;
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderData(const ByteVector &name, int flags, const ByteVectorList &data)
|
||||
{
|
||||
ByteVector result;
|
||||
for(unsigned int i = 0; i < data.size(); i++) {
|
||||
result.append(renderAtom("data", ByteVector::fromUInt(flags) + ByteVector(4, '\0') + data[i]));
|
||||
}
|
||||
return renderAtom(name, result);
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderBool(const ByteVector &name, MP4::Item &item)
|
||||
{
|
||||
ByteVectorList data;
|
||||
data.append(ByteVector(1, item.toBool() ? '\1' : '\0'));
|
||||
return renderData(name, TypeInteger, data);
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderInt(const ByteVector &name, MP4::Item &item)
|
||||
{
|
||||
ByteVectorList data;
|
||||
data.append(ByteVector::fromShort(item.toInt()));
|
||||
return renderData(name, TypeInteger, data);
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderUInt(const ByteVector &name, MP4::Item &item)
|
||||
{
|
||||
ByteVectorList data;
|
||||
data.append(ByteVector::fromUInt(item.toUInt()));
|
||||
return renderData(name, TypeInteger, data);
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderLongLong(const ByteVector &name, MP4::Item &item)
|
||||
{
|
||||
ByteVectorList data;
|
||||
data.append(ByteVector::fromLongLong(item.toLongLong()));
|
||||
return renderData(name, TypeInteger, data);
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderByte(const ByteVector &name, MP4::Item &item)
|
||||
{
|
||||
ByteVectorList data;
|
||||
data.append(ByteVector(1, item.toByte()));
|
||||
return renderData(name, TypeInteger, data);
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderIntPair(const ByteVector &name, MP4::Item &item)
|
||||
{
|
||||
ByteVectorList data;
|
||||
data.append(ByteVector(2, '\0') +
|
||||
ByteVector::fromShort(item.toIntPair().first) +
|
||||
ByteVector::fromShort(item.toIntPair().second) +
|
||||
ByteVector(2, '\0'));
|
||||
return renderData(name, TypeImplicit, data);
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderIntPairNoTrailing(const ByteVector &name, MP4::Item &item)
|
||||
{
|
||||
ByteVectorList data;
|
||||
data.append(ByteVector(2, '\0') +
|
||||
ByteVector::fromShort(item.toIntPair().first) +
|
||||
ByteVector::fromShort(item.toIntPair().second));
|
||||
return renderData(name, TypeImplicit, data);
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderText(const ByteVector &name, MP4::Item &item, int flags)
|
||||
{
|
||||
ByteVectorList data;
|
||||
StringList value = item.toStringList();
|
||||
for(unsigned int i = 0; i < value.size(); i++) {
|
||||
data.append(value[i].data(String::UTF8));
|
||||
}
|
||||
return renderData(name, flags, data);
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderCovr(const ByteVector &name, MP4::Item &item)
|
||||
{
|
||||
ByteVector data;
|
||||
MP4::CoverArtList value = item.toCoverArtList();
|
||||
for(unsigned int i = 0; i < value.size(); i++) {
|
||||
data.append(renderAtom("data", ByteVector::fromUInt(value[i].format()) +
|
||||
ByteVector(4, '\0') + value[i].data()));
|
||||
}
|
||||
return renderAtom(name, data);
|
||||
}
|
||||
|
||||
ByteVector
|
||||
MP4::Tag::renderFreeForm(const String &name, MP4::Item &item)
|
||||
{
|
||||
StringList header = StringList::split(name, ":");
|
||||
if (header.size() != 3) {
|
||||
debug("MP4: Invalid free-form item name \"" + name + "\"");
|
||||
return ByteVector::null;
|
||||
}
|
||||
ByteVector data;
|
||||
data.append(renderAtom("mean", ByteVector::fromUInt(0) + header[1].data(String::UTF8)));
|
||||
data.append(renderAtom("name", ByteVector::fromUInt(0) + header[2].data(String::UTF8)));
|
||||
AtomDataType type = item.atomDataType();
|
||||
if(type == TypeUndefined) {
|
||||
if(!item.toStringList().isEmpty()) {
|
||||
type = TypeUTF8;
|
||||
}
|
||||
else {
|
||||
type = TypeImplicit;
|
||||
}
|
||||
}
|
||||
if(type == TypeUTF8) {
|
||||
StringList value = item.toStringList();
|
||||
for(unsigned int i = 0; i < value.size(); i++) {
|
||||
data.append(renderAtom("data", ByteVector::fromUInt(type) + ByteVector(4, '\0') + value[i].data(String::UTF8)));
|
||||
}
|
||||
}
|
||||
else {
|
||||
ByteVectorList value = item.toByteVectorList();
|
||||
for(unsigned int i = 0; i < value.size(); i++) {
|
||||
data.append(renderAtom("data", ByteVector::fromUInt(type) + ByteVector(4, '\0') + value[i]));
|
||||
}
|
||||
}
|
||||
return renderAtom("----", data);
|
||||
}
|
||||
|
||||
bool
|
||||
MP4::Tag::save()
|
||||
{
|
||||
ByteVector data;
|
||||
for(MP4::ItemListMap::Iterator i = d->items.begin(); i != d->items.end(); i++) {
|
||||
const String name = i->first;
|
||||
if(name.startsWith("----")) {
|
||||
data.append(renderFreeForm(name, i->second));
|
||||
}
|
||||
else if(name == "trkn") {
|
||||
data.append(renderIntPair(name.data(String::Latin1), i->second));
|
||||
}
|
||||
else if(name == "disk") {
|
||||
data.append(renderIntPairNoTrailing(name.data(String::Latin1), i->second));
|
||||
}
|
||||
else if(name == "cpil" || name == "pgap" || name == "pcst" || name == "hdvd") {
|
||||
data.append(renderBool(name.data(String::Latin1), i->second));
|
||||
}
|
||||
else if(name == "tmpo") {
|
||||
data.append(renderInt(name.data(String::Latin1), i->second));
|
||||
}
|
||||
else if(name == "tvsn" || name == "tves" || name == "cnID" ||
|
||||
name == "sfID" || name == "atID" || name == "geID") {
|
||||
data.append(renderUInt(name.data(String::Latin1), i->second));
|
||||
}
|
||||
else if(name == "plID") {
|
||||
data.append(renderLongLong(name.data(String::Latin1), i->second));
|
||||
}
|
||||
else if(name == "stik" || name == "rtng" || name == "akID") {
|
||||
data.append(renderByte(name.data(String::Latin1), i->second));
|
||||
}
|
||||
else if(name == "covr") {
|
||||
data.append(renderCovr(name.data(String::Latin1), i->second));
|
||||
}
|
||||
else if(name.size() == 4){
|
||||
data.append(renderText(name.data(String::Latin1), i->second));
|
||||
}
|
||||
else {
|
||||
debug("MP4: Unknown item name \"" + name + "\"");
|
||||
}
|
||||
}
|
||||
data = renderAtom("ilst", data);
|
||||
|
||||
AtomList path = d->atoms->path("moov", "udta", "meta", "ilst");
|
||||
if(path.size() == 4) {
|
||||
saveExisting(data, path);
|
||||
}
|
||||
else {
|
||||
saveNew(data);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::updateParents(AtomList &path, long delta, int ignore)
|
||||
{
|
||||
for(unsigned int i = 0; i < path.size() - ignore; i++) {
|
||||
d->file->seek(path[i]->offset);
|
||||
long size = d->file->readBlock(4).toUInt();
|
||||
// 64-bit
|
||||
if (size == 1) {
|
||||
d->file->seek(4, File::Current); // Skip name
|
||||
long long longSize = d->file->readBlock(8).toLongLong();
|
||||
// Seek the offset of the 64-bit size
|
||||
d->file->seek(path[i]->offset + 8);
|
||||
d->file->writeBlock(ByteVector::fromLongLong(longSize + delta));
|
||||
}
|
||||
// 32-bit
|
||||
else {
|
||||
d->file->seek(path[i]->offset);
|
||||
d->file->writeBlock(ByteVector::fromUInt(size + delta));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::updateOffsets(long delta, long offset)
|
||||
{
|
||||
MP4::Atom *moov = d->atoms->find("moov");
|
||||
if(moov) {
|
||||
MP4::AtomList stco = moov->findall("stco", true);
|
||||
for(unsigned int i = 0; i < stco.size(); i++) {
|
||||
MP4::Atom *atom = stco[i];
|
||||
if(atom->offset > offset) {
|
||||
atom->offset += delta;
|
||||
}
|
||||
d->file->seek(atom->offset + 12);
|
||||
ByteVector data = d->file->readBlock(atom->length - 12);
|
||||
unsigned int count = data.mid(0, 4).toUInt();
|
||||
d->file->seek(atom->offset + 16);
|
||||
int pos = 4;
|
||||
while(count--) {
|
||||
long o = data.mid(pos, 4).toUInt();
|
||||
if(o > offset) {
|
||||
o += delta;
|
||||
}
|
||||
d->file->writeBlock(ByteVector::fromUInt(o));
|
||||
pos += 4;
|
||||
}
|
||||
}
|
||||
|
||||
MP4::AtomList co64 = moov->findall("co64", true);
|
||||
for(unsigned int i = 0; i < co64.size(); i++) {
|
||||
MP4::Atom *atom = co64[i];
|
||||
if(atom->offset > offset) {
|
||||
atom->offset += delta;
|
||||
}
|
||||
d->file->seek(atom->offset + 12);
|
||||
ByteVector data = d->file->readBlock(atom->length - 12);
|
||||
unsigned int count = data.mid(0, 4).toUInt();
|
||||
d->file->seek(atom->offset + 16);
|
||||
int pos = 4;
|
||||
while(count--) {
|
||||
long long o = data.mid(pos, 8).toLongLong();
|
||||
if(o > offset) {
|
||||
o += delta;
|
||||
}
|
||||
d->file->writeBlock(ByteVector::fromLongLong(o));
|
||||
pos += 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MP4::Atom *moof = d->atoms->find("moof");
|
||||
if(moof) {
|
||||
MP4::AtomList tfhd = moof->findall("tfhd", true);
|
||||
for(unsigned int i = 0; i < tfhd.size(); i++) {
|
||||
MP4::Atom *atom = tfhd[i];
|
||||
if(atom->offset > offset) {
|
||||
atom->offset += delta;
|
||||
}
|
||||
d->file->seek(atom->offset + 9);
|
||||
ByteVector data = d->file->readBlock(atom->offset - 9);
|
||||
unsigned int flags = (ByteVector(1, '\0') + data.mid(0, 3)).toUInt();
|
||||
if(flags & 1) {
|
||||
long long o = data.mid(7, 8).toLongLong();
|
||||
if(o > offset) {
|
||||
o += delta;
|
||||
}
|
||||
d->file->seek(atom->offset + 16);
|
||||
d->file->writeBlock(ByteVector::fromLongLong(o));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::saveNew(ByteVector &data)
|
||||
{
|
||||
data = renderAtom("meta", TagLib::ByteVector(4, '\0') +
|
||||
renderAtom("hdlr", TagLib::ByteVector(8, '\0') + TagLib::ByteVector("mdirappl") + TagLib::ByteVector(9, '\0')) +
|
||||
data + padIlst(data));
|
||||
|
||||
AtomList path = d->atoms->path("moov", "udta");
|
||||
if(path.size() != 2) {
|
||||
path = d->atoms->path("moov");
|
||||
data = renderAtom("udta", data);
|
||||
}
|
||||
|
||||
long offset = path[path.size() - 1]->offset + 8;
|
||||
d->file->insert(data, offset, 0);
|
||||
|
||||
updateParents(path, data.size());
|
||||
updateOffsets(data.size(), offset);
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::saveExisting(ByteVector &data, AtomList &path)
|
||||
{
|
||||
MP4::Atom *ilst = path[path.size() - 1];
|
||||
long offset = ilst->offset;
|
||||
long length = ilst->length;
|
||||
|
||||
MP4::Atom *meta = path[path.size() - 2];
|
||||
AtomList::Iterator index = meta->children.find(ilst);
|
||||
|
||||
// check if there is an atom before 'ilst', and possibly use it as padding
|
||||
if(index != meta->children.begin()) {
|
||||
AtomList::Iterator prevIndex = index;
|
||||
prevIndex--;
|
||||
MP4::Atom *prev = *prevIndex;
|
||||
if(prev->name == "free") {
|
||||
offset = prev->offset;
|
||||
length += prev->length;
|
||||
}
|
||||
}
|
||||
// check if there is an atom after 'ilst', and possibly use it as padding
|
||||
AtomList::Iterator nextIndex = index;
|
||||
nextIndex++;
|
||||
if(nextIndex != meta->children.end()) {
|
||||
MP4::Atom *next = *nextIndex;
|
||||
if(next->name == "free") {
|
||||
length += next->length;
|
||||
}
|
||||
}
|
||||
|
||||
long delta = data.size() - length;
|
||||
if(delta > 0 || (delta < 0 && delta > -8)) {
|
||||
data.append(padIlst(data));
|
||||
delta = data.size() - length;
|
||||
}
|
||||
else if(delta < 0) {
|
||||
data.append(padIlst(data, -delta - 8));
|
||||
delta = 0;
|
||||
}
|
||||
|
||||
d->file->insert(data, offset, length);
|
||||
|
||||
if(delta) {
|
||||
updateParents(path, delta, 1);
|
||||
updateOffsets(delta, offset);
|
||||
}
|
||||
}
|
||||
|
||||
String
|
||||
MP4::Tag::title() const
|
||||
{
|
||||
if(d->items.contains("\251nam"))
|
||||
return d->items["\251nam"].toStringList().toString(", ");
|
||||
return String::null;
|
||||
}
|
||||
|
||||
String
|
||||
MP4::Tag::artist() const
|
||||
{
|
||||
if(d->items.contains("\251ART"))
|
||||
return d->items["\251ART"].toStringList().toString(", ");
|
||||
return String::null;
|
||||
}
|
||||
|
||||
String
|
||||
MP4::Tag::album() const
|
||||
{
|
||||
if(d->items.contains("\251alb"))
|
||||
return d->items["\251alb"].toStringList().toString(", ");
|
||||
return String::null;
|
||||
}
|
||||
|
||||
String
|
||||
MP4::Tag::comment() const
|
||||
{
|
||||
if(d->items.contains("\251cmt"))
|
||||
return d->items["\251cmt"].toStringList().toString(", ");
|
||||
return String::null;
|
||||
}
|
||||
|
||||
String
|
||||
MP4::Tag::genre() const
|
||||
{
|
||||
if(d->items.contains("\251gen"))
|
||||
return d->items["\251gen"].toStringList().toString(", ");
|
||||
return String::null;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
MP4::Tag::year() const
|
||||
{
|
||||
if(d->items.contains("\251day"))
|
||||
return d->items["\251day"].toStringList().toString().toInt();
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
MP4::Tag::track() const
|
||||
{
|
||||
if(d->items.contains("trkn"))
|
||||
return d->items["trkn"].toIntPair().first;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::setTitle(const String &value)
|
||||
{
|
||||
d->items["\251nam"] = StringList(value);
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::setArtist(const String &value)
|
||||
{
|
||||
d->items["\251ART"] = StringList(value);
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::setAlbum(const String &value)
|
||||
{
|
||||
d->items["\251alb"] = StringList(value);
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::setComment(const String &value)
|
||||
{
|
||||
d->items["\251cmt"] = StringList(value);
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::setGenre(const String &value)
|
||||
{
|
||||
d->items["\251gen"] = StringList(value);
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::setYear(uint value)
|
||||
{
|
||||
d->items["\251day"] = StringList(String::number(value));
|
||||
}
|
||||
|
||||
void
|
||||
MP4::Tag::setTrack(uint value)
|
||||
{
|
||||
d->items["trkn"] = MP4::Item(value, 0);
|
||||
}
|
||||
|
||||
MP4::ItemListMap &
|
||||
MP4::Tag::itemListMap()
|
||||
{
|
||||
return d->items;
|
||||
}
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
/**************************************************************************
|
||||
copyright : (C) 2007,2011 by Lukáš Lalinský
|
||||
email : lalinsky@gmail.com
|
||||
**************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_MP4TAG_H
|
||||
#define TAGLIB_MP4TAG_H
|
||||
|
||||
#include "tag.h"
|
||||
#include "tbytevectorlist.h"
|
||||
#include "tfile.h"
|
||||
#include "tmap.h"
|
||||
#include "tstringlist.h"
|
||||
#include "taglib_export.h"
|
||||
#include "mp4atom.h"
|
||||
#include "mp4item.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace MP4 {
|
||||
|
||||
typedef TagLib::Map<String, Item> ItemListMap;
|
||||
|
||||
class TAGLIB_EXPORT Tag: public TagLib::Tag
|
||||
{
|
||||
public:
|
||||
Tag();
|
||||
Tag(TagLib::File *file, Atoms *atoms);
|
||||
~Tag();
|
||||
bool save();
|
||||
|
||||
String title() const;
|
||||
String artist() const;
|
||||
String album() const;
|
||||
String comment() const;
|
||||
String genre() const;
|
||||
uint year() const;
|
||||
uint track() const;
|
||||
|
||||
void setTitle(const String &value);
|
||||
void setArtist(const String &value);
|
||||
void setAlbum(const String &value);
|
||||
void setComment(const String &value);
|
||||
void setGenre(const String &value);
|
||||
void setYear(uint value);
|
||||
void setTrack(uint value);
|
||||
|
||||
ItemListMap &itemListMap();
|
||||
|
||||
private:
|
||||
AtomDataList parseData2(Atom *atom, TagLib::File *file, int expectedFlags = -1, bool freeForm = false);
|
||||
TagLib::ByteVectorList parseData(Atom *atom, TagLib::File *file, int expectedFlags = -1, bool freeForm = false);
|
||||
void parseText(Atom *atom, TagLib::File *file, int expectedFlags = 1);
|
||||
void parseFreeForm(Atom *atom, TagLib::File *file);
|
||||
void parseInt(Atom *atom, TagLib::File *file);
|
||||
void parseByte(Atom *atom, TagLib::File *file);
|
||||
void parseUInt(Atom *atom, TagLib::File *file);
|
||||
void parseLongLong(Atom *atom, TagLib::File *file);
|
||||
void parseGnre(Atom *atom, TagLib::File *file);
|
||||
void parseIntPair(Atom *atom, TagLib::File *file);
|
||||
void parseBool(Atom *atom, TagLib::File *file);
|
||||
void parseCovr(Atom *atom, TagLib::File *file);
|
||||
|
||||
TagLib::ByteVector padIlst(const ByteVector &data, int length = -1);
|
||||
TagLib::ByteVector renderAtom(const ByteVector &name, const TagLib::ByteVector &data);
|
||||
TagLib::ByteVector renderData(const ByteVector &name, int flags, const TagLib::ByteVectorList &data);
|
||||
TagLib::ByteVector renderText(const ByteVector &name, Item &item, int flags = TypeUTF8);
|
||||
TagLib::ByteVector renderFreeForm(const String &name, Item &item);
|
||||
TagLib::ByteVector renderBool(const ByteVector &name, Item &item);
|
||||
TagLib::ByteVector renderInt(const ByteVector &name, Item &item);
|
||||
TagLib::ByteVector renderByte(const ByteVector &name, Item &item);
|
||||
TagLib::ByteVector renderUInt(const ByteVector &name, Item &item);
|
||||
TagLib::ByteVector renderLongLong(const ByteVector &name, Item &item);
|
||||
TagLib::ByteVector renderIntPair(const ByteVector &name, Item &item);
|
||||
TagLib::ByteVector renderIntPairNoTrailing(const ByteVector &name, Item &item);
|
||||
TagLib::ByteVector renderCovr(const ByteVector &name, Item &item);
|
||||
|
||||
void updateParents(AtomList &path, long delta, int ignore = 0);
|
||||
void updateOffsets(long delta, long offset);
|
||||
|
||||
void saveNew(TagLib::ByteVector &data);
|
||||
void saveExisting(TagLib::ByteVector &data, AtomList &path);
|
||||
|
||||
class TagPrivate;
|
||||
TagPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,360 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||
email : kde@carewolf.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tbytevector.h>
|
||||
#include <tstring.h>
|
||||
#include <tagunion.h>
|
||||
#include <tdebug.h>
|
||||
#include <tpropertymap.h>
|
||||
|
||||
#include "mpcfile.h"
|
||||
#include "id3v1tag.h"
|
||||
#include "id3v2header.h"
|
||||
#include "apetag.h"
|
||||
#include "apefooter.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
namespace
|
||||
{
|
||||
enum { MPCAPEIndex, MPCID3v1Index };
|
||||
}
|
||||
|
||||
class MPC::File::FilePrivate
|
||||
{
|
||||
public:
|
||||
FilePrivate() :
|
||||
APELocation(-1),
|
||||
APESize(0),
|
||||
ID3v1Location(-1),
|
||||
ID3v2Header(0),
|
||||
ID3v2Location(-1),
|
||||
ID3v2Size(0),
|
||||
properties(0),
|
||||
scanned(false),
|
||||
hasAPE(false),
|
||||
hasID3v1(false),
|
||||
hasID3v2(false) {}
|
||||
|
||||
~FilePrivate()
|
||||
{
|
||||
delete ID3v2Header;
|
||||
delete properties;
|
||||
}
|
||||
|
||||
long APELocation;
|
||||
uint APESize;
|
||||
|
||||
long ID3v1Location;
|
||||
|
||||
ID3v2::Header *ID3v2Header;
|
||||
long ID3v2Location;
|
||||
uint ID3v2Size;
|
||||
|
||||
TagUnion tag;
|
||||
|
||||
Properties *properties;
|
||||
bool scanned;
|
||||
|
||||
// These indicate whether the file *on disk* has these tags, not if
|
||||
// this data structure does. This is used in computing offsets.
|
||||
|
||||
bool hasAPE;
|
||||
bool hasID3v1;
|
||||
bool hasID3v2;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MPC::File::File(FileName file, bool readProperties,
|
||||
Properties::ReadStyle propertiesStyle) : TagLib::File(file)
|
||||
{
|
||||
d = new FilePrivate;
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
MPC::File::File(IOStream *stream, bool readProperties,
|
||||
Properties::ReadStyle propertiesStyle) : TagLib::File(stream)
|
||||
{
|
||||
d = new FilePrivate;
|
||||
read(readProperties, propertiesStyle);
|
||||
}
|
||||
|
||||
MPC::File::~File()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
TagLib::Tag *MPC::File::tag() const
|
||||
{
|
||||
return &d->tag;
|
||||
}
|
||||
|
||||
PropertyMap MPC::File::properties() const
|
||||
{
|
||||
if(d->hasAPE)
|
||||
return d->tag.access<APE::Tag>(MPCAPEIndex, false)->properties();
|
||||
if(d->hasID3v1)
|
||||
return d->tag.access<ID3v1::Tag>(MPCID3v1Index, false)->properties();
|
||||
return PropertyMap();
|
||||
}
|
||||
|
||||
void MPC::File::removeUnsupportedProperties(const StringList &properties)
|
||||
{
|
||||
if(d->hasAPE)
|
||||
d->tag.access<APE::Tag>(MPCAPEIndex, false)->removeUnsupportedProperties(properties);
|
||||
if(d->hasID3v1)
|
||||
d->tag.access<ID3v1::Tag>(MPCID3v1Index, false)->removeUnsupportedProperties(properties);
|
||||
}
|
||||
|
||||
PropertyMap MPC::File::setProperties(const PropertyMap &properties)
|
||||
{
|
||||
if(d->hasAPE)
|
||||
return d->tag.access<APE::Tag>(MPCAPEIndex, false)->setProperties(properties);
|
||||
else if(d->hasID3v1)
|
||||
return d->tag.access<ID3v1::Tag>(MPCID3v1Index, false)->setProperties(properties);
|
||||
else
|
||||
return d->tag.access<APE::Tag>(APE, true)->setProperties(properties);
|
||||
}
|
||||
|
||||
|
||||
MPC::Properties *MPC::File::audioProperties() const
|
||||
{
|
||||
return d->properties;
|
||||
}
|
||||
|
||||
bool MPC::File::save()
|
||||
{
|
||||
if(readOnly()) {
|
||||
debug("MPC::File::save() -- File is read only.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Possibly strip ID3v2 tag
|
||||
|
||||
if(d->hasID3v2 && !d->ID3v2Header) {
|
||||
removeBlock(d->ID3v2Location, d->ID3v2Size);
|
||||
d->hasID3v2 = false;
|
||||
if(d->hasID3v1)
|
||||
d->ID3v1Location -= d->ID3v2Size;
|
||||
if(d->hasAPE)
|
||||
d->APELocation -= d->ID3v2Size;
|
||||
}
|
||||
|
||||
// Update ID3v1 tag
|
||||
|
||||
if(ID3v1Tag()) {
|
||||
if(d->hasID3v1) {
|
||||
seek(d->ID3v1Location);
|
||||
writeBlock(ID3v1Tag()->render());
|
||||
}
|
||||
else {
|
||||
seek(0, End);
|
||||
d->ID3v1Location = tell();
|
||||
writeBlock(ID3v1Tag()->render());
|
||||
d->hasID3v1 = true;
|
||||
}
|
||||
} else
|
||||
if(d->hasID3v1) {
|
||||
removeBlock(d->ID3v1Location, 128);
|
||||
d->hasID3v1 = false;
|
||||
if(d->hasAPE) {
|
||||
if(d->APELocation > d->ID3v1Location)
|
||||
d->APELocation -= 128;
|
||||
}
|
||||
}
|
||||
|
||||
// Update APE tag
|
||||
|
||||
if(APETag()) {
|
||||
if(d->hasAPE)
|
||||
insert(APETag()->render(), d->APELocation, d->APESize);
|
||||
else {
|
||||
if(d->hasID3v1) {
|
||||
insert(APETag()->render(), d->ID3v1Location, 0);
|
||||
d->APESize = APETag()->footer()->completeTagSize();
|
||||
d->hasAPE = true;
|
||||
d->APELocation = d->ID3v1Location;
|
||||
d->ID3v1Location += d->APESize;
|
||||
}
|
||||
else {
|
||||
seek(0, End);
|
||||
d->APELocation = tell();
|
||||
writeBlock(APETag()->render());
|
||||
d->APESize = APETag()->footer()->completeTagSize();
|
||||
d->hasAPE = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
if(d->hasAPE) {
|
||||
removeBlock(d->APELocation, d->APESize);
|
||||
d->hasAPE = false;
|
||||
if(d->hasID3v1) {
|
||||
if(d->ID3v1Location > d->APELocation)
|
||||
d->ID3v1Location -= d->APESize;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ID3v1::Tag *MPC::File::ID3v1Tag(bool create)
|
||||
{
|
||||
return d->tag.access<ID3v1::Tag>(MPCID3v1Index, create);
|
||||
}
|
||||
|
||||
APE::Tag *MPC::File::APETag(bool create)
|
||||
{
|
||||
return d->tag.access<APE::Tag>(MPCAPEIndex, create);
|
||||
}
|
||||
|
||||
void MPC::File::strip(int tags)
|
||||
{
|
||||
if(tags & ID3v1) {
|
||||
d->tag.set(MPCID3v1Index, 0);
|
||||
APETag(true);
|
||||
}
|
||||
|
||||
if(tags & ID3v2) {
|
||||
delete d->ID3v2Header;
|
||||
d->ID3v2Header = 0;
|
||||
}
|
||||
|
||||
if(tags & APE) {
|
||||
d->tag.set(MPCAPEIndex, 0);
|
||||
|
||||
if(!ID3v1Tag())
|
||||
APETag(true);
|
||||
}
|
||||
}
|
||||
|
||||
void MPC::File::remove(int tags)
|
||||
{
|
||||
strip(tags);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void MPC::File::read(bool readProperties, Properties::ReadStyle /* propertiesStyle */)
|
||||
{
|
||||
// Look for an ID3v1 tag
|
||||
|
||||
d->ID3v1Location = findID3v1();
|
||||
|
||||
if(d->ID3v1Location >= 0) {
|
||||
d->tag.set(MPCID3v1Index, new ID3v1::Tag(this, d->ID3v1Location));
|
||||
d->hasID3v1 = true;
|
||||
}
|
||||
|
||||
// Look for an APE tag
|
||||
|
||||
findAPE();
|
||||
|
||||
d->APELocation = findAPE();
|
||||
|
||||
if(d->APELocation >= 0) {
|
||||
d->tag.set(MPCAPEIndex, new APE::Tag(this, d->APELocation));
|
||||
|
||||
d->APESize = APETag()->footer()->completeTagSize();
|
||||
d->APELocation = d->APELocation + APETag()->footer()->size() - d->APESize;
|
||||
d->hasAPE = true;
|
||||
}
|
||||
|
||||
if(!d->hasID3v1)
|
||||
APETag(true);
|
||||
|
||||
// Look for and skip an ID3v2 tag
|
||||
|
||||
d->ID3v2Location = findID3v2();
|
||||
|
||||
if(d->ID3v2Location >= 0) {
|
||||
seek(d->ID3v2Location);
|
||||
d->ID3v2Header = new ID3v2::Header(readBlock(ID3v2::Header::size()));
|
||||
d->ID3v2Size = d->ID3v2Header->completeTagSize();
|
||||
d->hasID3v2 = true;
|
||||
}
|
||||
|
||||
if(d->hasID3v2)
|
||||
seek(d->ID3v2Location + d->ID3v2Size);
|
||||
else
|
||||
seek(0);
|
||||
|
||||
// Look for MPC metadata
|
||||
|
||||
if(readProperties) {
|
||||
d->properties = new Properties(this, length() - d->ID3v2Size - d->APESize);
|
||||
}
|
||||
}
|
||||
|
||||
long MPC::File::findAPE()
|
||||
{
|
||||
if(!isValid())
|
||||
return -1;
|
||||
|
||||
if(d->hasID3v1)
|
||||
seek(-160, End);
|
||||
else
|
||||
seek(-32, End);
|
||||
|
||||
long p = tell();
|
||||
|
||||
if(readBlock(8) == APE::Tag::fileIdentifier())
|
||||
return p;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
long MPC::File::findID3v1()
|
||||
{
|
||||
if(!isValid())
|
||||
return -1;
|
||||
|
||||
seek(-128, End);
|
||||
long p = tell();
|
||||
|
||||
if(readBlock(3) == ID3v1::Tag::fileIdentifier())
|
||||
return p;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
long MPC::File::findID3v2()
|
||||
{
|
||||
if(!isValid())
|
||||
return -1;
|
||||
|
||||
seek(0);
|
||||
|
||||
if(readBlock(3) == ID3v2::Header::fileIdentifier())
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,204 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||
email : kde@carewolf.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_MPCFILE_H
|
||||
#define TAGLIB_MPCFILE_H
|
||||
|
||||
#include "taglib_export.h"
|
||||
#include "tfile.h"
|
||||
#include "tag.h"
|
||||
|
||||
#include "mpcproperties.h"
|
||||
|
||||
#include "tlist.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
class Tag;
|
||||
|
||||
namespace ID3v1 { class Tag; }
|
||||
namespace APE { class Tag; }
|
||||
|
||||
//! An implementation of MPC metadata
|
||||
|
||||
/*!
|
||||
* This is implementation of MPC metadata.
|
||||
*
|
||||
* This supports ID3v1 and APE (v1 and v2) style comments as well as reading stream
|
||||
* properties from the file. ID3v2 tags are invalid in MPC-files, but will be skipped
|
||||
* and ignored.
|
||||
*/
|
||||
|
||||
namespace MPC {
|
||||
|
||||
//! An implementation of TagLib::File with MPC specific methods
|
||||
|
||||
/*!
|
||||
* This implements and provides an interface for MPC files to the
|
||||
* TagLib::Tag and TagLib::AudioProperties interfaces by way of implementing
|
||||
* the abstract TagLib::File API as well as providing some additional
|
||||
* information specific to MPC files.
|
||||
* The only invalid tag combination supported is an ID3v1 tag after an APE tag.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT File : public TagLib::File
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* This set of flags is used for various operations and is suitable for
|
||||
* being OR-ed together.
|
||||
*/
|
||||
enum TagTypes {
|
||||
//! Empty set. Matches no tag types.
|
||||
NoTags = 0x0000,
|
||||
//! Matches ID3v1 tags.
|
||||
ID3v1 = 0x0001,
|
||||
//! Matches ID3v2 tags.
|
||||
ID3v2 = 0x0002,
|
||||
//! Matches APE tags.
|
||||
APE = 0x0004,
|
||||
//! Matches all tag types.
|
||||
AllTags = 0xffff
|
||||
};
|
||||
|
||||
/*!
|
||||
* Contructs an MPC file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*/
|
||||
File(FileName file, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Contructs an MPC file from \a file. If \a readProperties is true the
|
||||
* file's audio properties will also be read using \a propertiesStyle. If
|
||||
* false, \a propertiesStyle is ignored.
|
||||
*
|
||||
* \note TagLib will *not* take ownership of the stream, the caller is
|
||||
* responsible for deleting it after the File object.
|
||||
*/
|
||||
File(IOStream *stream, bool readProperties = true,
|
||||
Properties::ReadStyle propertiesStyle = Properties::Average);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the File.
|
||||
*/
|
||||
virtual ~File();
|
||||
|
||||
/*!
|
||||
* Returns the Tag for this file. This will be an APE tag, an ID3v1 tag
|
||||
* or a combination of the two.
|
||||
*/
|
||||
virtual TagLib::Tag *tag() const;
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- export function.
|
||||
* If the file contains both an APE and an ID3v1 tag, only the APE
|
||||
* tag will be converted to the PropertyMap.
|
||||
*/
|
||||
PropertyMap properties() const;
|
||||
|
||||
void removeUnsupportedProperties(const StringList &properties);
|
||||
|
||||
/*!
|
||||
* Implements the unified property interface -- import function.
|
||||
* As with the export, only one tag is taken into account. If the file
|
||||
* has no tag at all, an APE tag will be created.
|
||||
*/
|
||||
PropertyMap setProperties(const PropertyMap &);
|
||||
|
||||
/*!
|
||||
* Returns the MPC::Properties for this file. If no audio properties
|
||||
* were read then this will return a null pointer.
|
||||
*/
|
||||
virtual Properties *audioProperties() const;
|
||||
|
||||
/*!
|
||||
* Saves the file.
|
||||
*/
|
||||
virtual bool save();
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the ID3v1 tag of the file.
|
||||
*
|
||||
* If \a create is false (the default) this will return a null pointer
|
||||
* if there is no valid ID3v1 tag. If \a create is true it will create
|
||||
* an ID3v1 tag if one does not exist. If there is already an APE tag, the
|
||||
* new ID3v1 tag will be placed after it.
|
||||
*
|
||||
* \note The Tag <b>is still</b> owned by the APE::File and should not be
|
||||
* deleted by the user. It will be deleted when the file (object) is
|
||||
* destroyed.
|
||||
*/
|
||||
ID3v1::Tag *ID3v1Tag(bool create = false);
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the APE tag of the file.
|
||||
*
|
||||
* If \a create is false (the default) this will return a null pointer
|
||||
* if there is no valid APE tag. If \a create is true it will create
|
||||
* a APE tag if one does not exist. If there is already an ID3v1 tag, thes
|
||||
* new APE tag will be placed before it.
|
||||
*
|
||||
* \note The Tag <b>is still</b> owned by the APE::File and should not be
|
||||
* deleted by the user. It will be deleted when the file (object) is
|
||||
* destroyed.
|
||||
*/
|
||||
APE::Tag *APETag(bool create = false);
|
||||
|
||||
/*!
|
||||
* This will remove the tags that match the OR-ed together TagTypes from the
|
||||
* file. By default it removes all tags.
|
||||
*
|
||||
* \warning This will also invalidate pointers to the tags
|
||||
* as their memory will be freed.
|
||||
*
|
||||
* \note In order to make the removal permanent save() still needs to be called.
|
||||
*/
|
||||
void strip(int tags = AllTags);
|
||||
|
||||
/*!
|
||||
* \deprecated
|
||||
* \see strip
|
||||
*/
|
||||
void remove(int tags = AllTags);
|
||||
|
||||
private:
|
||||
File(const File &);
|
||||
File &operator=(const File &);
|
||||
|
||||
void read(bool readProperties, Properties::ReadStyle propertiesStyle);
|
||||
void scan();
|
||||
long findAPE();
|
||||
long findID3v1();
|
||||
long findID3v2();
|
||||
|
||||
class FilePrivate;
|
||||
FilePrivate *d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,316 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||
email : kde@carewolf.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tstring.h>
|
||||
#include <tdebug.h>
|
||||
#include <bitset>
|
||||
#include <math.h>
|
||||
|
||||
#include "mpcproperties.h"
|
||||
#include "mpcfile.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class MPC::Properties::PropertiesPrivate
|
||||
{
|
||||
public:
|
||||
PropertiesPrivate(long length, ReadStyle s) :
|
||||
streamLength(length),
|
||||
style(s),
|
||||
version(0),
|
||||
length(0),
|
||||
bitrate(0),
|
||||
sampleRate(0),
|
||||
channels(0),
|
||||
totalFrames(0),
|
||||
sampleFrames(0),
|
||||
trackGain(0),
|
||||
trackPeak(0),
|
||||
albumGain(0),
|
||||
albumPeak(0) {}
|
||||
|
||||
long streamLength;
|
||||
ReadStyle style;
|
||||
int version;
|
||||
int length;
|
||||
int bitrate;
|
||||
int sampleRate;
|
||||
int channels;
|
||||
uint totalFrames;
|
||||
uint sampleFrames;
|
||||
uint trackGain;
|
||||
uint trackPeak;
|
||||
uint albumGain;
|
||||
uint albumPeak;
|
||||
String flags;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
MPC::Properties::Properties(const ByteVector &data, long streamLength, ReadStyle style) : AudioProperties(style)
|
||||
{
|
||||
d = new PropertiesPrivate(streamLength, style);
|
||||
readSV7(data);
|
||||
}
|
||||
|
||||
MPC::Properties::Properties(File *file, long streamLength, ReadStyle style) : AudioProperties(style)
|
||||
{
|
||||
d = new PropertiesPrivate(streamLength, style);
|
||||
ByteVector magic = file->readBlock(4);
|
||||
if(magic == "MPCK") {
|
||||
// Musepack version 8
|
||||
readSV8(file);
|
||||
}
|
||||
else {
|
||||
// Musepack version 7 or older, fixed size header
|
||||
readSV7(magic + file->readBlock(MPC::HeaderSize - 4));
|
||||
}
|
||||
}
|
||||
|
||||
MPC::Properties::~Properties()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
int MPC::Properties::length() const
|
||||
{
|
||||
return d->length;
|
||||
}
|
||||
|
||||
int MPC::Properties::bitrate() const
|
||||
{
|
||||
return d->bitrate;
|
||||
}
|
||||
|
||||
int MPC::Properties::sampleRate() const
|
||||
{
|
||||
return d->sampleRate;
|
||||
}
|
||||
|
||||
int MPC::Properties::channels() const
|
||||
{
|
||||
return d->channels;
|
||||
}
|
||||
|
||||
int MPC::Properties::mpcVersion() const
|
||||
{
|
||||
return d->version;
|
||||
}
|
||||
|
||||
TagLib::uint MPC::Properties::totalFrames() const
|
||||
{
|
||||
return d->totalFrames;
|
||||
}
|
||||
|
||||
TagLib::uint MPC::Properties::sampleFrames() const
|
||||
{
|
||||
return d->sampleFrames;
|
||||
}
|
||||
|
||||
int MPC::Properties::trackGain() const
|
||||
{
|
||||
return d->trackGain;
|
||||
}
|
||||
|
||||
int MPC::Properties::trackPeak() const
|
||||
{
|
||||
return d->trackPeak;
|
||||
}
|
||||
|
||||
int MPC::Properties::albumGain() const
|
||||
{
|
||||
return d->albumGain;
|
||||
}
|
||||
|
||||
int MPC::Properties::albumPeak() const
|
||||
{
|
||||
return d->albumPeak;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsigned long readSize(File *file, TagLib::uint &sizelength)
|
||||
{
|
||||
unsigned char tmp;
|
||||
unsigned long size = 0;
|
||||
|
||||
do {
|
||||
ByteVector b = file->readBlock(1);
|
||||
tmp = b[0];
|
||||
size = (size << 7) | (tmp & 0x7F);
|
||||
sizelength++;
|
||||
} while((tmp & 0x80));
|
||||
return size;
|
||||
}
|
||||
|
||||
unsigned long readSize(const ByteVector &data, TagLib::uint &sizelength)
|
||||
{
|
||||
unsigned char tmp;
|
||||
unsigned long size = 0;
|
||||
unsigned long pos = 0;
|
||||
|
||||
do {
|
||||
tmp = data[pos++];
|
||||
size = (size << 7) | (tmp & 0x7F);
|
||||
sizelength++;
|
||||
} while((tmp & 0x80) && (pos < data.size()));
|
||||
return size;
|
||||
}
|
||||
|
||||
static const unsigned short sftable [4] = { 44100, 48000, 37800, 32000 };
|
||||
|
||||
void MPC::Properties::readSV8(File *file)
|
||||
{
|
||||
bool readSH = false, readRG = false;
|
||||
|
||||
while(!readSH && !readRG) {
|
||||
ByteVector packetType = file->readBlock(2);
|
||||
uint packetSizeLength = 0;
|
||||
unsigned long packetSize = readSize(file, packetSizeLength);
|
||||
unsigned long dataSize = packetSize - 2 - packetSizeLength;
|
||||
|
||||
if(packetType == "SH") {
|
||||
// Stream Header
|
||||
// http://trac.musepack.net/wiki/SV8Specification#StreamHeaderPacket
|
||||
ByteVector data = file->readBlock(dataSize);
|
||||
readSH = true;
|
||||
|
||||
TagLib::uint pos = 4;
|
||||
d->version = data[pos];
|
||||
pos += 1;
|
||||
d->sampleFrames = readSize(data.mid(pos), pos);
|
||||
ulong begSilence = readSize(data.mid(pos), pos);
|
||||
|
||||
std::bitset<16> flags(TAGLIB_CONSTRUCT_BITSET(data.mid(pos, 2).toUShort(true)));
|
||||
pos += 2;
|
||||
|
||||
d->sampleRate = sftable[flags[15] * 4 + flags[14] * 2 + flags[13]];
|
||||
d->channels = flags[7] * 8 + flags[6] * 4 + flags[5] * 2 + flags[4] + 1;
|
||||
|
||||
if((d->sampleFrames - begSilence) != 0)
|
||||
d->bitrate = (int)(d->streamLength * 8.0 * d->sampleRate / (d->sampleFrames - begSilence));
|
||||
d->bitrate = d->bitrate / 1000;
|
||||
|
||||
d->length = (d->sampleFrames - begSilence) / d->sampleRate;
|
||||
}
|
||||
|
||||
else if (packetType == "RG") {
|
||||
// Replay Gain
|
||||
// http://trac.musepack.net/wiki/SV8Specification#ReplaygainPacket
|
||||
ByteVector data = file->readBlock(dataSize);
|
||||
readRG = true;
|
||||
|
||||
int replayGainVersion = data[0];
|
||||
if(replayGainVersion == 1) {
|
||||
d->trackGain = data.mid(1, 2).toUInt(true);
|
||||
d->trackPeak = data.mid(3, 2).toUInt(true);
|
||||
d->albumGain = data.mid(5, 2).toUInt(true);
|
||||
d->albumPeak = data.mid(7, 2).toUInt(true);
|
||||
}
|
||||
}
|
||||
|
||||
else if(packetType == "SE") {
|
||||
break;
|
||||
}
|
||||
|
||||
else {
|
||||
file->seek(dataSize, File::Current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MPC::Properties::readSV7(const ByteVector &data)
|
||||
{
|
||||
if(data.startsWith("MP+")) {
|
||||
d->version = data[3] & 15;
|
||||
if(d->version < 7)
|
||||
return;
|
||||
|
||||
d->totalFrames = data.mid(4, 4).toUInt(false);
|
||||
|
||||
std::bitset<32> flags(TAGLIB_CONSTRUCT_BITSET(data.mid(8, 4).toUInt(false)));
|
||||
d->sampleRate = sftable[flags[17] * 2 + flags[16]];
|
||||
d->channels = 2;
|
||||
|
||||
uint gapless = data.mid(5, 4).toUInt(false);
|
||||
|
||||
d->trackGain = data.mid(14,2).toShort(false);
|
||||
d->trackPeak = data.mid(12,2).toUInt(false);
|
||||
d->albumGain = data.mid(18,2).toShort(false);
|
||||
d->albumPeak = data.mid(16,2).toUInt(false);
|
||||
|
||||
// convert gain info
|
||||
if(d->trackGain != 0) {
|
||||
int tmp = (int)((64.82 - (short)d->trackGain / 100.) * 256. + .5);
|
||||
if(tmp >= (1 << 16) || tmp < 0) tmp = 0;
|
||||
d->trackGain = tmp;
|
||||
}
|
||||
|
||||
if(d->albumGain != 0) {
|
||||
int tmp = (int)((64.82 - d->albumGain / 100.) * 256. + .5);
|
||||
if(tmp >= (1 << 16) || tmp < 0) tmp = 0;
|
||||
d->albumGain = tmp;
|
||||
}
|
||||
|
||||
if (d->trackPeak != 0)
|
||||
d->trackPeak = (int)(log10((double)d->trackPeak) * 20 * 256 + .5);
|
||||
|
||||
if (d->albumPeak != 0)
|
||||
d->albumPeak = (int)(log10((double)d->albumPeak) * 20 * 256 + .5);
|
||||
|
||||
bool trueGapless = (gapless >> 31) & 0x0001;
|
||||
if(trueGapless) {
|
||||
uint lastFrameSamples = (gapless >> 20) & 0x07FF;
|
||||
d->sampleFrames = d->totalFrames * 1152 - lastFrameSamples;
|
||||
}
|
||||
else
|
||||
d->sampleFrames = d->totalFrames * 1152 - 576;
|
||||
}
|
||||
else {
|
||||
uint headerData = data.mid(0, 4).toUInt(false);
|
||||
|
||||
d->bitrate = (headerData >> 23) & 0x01ff;
|
||||
d->version = (headerData >> 11) & 0x03ff;
|
||||
d->sampleRate = 44100;
|
||||
d->channels = 2;
|
||||
|
||||
if(d->version >= 5)
|
||||
d->totalFrames = data.mid(4, 4).toUInt(false);
|
||||
else
|
||||
d->totalFrames = data.mid(6, 2).toUInt(false);
|
||||
|
||||
d->sampleFrames = d->totalFrames * 1152 - 576;
|
||||
}
|
||||
|
||||
d->length = d->sampleRate > 0 ? (d->sampleFrames + (d->sampleRate / 2)) / d->sampleRate : 0;
|
||||
|
||||
if(!d->bitrate)
|
||||
d->bitrate = d->length > 0 ? ((d->streamLength * 8L) / d->length) / 1000 : 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||
email : kde@carewolf.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_MPCPROPERTIES_H
|
||||
#define TAGLIB_MPCPROPERTIES_H
|
||||
|
||||
#include "taglib_export.h"
|
||||
#include "audioproperties.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace MPC {
|
||||
|
||||
class File;
|
||||
|
||||
static const uint HeaderSize = 8*7;
|
||||
|
||||
//! An implementation of audio property reading for MPC
|
||||
|
||||
/*!
|
||||
* This reads the data from an MPC stream found in the AudioProperties
|
||||
* API.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT Properties : public AudioProperties
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* Create an instance of MPC::Properties with the data read from the
|
||||
* ByteVector \a data.
|
||||
*
|
||||
* This constructor is deprecated. It only works for MPC version up to 7.
|
||||
*/
|
||||
Properties(const ByteVector &data, long streamLength, ReadStyle style = Average);
|
||||
|
||||
/*!
|
||||
* Create an instance of MPC::Properties with the data read directly
|
||||
* from a MPC::File.
|
||||
*/
|
||||
Properties(File *file, long streamLength, ReadStyle style = Average);
|
||||
|
||||
/*!
|
||||
* Destroys this MPC::Properties instance.
|
||||
*/
|
||||
virtual ~Properties();
|
||||
|
||||
// Reimplementations.
|
||||
|
||||
virtual int length() const;
|
||||
virtual int bitrate() const;
|
||||
virtual int sampleRate() const;
|
||||
virtual int channels() const;
|
||||
|
||||
/*!
|
||||
* Returns the version of the bitstream (SV4-SV8)
|
||||
*/
|
||||
int mpcVersion() const;
|
||||
uint totalFrames() const;
|
||||
uint sampleFrames() const;
|
||||
|
||||
/*!
|
||||
* Returns the track gain as an integer value,
|
||||
* to convert to dB: trackGain in dB = 64.82 - (trackGain / 256)
|
||||
*/
|
||||
int trackGain() const;
|
||||
|
||||
/*!
|
||||
* Returns the track peak as an integer value,
|
||||
* to convert to dB: trackPeak in dB = trackPeak / 256
|
||||
* to convert to floating [-1..1]: trackPeak = 10^(trackPeak / 256 / 20)/32768
|
||||
*/
|
||||
int trackPeak() const;
|
||||
|
||||
/*!
|
||||
* Returns the album gain as an integer value,
|
||||
* to convert to dB: albumGain in dB = 64.82 - (albumGain / 256)
|
||||
*/
|
||||
int albumGain() const;
|
||||
|
||||
/*!
|
||||
* Returns the album peak as an integer value,
|
||||
* to convert to dB: albumPeak in dB = albumPeak / 256
|
||||
* to convert to floating [-1..1]: albumPeak = 10^(albumPeak / 256 / 20)/32768
|
||||
*/
|
||||
int albumPeak() const;
|
||||
|
||||
private:
|
||||
Properties(const Properties &);
|
||||
Properties &operator=(const Properties &);
|
||||
|
||||
void readSV7(const ByteVector &data);
|
||||
void readSV8(File *file);
|
||||
|
||||
class PropertiesPrivate;
|
||||
PropertiesPrivate *d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,219 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include "id3v1genres.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
namespace TagLib {
|
||||
namespace ID3v1 {
|
||||
|
||||
static const int genresSize = 148;
|
||||
static const String genres[] = {
|
||||
"Blues",
|
||||
"Classic Rock",
|
||||
"Country",
|
||||
"Dance",
|
||||
"Disco",
|
||||
"Funk",
|
||||
"Grunge",
|
||||
"Hip-Hop",
|
||||
"Jazz",
|
||||
"Metal",
|
||||
"New Age",
|
||||
"Oldies",
|
||||
"Other",
|
||||
"Pop",
|
||||
"R&B",
|
||||
"Rap",
|
||||
"Reggae",
|
||||
"Rock",
|
||||
"Techno",
|
||||
"Industrial",
|
||||
"Alternative",
|
||||
"Ska",
|
||||
"Death Metal",
|
||||
"Pranks",
|
||||
"Soundtrack",
|
||||
"Euro-Techno",
|
||||
"Ambient",
|
||||
"Trip-Hop",
|
||||
"Vocal",
|
||||
"Jazz+Funk",
|
||||
"Fusion",
|
||||
"Trance",
|
||||
"Classical",
|
||||
"Instrumental",
|
||||
"Acid",
|
||||
"House",
|
||||
"Game",
|
||||
"Sound Clip",
|
||||
"Gospel",
|
||||
"Noise",
|
||||
"Alternative Rock",
|
||||
"Bass",
|
||||
"Soul",
|
||||
"Punk",
|
||||
"Space",
|
||||
"Meditative",
|
||||
"Instrumental Pop",
|
||||
"Instrumental Rock",
|
||||
"Ethnic",
|
||||
"Gothic",
|
||||
"Darkwave",
|
||||
"Techno-Industrial",
|
||||
"Electronic",
|
||||
"Pop-Folk",
|
||||
"Eurodance",
|
||||
"Dream",
|
||||
"Southern Rock",
|
||||
"Comedy",
|
||||
"Cult",
|
||||
"Gangsta",
|
||||
"Top 40",
|
||||
"Christian Rap",
|
||||
"Pop/Funk",
|
||||
"Jungle",
|
||||
"Native American",
|
||||
"Cabaret",
|
||||
"New Wave",
|
||||
"Psychedelic",
|
||||
"Rave",
|
||||
"Showtunes",
|
||||
"Trailer",
|
||||
"Lo-Fi",
|
||||
"Tribal",
|
||||
"Acid Punk",
|
||||
"Acid Jazz",
|
||||
"Polka",
|
||||
"Retro",
|
||||
"Musical",
|
||||
"Rock & Roll",
|
||||
"Hard Rock",
|
||||
"Folk",
|
||||
"Folk/Rock",
|
||||
"National Folk",
|
||||
"Swing",
|
||||
"Fusion",
|
||||
"Bebob",
|
||||
"Latin",
|
||||
"Revival",
|
||||
"Celtic",
|
||||
"Bluegrass",
|
||||
"Avantgarde",
|
||||
"Gothic Rock",
|
||||
"Progressive Rock",
|
||||
"Psychedelic Rock",
|
||||
"Symphonic Rock",
|
||||
"Slow Rock",
|
||||
"Big Band",
|
||||
"Chorus",
|
||||
"Easy Listening",
|
||||
"Acoustic",
|
||||
"Humour",
|
||||
"Speech",
|
||||
"Chanson",
|
||||
"Opera",
|
||||
"Chamber Music",
|
||||
"Sonata",
|
||||
"Symphony",
|
||||
"Booty Bass",
|
||||
"Primus",
|
||||
"Porn Groove",
|
||||
"Satire",
|
||||
"Slow Jam",
|
||||
"Club",
|
||||
"Tango",
|
||||
"Samba",
|
||||
"Folklore",
|
||||
"Ballad",
|
||||
"Power Ballad",
|
||||
"Rhythmic Soul",
|
||||
"Freestyle",
|
||||
"Duet",
|
||||
"Punk Rock",
|
||||
"Drum Solo",
|
||||
"A Cappella",
|
||||
"Euro-House",
|
||||
"Dance Hall",
|
||||
"Goa",
|
||||
"Drum & Bass",
|
||||
"Club-House",
|
||||
"Hardcore",
|
||||
"Terror",
|
||||
"Indie",
|
||||
"BritPop",
|
||||
"Negerpunk",
|
||||
"Polsk Punk",
|
||||
"Beat",
|
||||
"Christian Gangsta Rap",
|
||||
"Heavy Metal",
|
||||
"Black Metal",
|
||||
"Crossover",
|
||||
"Contemporary Christian",
|
||||
"Christian Rock",
|
||||
"Merengue",
|
||||
"Salsa",
|
||||
"Thrash Metal",
|
||||
"Anime",
|
||||
"Jpop",
|
||||
"Synthpop"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
StringList ID3v1::genreList()
|
||||
{
|
||||
static StringList l;
|
||||
if(l.isEmpty()) {
|
||||
for(int i = 0; i < genresSize; i++)
|
||||
l.append(genres[i]);
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
ID3v1::GenreMap ID3v1::genreMap()
|
||||
{
|
||||
static GenreMap m;
|
||||
if(m.isEmpty()) {
|
||||
for(int i = 0; i < genresSize; i++)
|
||||
m.insert(genres[i], i);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
String ID3v1::genre(int i)
|
||||
{
|
||||
if(i >= 0 && i < genresSize)
|
||||
return genres[i] + String::null; // always make a copy
|
||||
return String::null;
|
||||
}
|
||||
|
||||
int ID3v1::genreIndex(const String &name)
|
||||
{
|
||||
if(genreMap().contains(name))
|
||||
return genreMap()[name];
|
||||
return 255;
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_ID3V1GENRE_H
|
||||
#define TAGLIB_ID3V1GENRE_H
|
||||
|
||||
#include "tmap.h"
|
||||
#include "tstringlist.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
namespace ID3v1 {
|
||||
|
||||
typedef Map<String, int> GenreMap;
|
||||
|
||||
/*!
|
||||
* Returns the list of canonical ID3v1 genre names in the order that they
|
||||
* are listed in the standard.
|
||||
*/
|
||||
StringList TAGLIB_EXPORT genreList();
|
||||
|
||||
/*!
|
||||
* A "reverse mapping" that goes from the canonical ID3v1 genre name to the
|
||||
* respective genre number. genreMap()["Rock"] ==
|
||||
*/
|
||||
GenreMap TAGLIB_EXPORT genreMap();
|
||||
|
||||
/*!
|
||||
* Returns the name of the genre at \a index in the ID3v1 genre list. If
|
||||
* \a index is out of range -- less than zero or greater than 146 -- a null
|
||||
* string will be returned.
|
||||
*/
|
||||
String TAGLIB_EXPORT genre(int index);
|
||||
|
||||
/*!
|
||||
* Returns the genre index for the (case sensitive) genre \a name. If the
|
||||
* genre is not in the list 255 (which signifies an unknown genre in ID3v1)
|
||||
* will be returned.
|
||||
*/
|
||||
int TAGLIB_EXPORT genreIndex(const String &name);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,255 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tdebug.h>
|
||||
#include <tfile.h>
|
||||
|
||||
#include "id3v1tag.h"
|
||||
#include "id3v1genres.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v1;
|
||||
|
||||
class ID3v1::Tag::TagPrivate
|
||||
{
|
||||
public:
|
||||
TagPrivate() : file(0), tagOffset(-1), track(0), genre(255) {}
|
||||
|
||||
File *file;
|
||||
long tagOffset;
|
||||
|
||||
String title;
|
||||
String artist;
|
||||
String album;
|
||||
String year;
|
||||
String comment;
|
||||
uchar track;
|
||||
uchar genre;
|
||||
|
||||
static const StringHandler *stringHandler;
|
||||
};
|
||||
|
||||
static const StringHandler defaultStringHandler;
|
||||
const ID3v1::StringHandler *ID3v1::Tag::TagPrivate::stringHandler = &defaultStringHandler;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// StringHandler implementation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
StringHandler::StringHandler()
|
||||
{
|
||||
}
|
||||
|
||||
String ID3v1::StringHandler::parse(const ByteVector &data) const
|
||||
{
|
||||
return String(data, String::Latin1).stripWhiteSpace();
|
||||
}
|
||||
|
||||
ByteVector ID3v1::StringHandler::render(const String &s) const
|
||||
{
|
||||
if(!s.isLatin1())
|
||||
{
|
||||
return ByteVector();
|
||||
}
|
||||
|
||||
return s.data(String::Latin1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ID3v1::Tag::Tag() : TagLib::Tag()
|
||||
{
|
||||
d = new TagPrivate;
|
||||
}
|
||||
|
||||
ID3v1::Tag::Tag(File *file, long tagOffset) : TagLib::Tag()
|
||||
{
|
||||
d = new TagPrivate;
|
||||
d->file = file;
|
||||
d->tagOffset = tagOffset;
|
||||
|
||||
read();
|
||||
}
|
||||
|
||||
ID3v1::Tag::~Tag()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
ByteVector ID3v1::Tag::render() const
|
||||
{
|
||||
ByteVector data;
|
||||
|
||||
data.append(fileIdentifier());
|
||||
data.append(TagPrivate::stringHandler->render(d->title).resize(30));
|
||||
data.append(TagPrivate::stringHandler->render(d->artist).resize(30));
|
||||
data.append(TagPrivate::stringHandler->render(d->album).resize(30));
|
||||
data.append(TagPrivate::stringHandler->render(d->year).resize(4));
|
||||
data.append(TagPrivate::stringHandler->render(d->comment).resize(28));
|
||||
data.append(char(0));
|
||||
data.append(char(d->track));
|
||||
data.append(char(d->genre));
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
ByteVector ID3v1::Tag::fileIdentifier()
|
||||
{
|
||||
return ByteVector::fromCString("TAG");
|
||||
}
|
||||
|
||||
String ID3v1::Tag::title() const
|
||||
{
|
||||
return d->title;
|
||||
}
|
||||
|
||||
String ID3v1::Tag::artist() const
|
||||
{
|
||||
return d->artist;
|
||||
}
|
||||
|
||||
String ID3v1::Tag::album() const
|
||||
{
|
||||
return d->album;
|
||||
}
|
||||
|
||||
String ID3v1::Tag::comment() const
|
||||
{
|
||||
return d->comment;
|
||||
}
|
||||
|
||||
String ID3v1::Tag::genre() const
|
||||
{
|
||||
return ID3v1::genre(d->genre);
|
||||
}
|
||||
|
||||
TagLib::uint ID3v1::Tag::year() const
|
||||
{
|
||||
return d->year.toInt();
|
||||
}
|
||||
|
||||
TagLib::uint ID3v1::Tag::track() const
|
||||
{
|
||||
return d->track;
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setTitle(const String &s)
|
||||
{
|
||||
d->title = s;
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setArtist(const String &s)
|
||||
{
|
||||
d->artist = s;
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setAlbum(const String &s)
|
||||
{
|
||||
d->album = s;
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setComment(const String &s)
|
||||
{
|
||||
d->comment = s;
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setGenre(const String &s)
|
||||
{
|
||||
d->genre = ID3v1::genreIndex(s);
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setYear(uint i)
|
||||
{
|
||||
d->year = i > 0 ? String::number(i) : String::null;
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setTrack(uint i)
|
||||
{
|
||||
d->track = i < 256 ? i : 0;
|
||||
}
|
||||
|
||||
void ID3v1::Tag::setStringHandler(const StringHandler *handler)
|
||||
{
|
||||
if (handler)
|
||||
TagPrivate::stringHandler = handler;
|
||||
else
|
||||
TagPrivate::stringHandler = &defaultStringHandler;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ID3v1::Tag::read()
|
||||
{
|
||||
if(d->file && d->file->isValid()) {
|
||||
d->file->seek(d->tagOffset);
|
||||
// read the tag -- always 128 bytes
|
||||
ByteVector data = d->file->readBlock(128);
|
||||
|
||||
// some initial sanity checking
|
||||
if(data.size() == 128 && data.startsWith("TAG"))
|
||||
parse(data);
|
||||
else
|
||||
debug("ID3v1 tag is not valid or could not be read at the specified offset.");
|
||||
}
|
||||
}
|
||||
|
||||
void ID3v1::Tag::parse(const ByteVector &data)
|
||||
{
|
||||
int offset = 3;
|
||||
|
||||
d->title = TagPrivate::stringHandler->parse(data.mid(offset, 30));
|
||||
offset += 30;
|
||||
|
||||
d->artist = TagPrivate::stringHandler->parse(data.mid(offset, 30));
|
||||
offset += 30;
|
||||
|
||||
d->album = TagPrivate::stringHandler->parse(data.mid(offset, 30));
|
||||
offset += 30;
|
||||
|
||||
d->year = TagPrivate::stringHandler->parse(data.mid(offset, 4));
|
||||
offset += 4;
|
||||
|
||||
// Check for ID3v1.1 -- Note that ID3v1 *does not* support "track zero" -- this
|
||||
// is not a bug in TagLib. Since a zeroed byte is what we would expect to
|
||||
// indicate the end of a C-String, specifically the comment string, a value of
|
||||
// zero must be assumed to be just that.
|
||||
|
||||
if(data[offset + 28] == 0 && data[offset + 29] != 0) {
|
||||
// ID3v1.1 detected
|
||||
|
||||
d->comment = TagPrivate::stringHandler->parse(data.mid(offset, 28));
|
||||
d->track = uchar(data[offset + 29]);
|
||||
}
|
||||
else
|
||||
d->comment = data.mid(offset, 30);
|
||||
|
||||
offset += 30;
|
||||
|
||||
d->genre = uchar(data[offset]);
|
||||
}
|
|
@ -0,0 +1,187 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_ID3V1TAG_H
|
||||
#define TAGLIB_ID3V1TAG_H
|
||||
|
||||
#include "tag.h"
|
||||
#include "tbytevector.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
class File;
|
||||
|
||||
//! An ID3v1 implementation
|
||||
|
||||
namespace ID3v1 {
|
||||
|
||||
//! A abstraction for the string to data encoding in ID3v1 tags.
|
||||
|
||||
/*!
|
||||
* ID3v1 should in theory always contain ISO-8859-1 (Latin1) data. In
|
||||
* practice it does not. TagLib by default only supports ISO-8859-1 data
|
||||
* in ID3v1 tags.
|
||||
*
|
||||
* However by subclassing this class and reimplementing parse() and render()
|
||||
* and setting your reimplementation as the default with
|
||||
* ID3v1::Tag::setStringHandler() you can define how you would like these
|
||||
* transformations to be done.
|
||||
*
|
||||
* \warning It is advisable <b>not</b> to write non-ISO-8859-1 data to ID3v1
|
||||
* tags. Please consider disabling the writing of ID3v1 tags in the case
|
||||
* that the data is not ISO-8859-1.
|
||||
*
|
||||
* \see ID3v1::Tag::setStringHandler()
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT StringHandler
|
||||
{
|
||||
TAGLIB_IGNORE_MISSING_DESTRUCTOR
|
||||
public:
|
||||
// BIC: Add virtual destructor.
|
||||
StringHandler();
|
||||
|
||||
/*!
|
||||
* Decode a string from \a data. The default implementation assumes that
|
||||
* \a data is an ISO-8859-1 (Latin1) character array.
|
||||
*/
|
||||
virtual String parse(const ByteVector &data) const;
|
||||
|
||||
/*!
|
||||
* Encode a ByteVector with the data from \a s. The default implementation
|
||||
* assumes that \a s is an ISO-8859-1 (Latin1) string. If the string is
|
||||
* does not conform to ISO-8859-1, no value is written.
|
||||
*
|
||||
* \warning It is recommended that you <b>not</b> override this method, but
|
||||
* instead do not write an ID3v1 tag in the case that the data is not
|
||||
* ISO-8859-1.
|
||||
*/
|
||||
virtual ByteVector render(const String &s) const;
|
||||
};
|
||||
|
||||
//! The main class in the ID3v1 implementation
|
||||
|
||||
/*!
|
||||
* This is an implementation of the ID3v1 format. ID3v1 is both the simplist
|
||||
* and most common of tag formats but is rather limited. Because of its
|
||||
* pervasiveness and the way that applications have been written around the
|
||||
* fields that it provides, the generic TagLib::Tag API is a mirror of what is
|
||||
* provided by ID3v1.
|
||||
*
|
||||
* ID3v1 tags should generally only contain Latin1 information. However because
|
||||
* many applications do not follow this rule there is now support for overriding
|
||||
* the ID3v1 string handling using the ID3v1::StringHandler class. Please see
|
||||
* the documentation for that class for more information.
|
||||
*
|
||||
* \see StringHandler
|
||||
*
|
||||
* \note Most fields are truncated to a maximum of 28-30 bytes. The
|
||||
* truncation happens automatically when the tag is rendered.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT Tag : public TagLib::Tag
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* Create an ID3v1 tag with default values.
|
||||
*/
|
||||
Tag();
|
||||
|
||||
/*!
|
||||
* Create an ID3v1 tag and parse the data in \a file starting at
|
||||
* \a tagOffset.
|
||||
*/
|
||||
Tag(File *file, long tagOffset);
|
||||
|
||||
/*!
|
||||
* Destroys this Tag instance.
|
||||
*/
|
||||
virtual ~Tag();
|
||||
|
||||
/*!
|
||||
* Renders the in memory values to a ByteVector suitable for writing to
|
||||
* the file.
|
||||
*/
|
||||
ByteVector render() const;
|
||||
|
||||
/*!
|
||||
* Returns the string "TAG" suitable for usage in locating the tag in a
|
||||
* file.
|
||||
*/
|
||||
static ByteVector fileIdentifier();
|
||||
|
||||
// Reimplementations.
|
||||
|
||||
virtual String title() const;
|
||||
virtual String artist() const;
|
||||
virtual String album() const;
|
||||
virtual String comment() const;
|
||||
virtual String genre() const;
|
||||
virtual uint year() const;
|
||||
virtual uint track() const;
|
||||
|
||||
virtual void setTitle(const String &s);
|
||||
virtual void setArtist(const String &s);
|
||||
virtual void setAlbum(const String &s);
|
||||
virtual void setComment(const String &s);
|
||||
virtual void setGenre(const String &s);
|
||||
virtual void setYear(uint i);
|
||||
virtual void setTrack(uint i);
|
||||
|
||||
/*!
|
||||
* Sets the string handler that decides how the ID3v1 data will be
|
||||
* converted to and from binary data.
|
||||
* If the parameter \a handler is null, the previous handler is
|
||||
* released and default ISO-8859-1 handler is restored.
|
||||
*
|
||||
* \note The caller is responsible for deleting the previous handler
|
||||
* as needed after it is released.
|
||||
*
|
||||
* \see StringHandler
|
||||
*/
|
||||
static void setStringHandler(const StringHandler *handler);
|
||||
|
||||
protected:
|
||||
/*!
|
||||
* Reads from the file specified in the constructor.
|
||||
*/
|
||||
void read();
|
||||
/*!
|
||||
* Pareses the body of the tag in \a data.
|
||||
*/
|
||||
void parse(const ByteVector &data);
|
||||
|
||||
private:
|
||||
Tag(const Tag &);
|
||||
Tag &operator=(const Tag &);
|
||||
|
||||
class TagPrivate;
|
||||
TagPrivate *d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,222 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include "attachedpictureframe.h"
|
||||
|
||||
#include <tstringlist.h>
|
||||
#include <tdebug.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class AttachedPictureFrame::AttachedPictureFramePrivate
|
||||
{
|
||||
public:
|
||||
AttachedPictureFramePrivate() : textEncoding(String::Latin1),
|
||||
type(AttachedPictureFrame::Other) {}
|
||||
|
||||
String::Type textEncoding;
|
||||
String mimeType;
|
||||
AttachedPictureFrame::Type type;
|
||||
String description;
|
||||
ByteVector data;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AttachedPictureFrame::AttachedPictureFrame() : Frame("APIC")
|
||||
{
|
||||
d = new AttachedPictureFramePrivate;
|
||||
}
|
||||
|
||||
AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data) : Frame(data)
|
||||
{
|
||||
d = new AttachedPictureFramePrivate;
|
||||
setData(data);
|
||||
}
|
||||
|
||||
AttachedPictureFrame::~AttachedPictureFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String AttachedPictureFrame::toString() const
|
||||
{
|
||||
String s = "[" + d->mimeType + "]";
|
||||
return d->description.isEmpty() ? s : d->description + " " + s;
|
||||
}
|
||||
|
||||
String::Type AttachedPictureFrame::textEncoding() const
|
||||
{
|
||||
return d->textEncoding;
|
||||
}
|
||||
|
||||
void AttachedPictureFrame::setTextEncoding(String::Type t)
|
||||
{
|
||||
d->textEncoding = t;
|
||||
}
|
||||
|
||||
String AttachedPictureFrame::mimeType() const
|
||||
{
|
||||
return d->mimeType;
|
||||
}
|
||||
|
||||
void AttachedPictureFrame::setMimeType(const String &m)
|
||||
{
|
||||
d->mimeType = m;
|
||||
}
|
||||
|
||||
AttachedPictureFrame::Type AttachedPictureFrame::type() const
|
||||
{
|
||||
return d->type;
|
||||
}
|
||||
|
||||
void AttachedPictureFrame::setType(Type t)
|
||||
{
|
||||
d->type = t;
|
||||
}
|
||||
|
||||
String AttachedPictureFrame::description() const
|
||||
{
|
||||
return d->description;
|
||||
}
|
||||
|
||||
void AttachedPictureFrame::setDescription(const String &desc)
|
||||
{
|
||||
d->description = desc;
|
||||
}
|
||||
|
||||
ByteVector AttachedPictureFrame::picture() const
|
||||
{
|
||||
return d->data;
|
||||
}
|
||||
|
||||
void AttachedPictureFrame::setPicture(const ByteVector &p)
|
||||
{
|
||||
d->data = p;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void AttachedPictureFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
if(data.size() < 5) {
|
||||
debug("A picture frame must contain at least 5 bytes.");
|
||||
return;
|
||||
}
|
||||
|
||||
d->textEncoding = String::Type(data[0]);
|
||||
|
||||
int pos = 1;
|
||||
|
||||
d->mimeType = readStringField(data, String::Latin1, &pos);
|
||||
/* Now we need at least two more bytes available */
|
||||
if (uint(pos) + 1 >= data.size()) {
|
||||
debug("Truncated picture frame.");
|
||||
return;
|
||||
}
|
||||
|
||||
d->type = (TagLib::ID3v2::AttachedPictureFrame::Type)data[pos++];
|
||||
d->description = readStringField(data, d->textEncoding, &pos);
|
||||
|
||||
d->data = data.mid(pos);
|
||||
}
|
||||
|
||||
ByteVector AttachedPictureFrame::renderFields() const
|
||||
{
|
||||
ByteVector data;
|
||||
|
||||
String::Type encoding = checkTextEncoding(d->description, d->textEncoding);
|
||||
|
||||
data.append(char(encoding));
|
||||
data.append(d->mimeType.data(String::Latin1));
|
||||
data.append(textDelimiter(String::Latin1));
|
||||
data.append(char(d->type));
|
||||
data.append(d->description.data(encoding));
|
||||
data.append(textDelimiter(encoding));
|
||||
data.append(d->data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AttachedPictureFrame::AttachedPictureFrame(const ByteVector &data, Header *h) : Frame(h)
|
||||
{
|
||||
d = new AttachedPictureFramePrivate;
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// support for ID3v2.2 PIC frames
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void AttachedPictureFrameV22::parseFields(const ByteVector &data)
|
||||
{
|
||||
if(data.size() < 5) {
|
||||
debug("A picture frame must contain at least 5 bytes.");
|
||||
return;
|
||||
}
|
||||
|
||||
d->textEncoding = String::Type(data[0]);
|
||||
|
||||
int pos = 1;
|
||||
|
||||
String fixedString = String(data.mid(pos, 3), String::Latin1);
|
||||
pos += 3;
|
||||
// convert fixed string image type to mime string
|
||||
if (fixedString.upper() == "JPG") {
|
||||
d->mimeType = "image/jpeg";
|
||||
} else if (fixedString.upper() == "PNG") {
|
||||
d->mimeType = "image/png";
|
||||
} else {
|
||||
debug("probably unsupported image type");
|
||||
d->mimeType = "image/" + fixedString;
|
||||
}
|
||||
|
||||
d->type = (TagLib::ID3v2::AttachedPictureFrame::Type)data[pos++];
|
||||
d->description = readStringField(data, d->textEncoding, &pos);
|
||||
|
||||
d->data = data.mid(pos);
|
||||
}
|
||||
|
||||
AttachedPictureFrameV22::AttachedPictureFrameV22(const ByteVector &data, Header *h)
|
||||
{
|
||||
// set v2.2 header to make fieldData work correctly
|
||||
setHeader(h, true);
|
||||
|
||||
parseFields(fieldData(data));
|
||||
|
||||
// now set the v2.4 header
|
||||
Frame::Header *newHeader = new Frame::Header("APIC");
|
||||
newHeader->setFrameSize(h->frameSize());
|
||||
setHeader(newHeader, true);
|
||||
}
|
|
@ -0,0 +1,230 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_ATTACHEDPICTUREFRAME_H
|
||||
#define TAGLIB_ATTACHEDPICTUREFRAME_H
|
||||
|
||||
#include "id3v2frame.h"
|
||||
#include "id3v2header.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! An ID3v2 attached picture frame implementation
|
||||
|
||||
/*!
|
||||
* This is an implementation of ID3v2 attached pictures. Pictures may be
|
||||
* included in tags, one per APIC frame (but there may be multiple APIC
|
||||
* frames in a single tag). These pictures are usually in either JPEG or
|
||||
* PNG format.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT AttachedPictureFrame : public Frame
|
||||
{
|
||||
friend class FrameFactory;
|
||||
|
||||
public:
|
||||
|
||||
/*!
|
||||
* This describes the function or content of the picture.
|
||||
*/
|
||||
enum Type {
|
||||
//! A type not enumerated below
|
||||
Other = 0x00,
|
||||
//! 32x32 PNG image that should be used as the file icon
|
||||
FileIcon = 0x01,
|
||||
//! File icon of a different size or format
|
||||
OtherFileIcon = 0x02,
|
||||
//! Front cover image of the album
|
||||
FrontCover = 0x03,
|
||||
//! Back cover image of the album
|
||||
BackCover = 0x04,
|
||||
//! Inside leaflet page of the album
|
||||
LeafletPage = 0x05,
|
||||
//! Image from the album itself
|
||||
Media = 0x06,
|
||||
//! Picture of the lead artist or soloist
|
||||
LeadArtist = 0x07,
|
||||
//! Picture of the artist or performer
|
||||
Artist = 0x08,
|
||||
//! Picture of the conductor
|
||||
Conductor = 0x09,
|
||||
//! Picture of the band or orchestra
|
||||
Band = 0x0A,
|
||||
//! Picture of the composer
|
||||
Composer = 0x0B,
|
||||
//! Picture of the lyricist or text writer
|
||||
Lyricist = 0x0C,
|
||||
//! Picture of the recording location or studio
|
||||
RecordingLocation = 0x0D,
|
||||
//! Picture of the artists during recording
|
||||
DuringRecording = 0x0E,
|
||||
//! Picture of the artists during performance
|
||||
DuringPerformance = 0x0F,
|
||||
//! Picture from a movie or video related to the track
|
||||
MovieScreenCapture = 0x10,
|
||||
//! Picture of a large, coloured fish
|
||||
ColouredFish = 0x11,
|
||||
//! Illustration related to the track
|
||||
Illustration = 0x12,
|
||||
//! Logo of the band or performer
|
||||
BandLogo = 0x13,
|
||||
//! Logo of the publisher (record company)
|
||||
PublisherLogo = 0x14
|
||||
};
|
||||
|
||||
/*!
|
||||
* Constructs an empty picture frame. The description, content and text
|
||||
* encoding should be set manually.
|
||||
*/
|
||||
AttachedPictureFrame();
|
||||
|
||||
/*!
|
||||
* Constructs an AttachedPicture frame based on \a data.
|
||||
*/
|
||||
explicit AttachedPictureFrame(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Destroys the AttahcedPictureFrame instance.
|
||||
*/
|
||||
virtual ~AttachedPictureFrame();
|
||||
|
||||
/*!
|
||||
* Returns a string containing the description and mime-type
|
||||
*/
|
||||
virtual String toString() const;
|
||||
|
||||
/*!
|
||||
* Returns the text encoding used for the description.
|
||||
*
|
||||
* \see setTextEncoding()
|
||||
* \see description()
|
||||
*/
|
||||
String::Type textEncoding() const;
|
||||
|
||||
/*!
|
||||
* Set the text encoding used for the description.
|
||||
*
|
||||
* \see description()
|
||||
*/
|
||||
void setTextEncoding(String::Type t);
|
||||
|
||||
/*!
|
||||
* Returns the mime type of the image. This should in most cases be
|
||||
* "image/png" or "image/jpeg".
|
||||
*/
|
||||
String mimeType() const;
|
||||
|
||||
/*!
|
||||
* Sets the mime type of the image. This should in most cases be
|
||||
* "image/png" or "image/jpeg".
|
||||
*/
|
||||
void setMimeType(const String &m);
|
||||
|
||||
/*!
|
||||
* Returns the type of the image.
|
||||
*
|
||||
* \see Type
|
||||
* \see setType()
|
||||
*/
|
||||
Type type() const;
|
||||
|
||||
/*!
|
||||
* Sets the type for the image.
|
||||
*
|
||||
* \see Type
|
||||
* \see type()
|
||||
*/
|
||||
void setType(Type t);
|
||||
|
||||
/*!
|
||||
* Returns a text description of the image.
|
||||
*
|
||||
* \see setDescription()
|
||||
* \see textEncoding()
|
||||
* \see setTextEncoding()
|
||||
*/
|
||||
|
||||
String description() const;
|
||||
|
||||
/*!
|
||||
* Sets a textual description of the image to \a desc.
|
||||
*
|
||||
* \see description()
|
||||
* \see textEncoding()
|
||||
* \see setTextEncoding()
|
||||
*/
|
||||
|
||||
void setDescription(const String &desc);
|
||||
|
||||
/*!
|
||||
* Returns the image data as a ByteVector.
|
||||
*
|
||||
* \note ByteVector has a data() method that returns a const char * which
|
||||
* should make it easy to export this data to external programs.
|
||||
*
|
||||
* \see setPicture()
|
||||
* \see mimeType()
|
||||
*/
|
||||
ByteVector picture() const;
|
||||
|
||||
/*!
|
||||
* Sets the image data to \a p. \a p should be of the type specified in
|
||||
* this frame's mime-type specification.
|
||||
*
|
||||
* \see picture()
|
||||
* \see mimeType()
|
||||
* \see setMimeType()
|
||||
*/
|
||||
void setPicture(const ByteVector &p);
|
||||
|
||||
protected:
|
||||
virtual void parseFields(const ByteVector &data);
|
||||
virtual ByteVector renderFields() const;
|
||||
class AttachedPictureFramePrivate;
|
||||
AttachedPictureFramePrivate *d;
|
||||
|
||||
private:
|
||||
AttachedPictureFrame(const AttachedPictureFrame &);
|
||||
AttachedPictureFrame &operator=(const AttachedPictureFrame &);
|
||||
AttachedPictureFrame(const ByteVector &data, Header *h);
|
||||
|
||||
};
|
||||
|
||||
//! support for ID3v2.2 PIC frames
|
||||
class TAGLIB_EXPORT AttachedPictureFrameV22 : public AttachedPictureFrame
|
||||
{
|
||||
protected:
|
||||
virtual void parseFields(const ByteVector &data);
|
||||
private:
|
||||
AttachedPictureFrameV22(const ByteVector &data, Header *h);
|
||||
friend class FrameFactory;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,197 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tbytevectorlist.h>
|
||||
#include <id3v2tag.h>
|
||||
#include <tdebug.h>
|
||||
#include <tstringlist.h>
|
||||
|
||||
#include "commentsframe.h"
|
||||
#include "tpropertymap.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class CommentsFrame::CommentsFramePrivate
|
||||
{
|
||||
public:
|
||||
CommentsFramePrivate() : textEncoding(String::Latin1) {}
|
||||
String::Type textEncoding;
|
||||
ByteVector language;
|
||||
String description;
|
||||
String text;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CommentsFrame::CommentsFrame(String::Type encoding) : Frame("COMM")
|
||||
{
|
||||
d = new CommentsFramePrivate;
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
CommentsFrame::CommentsFrame(const ByteVector &data) : Frame(data)
|
||||
{
|
||||
d = new CommentsFramePrivate;
|
||||
setData(data);
|
||||
}
|
||||
|
||||
CommentsFrame::~CommentsFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String CommentsFrame::toString() const
|
||||
{
|
||||
return d->text;
|
||||
}
|
||||
|
||||
ByteVector CommentsFrame::language() const
|
||||
{
|
||||
return d->language;
|
||||
}
|
||||
|
||||
String CommentsFrame::description() const
|
||||
{
|
||||
return d->description;
|
||||
}
|
||||
|
||||
String CommentsFrame::text() const
|
||||
{
|
||||
return d->text;
|
||||
}
|
||||
|
||||
void CommentsFrame::setLanguage(const ByteVector &languageEncoding)
|
||||
{
|
||||
d->language = languageEncoding.mid(0, 3);
|
||||
}
|
||||
|
||||
void CommentsFrame::setDescription(const String &s)
|
||||
{
|
||||
d->description = s;
|
||||
}
|
||||
|
||||
void CommentsFrame::setText(const String &s)
|
||||
{
|
||||
d->text = s;
|
||||
}
|
||||
|
||||
String::Type CommentsFrame::textEncoding() const
|
||||
{
|
||||
return d->textEncoding;
|
||||
}
|
||||
|
||||
void CommentsFrame::setTextEncoding(String::Type encoding)
|
||||
{
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
PropertyMap CommentsFrame::asProperties() const
|
||||
{
|
||||
String key = description().upper();
|
||||
PropertyMap map;
|
||||
if(key.isEmpty() || key == "COMMENT")
|
||||
map.insert("COMMENT", text());
|
||||
else if(key.isNull())
|
||||
map.unsupportedData().append(L"COMM/" + description());
|
||||
else
|
||||
map.insert("COMMENT:" + key, text());
|
||||
return map;
|
||||
}
|
||||
|
||||
CommentsFrame *CommentsFrame::findByDescription(const ID3v2::Tag *tag, const String &d) // static
|
||||
{
|
||||
ID3v2::FrameList comments = tag->frameList("COMM");
|
||||
|
||||
for(ID3v2::FrameList::ConstIterator it = comments.begin();
|
||||
it != comments.end();
|
||||
++it)
|
||||
{
|
||||
CommentsFrame *frame = dynamic_cast<CommentsFrame *>(*it);
|
||||
if(frame && frame->description() == d)
|
||||
return frame;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CommentsFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
if(data.size() < 5) {
|
||||
debug("A comment frame must contain at least 5 bytes.");
|
||||
return;
|
||||
}
|
||||
|
||||
d->textEncoding = String::Type(data[0]);
|
||||
d->language = data.mid(1, 3);
|
||||
|
||||
int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
|
||||
|
||||
ByteVectorList l = ByteVectorList::split(data.mid(4), textDelimiter(d->textEncoding), byteAlign, 2);
|
||||
|
||||
if(l.size() == 2) {
|
||||
if(d->textEncoding == String::Latin1) {
|
||||
d->description = Tag::latin1StringHandler()->parse(l.front());
|
||||
d->text = Tag::latin1StringHandler()->parse(l.back());
|
||||
} else {
|
||||
d->description = String(l.front(), d->textEncoding);
|
||||
d->text = String(l.back(), d->textEncoding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector CommentsFrame::renderFields() const
|
||||
{
|
||||
ByteVector v;
|
||||
|
||||
String::Type encoding = d->textEncoding;
|
||||
|
||||
encoding = checkTextEncoding(d->description, encoding);
|
||||
encoding = checkTextEncoding(d->text, encoding);
|
||||
|
||||
v.append(char(encoding));
|
||||
v.append(d->language.size() == 3 ? d->language : "XXX");
|
||||
v.append(d->description.data(encoding));
|
||||
v.append(textDelimiter(encoding));
|
||||
v.append(d->text.data(encoding));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CommentsFrame::CommentsFrame(const ByteVector &data, Header *h) : Frame(h)
|
||||
{
|
||||
d = new CommentsFramePrivate();
|
||||
parseFields(fieldData(data));
|
||||
}
|
|
@ -0,0 +1,179 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_COMMENTSFRAME_H
|
||||
#define TAGLIB_COMMENTSFRAME_H
|
||||
|
||||
#include "id3v2frame.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! An implementation of ID3v2 comments
|
||||
|
||||
/*!
|
||||
* This implements the ID3v2 comment format. An ID3v2 comment concists of
|
||||
* a language encoding, a description and a single text field.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT CommentsFrame : public Frame
|
||||
{
|
||||
friend class FrameFactory;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Construct an empty comment frame that will use the text encoding
|
||||
* \a encoding.
|
||||
*/
|
||||
explicit CommentsFrame(String::Type encoding = String::Latin1);
|
||||
|
||||
/*!
|
||||
* Construct a comment based on the data in \a data.
|
||||
*/
|
||||
explicit CommentsFrame(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Destroys this CommentFrame instance.
|
||||
*/
|
||||
virtual ~CommentsFrame();
|
||||
|
||||
/*!
|
||||
* Returns the text of this comment.
|
||||
*
|
||||
* \see text()
|
||||
*/
|
||||
virtual String toString() const;
|
||||
|
||||
/*!
|
||||
* Returns the language encoding as a 3 byte encoding as specified by
|
||||
* <a href="http://en.wikipedia.org/wiki/ISO_639">ISO-639-2</a>.
|
||||
*
|
||||
* \note Most taggers simply ignore this value.
|
||||
*
|
||||
* \see setLanguage()
|
||||
*/
|
||||
ByteVector language() const;
|
||||
|
||||
/*!
|
||||
* Returns the description of this comment.
|
||||
*
|
||||
* \note Most taggers simply ignore this value.
|
||||
*
|
||||
* \see setDescription()
|
||||
*/
|
||||
String description() const;
|
||||
|
||||
/*!
|
||||
* Returns the text of this comment.
|
||||
*
|
||||
* \see setText()
|
||||
*/
|
||||
String text() const;
|
||||
|
||||
/*!
|
||||
* Set the language using the 3 byte language code from
|
||||
* <a href="http://en.wikipedia.org/wiki/ISO_639">ISO-639-2</a> to
|
||||
* \a languageCode.
|
||||
*
|
||||
* \see language()
|
||||
*/
|
||||
void setLanguage(const ByteVector &languageCode);
|
||||
|
||||
/*!
|
||||
* Sets the description of the comment to \a s.
|
||||
*
|
||||
* \see decription()
|
||||
*/
|
||||
void setDescription(const String &s);
|
||||
|
||||
/*!
|
||||
* Sets the text portion of the comment to \a s.
|
||||
*
|
||||
* \see text()
|
||||
*/
|
||||
virtual void setText(const String &s);
|
||||
|
||||
/*!
|
||||
* Returns the text encoding that will be used in rendering this frame.
|
||||
* This defaults to the type that was either specified in the constructor
|
||||
* or read from the frame when parsed.
|
||||
*
|
||||
* \see setTextEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
String::Type textEncoding() const;
|
||||
|
||||
/*!
|
||||
* Sets the text encoding to be used when rendering this frame to
|
||||
* \a encoding.
|
||||
*
|
||||
* \see textEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
void setTextEncoding(String::Type encoding);
|
||||
|
||||
/*!
|
||||
* Parses this frame as PropertyMap with a single key.
|
||||
* - if description() is empty or "COMMENT", the key will be "COMMENT"
|
||||
* - if description() is not a valid PropertyMap key, the frame will be
|
||||
* marked unsupported by an entry "COMM/<description>" in the unsupportedData()
|
||||
* attribute of the returned map.
|
||||
* - otherwise, the key will be "COMMENT:<description>"
|
||||
* - The single value will be the frame's text().
|
||||
*/
|
||||
PropertyMap asProperties() const;
|
||||
|
||||
/*!
|
||||
* Comments each have a unique description. This searches for a comment
|
||||
* frame with the decription \a d and returns a pointer to it. If no
|
||||
* frame is found that matches the given description null is returned.
|
||||
*
|
||||
* \see description()
|
||||
*/
|
||||
static CommentsFrame *findByDescription(const Tag *tag, const String &d);
|
||||
|
||||
protected:
|
||||
// Reimplementations.
|
||||
|
||||
virtual void parseFields(const ByteVector &data);
|
||||
virtual ByteVector renderFields() const;
|
||||
|
||||
private:
|
||||
/*!
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
CommentsFrame(const ByteVector &data, Header *h);
|
||||
CommentsFrame(const CommentsFrame &);
|
||||
CommentsFrame &operator=(const CommentsFrame &);
|
||||
|
||||
class CommentsFramePrivate;
|
||||
CommentsFramePrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,176 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
copyright : (C) 2006 by Aaron VonderHaar
|
||||
email : avh4@users.sourceforge.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tdebug.h>
|
||||
|
||||
#include "generalencapsulatedobjectframe.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFramePrivate
|
||||
{
|
||||
public:
|
||||
GeneralEncapsulatedObjectFramePrivate() : textEncoding(String::Latin1) {}
|
||||
|
||||
String::Type textEncoding;
|
||||
String mimeType;
|
||||
String fileName;
|
||||
String description;
|
||||
ByteVector data;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame() : Frame("GEOB")
|
||||
{
|
||||
d = new GeneralEncapsulatedObjectFramePrivate;
|
||||
}
|
||||
|
||||
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data) : Frame(data)
|
||||
{
|
||||
d = new GeneralEncapsulatedObjectFramePrivate;
|
||||
setData(data);
|
||||
}
|
||||
|
||||
GeneralEncapsulatedObjectFrame::~GeneralEncapsulatedObjectFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String GeneralEncapsulatedObjectFrame::toString() const
|
||||
{
|
||||
String text = "[" + d->mimeType + "]";
|
||||
|
||||
if(!d->fileName.isEmpty())
|
||||
text += " " + d->fileName;
|
||||
|
||||
if(!d->description.isEmpty())
|
||||
text += " \"" + d->description + "\"";
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
String::Type GeneralEncapsulatedObjectFrame::textEncoding() const
|
||||
{
|
||||
return d->textEncoding;
|
||||
}
|
||||
|
||||
void GeneralEncapsulatedObjectFrame::setTextEncoding(String::Type encoding)
|
||||
{
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
String GeneralEncapsulatedObjectFrame::mimeType() const
|
||||
{
|
||||
return d->mimeType;
|
||||
}
|
||||
|
||||
void GeneralEncapsulatedObjectFrame::setMimeType(const String &type)
|
||||
{
|
||||
d->mimeType = type;
|
||||
}
|
||||
|
||||
String GeneralEncapsulatedObjectFrame::fileName() const
|
||||
{
|
||||
return d->fileName;
|
||||
}
|
||||
|
||||
void GeneralEncapsulatedObjectFrame::setFileName(const String &name)
|
||||
{
|
||||
d->fileName = name;
|
||||
}
|
||||
|
||||
String GeneralEncapsulatedObjectFrame::description() const
|
||||
{
|
||||
return d->description;
|
||||
}
|
||||
|
||||
void GeneralEncapsulatedObjectFrame::setDescription(const String &desc)
|
||||
{
|
||||
d->description = desc;
|
||||
}
|
||||
|
||||
ByteVector GeneralEncapsulatedObjectFrame::object() const
|
||||
{
|
||||
return d->data;
|
||||
}
|
||||
|
||||
void GeneralEncapsulatedObjectFrame::setObject(const ByteVector &data)
|
||||
{
|
||||
d->data = data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void GeneralEncapsulatedObjectFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
if(data.size() < 4) {
|
||||
debug("An object frame must contain at least 4 bytes.");
|
||||
return;
|
||||
}
|
||||
|
||||
d->textEncoding = String::Type(data[0]);
|
||||
|
||||
int pos = 1;
|
||||
|
||||
d->mimeType = readStringField(data, String::Latin1, &pos);
|
||||
d->fileName = readStringField(data, d->textEncoding, &pos);
|
||||
d->description = readStringField(data, d->textEncoding, &pos);
|
||||
|
||||
d->data = data.mid(pos);
|
||||
}
|
||||
|
||||
ByteVector GeneralEncapsulatedObjectFrame::renderFields() const
|
||||
{
|
||||
ByteVector data;
|
||||
|
||||
data.append(char(d->textEncoding));
|
||||
data.append(d->mimeType.data(String::Latin1));
|
||||
data.append(textDelimiter(String::Latin1));
|
||||
data.append(d->fileName.data(d->textEncoding));
|
||||
data.append(textDelimiter(d->textEncoding));
|
||||
data.append(d->description.data(d->textEncoding));
|
||||
data.append(textDelimiter(d->textEncoding));
|
||||
data.append(d->data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GeneralEncapsulatedObjectFrame::GeneralEncapsulatedObjectFrame(const ByteVector &data, Header *h) : Frame(h)
|
||||
{
|
||||
d = new GeneralEncapsulatedObjectFramePrivate;
|
||||
parseFields(fieldData(data));
|
||||
}
|
|
@ -0,0 +1,178 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
copyright : (C) 2006 by Aaron VonderHaar
|
||||
email : avh4@users.sourceforge.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_GENERALENCAPSULATEDOBJECT_H
|
||||
#define TAGLIB_GENERALENCAPSULATEDOBJECT_H
|
||||
|
||||
#include "id3v2frame.h"
|
||||
#include "id3v2header.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! An ID3v2 general encapsulated object frame implementation
|
||||
|
||||
/*!
|
||||
* This is an implementation of ID3v2 general encapsulated objects.
|
||||
* Arbitrary binary data may be included in tags, stored in GEOB frames.
|
||||
* There may be multiple GEOB frames in a single tag. Each GEOB it
|
||||
* labelled with a content description (which may be blank), a required
|
||||
* mime-type, and a file name (may be blank). The content description
|
||||
* uniquely identifies the GEOB frame in the tag.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT GeneralEncapsulatedObjectFrame : public Frame
|
||||
{
|
||||
friend class FrameFactory;
|
||||
|
||||
public:
|
||||
|
||||
/*!
|
||||
* Constructs an empty object frame. The description, file name and text
|
||||
* encoding should be set manually.
|
||||
*/
|
||||
GeneralEncapsulatedObjectFrame();
|
||||
|
||||
/*!
|
||||
* Constructs a GeneralEncapsulatedObjectFrame frame based on \a data.
|
||||
*
|
||||
* \warning This is \em not data for the encapsulated object, for that use
|
||||
* setObject(). This constructor is used when reading the frame from the
|
||||
* disk.
|
||||
*/
|
||||
explicit GeneralEncapsulatedObjectFrame(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Destroys the GeneralEncapsulatedObjectFrame instance.
|
||||
*/
|
||||
virtual ~GeneralEncapsulatedObjectFrame();
|
||||
|
||||
/*!
|
||||
* Returns a string containing the description, file name and mime-type
|
||||
*/
|
||||
virtual String toString() const;
|
||||
|
||||
/*!
|
||||
* Returns the text encoding used for the description and file name.
|
||||
*
|
||||
* \see setTextEncoding()
|
||||
* \see description()
|
||||
* \see fileName()
|
||||
*/
|
||||
String::Type textEncoding() const;
|
||||
|
||||
/*!
|
||||
* Set the text encoding used for the description and file name.
|
||||
*
|
||||
* \see description()
|
||||
* \see fileName()
|
||||
*/
|
||||
void setTextEncoding(String::Type encoding);
|
||||
|
||||
/*!
|
||||
* Returns the mime type of the object.
|
||||
*/
|
||||
String mimeType() const;
|
||||
|
||||
/*!
|
||||
* Sets the mime type of the object.
|
||||
*/
|
||||
void setMimeType(const String &type);
|
||||
|
||||
/*!
|
||||
* Returns the file name of the object.
|
||||
*
|
||||
* \see setFileName()
|
||||
*/
|
||||
String fileName() const;
|
||||
|
||||
/*!
|
||||
* Sets the file name for the object.
|
||||
*
|
||||
* \see fileName()
|
||||
*/
|
||||
void setFileName(const String &name);
|
||||
|
||||
/*!
|
||||
* Returns the content description of the object.
|
||||
*
|
||||
* \see setDescription()
|
||||
* \see textEncoding()
|
||||
* \see setTextEncoding()
|
||||
*/
|
||||
|
||||
String description() const;
|
||||
|
||||
/*!
|
||||
* Sets the content description of the object to \a desc.
|
||||
*
|
||||
* \see description()
|
||||
* \see textEncoding()
|
||||
* \see setTextEncoding()
|
||||
*/
|
||||
|
||||
void setDescription(const String &desc);
|
||||
|
||||
/*!
|
||||
* Returns the object data as a ByteVector.
|
||||
*
|
||||
* \note ByteVector has a data() method that returns a const char * which
|
||||
* should make it easy to export this data to external programs.
|
||||
*
|
||||
* \see setObject()
|
||||
* \see mimeType()
|
||||
*/
|
||||
ByteVector object() const;
|
||||
|
||||
/*!
|
||||
* Sets the object data to \a data. \a data should be of the type specified in
|
||||
* this frame's mime-type specification.
|
||||
*
|
||||
* \see object()
|
||||
* \see mimeType()
|
||||
* \see setMimeType()
|
||||
*/
|
||||
void setObject(const ByteVector &object);
|
||||
|
||||
protected:
|
||||
virtual void parseFields(const ByteVector &data);
|
||||
virtual ByteVector renderFields() const;
|
||||
|
||||
private:
|
||||
GeneralEncapsulatedObjectFrame(const ByteVector &data, Header *h);
|
||||
GeneralEncapsulatedObjectFrame(const GeneralEncapsulatedObjectFrame &);
|
||||
GeneralEncapsulatedObjectFrame &operator=(const GeneralEncapsulatedObjectFrame &);
|
||||
|
||||
class GeneralEncapsulatedObjectFramePrivate;
|
||||
GeneralEncapsulatedObjectFramePrivate *d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,162 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2012 by Rupert Daniel
|
||||
email : rupert@cancelmonday.com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tdebug.h>
|
||||
|
||||
#include "ownershipframe.h"
|
||||
#include <id3v2tag.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class OwnershipFrame::OwnershipFramePrivate
|
||||
{
|
||||
public:
|
||||
String pricePaid;
|
||||
String datePurchased;
|
||||
String seller;
|
||||
String::Type textEncoding;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
OwnershipFrame::OwnershipFrame(String::Type encoding) : Frame("OWNE")
|
||||
{
|
||||
d = new OwnershipFramePrivate;
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
OwnershipFrame::OwnershipFrame(const ByteVector &data) : Frame(data)
|
||||
{
|
||||
d = new OwnershipFramePrivate;
|
||||
setData(data);
|
||||
}
|
||||
|
||||
OwnershipFrame::~OwnershipFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String OwnershipFrame::toString() const
|
||||
{
|
||||
return "pricePaid=" + d->pricePaid + " datePurchased=" + d->datePurchased + " seller=" + d->seller;
|
||||
}
|
||||
|
||||
String OwnershipFrame::pricePaid() const
|
||||
{
|
||||
return d->pricePaid;
|
||||
}
|
||||
|
||||
void OwnershipFrame::setPricePaid(const String &s)
|
||||
{
|
||||
d->pricePaid = s;
|
||||
}
|
||||
|
||||
String OwnershipFrame::datePurchased() const
|
||||
{
|
||||
return d->datePurchased;
|
||||
}
|
||||
|
||||
void OwnershipFrame::setDatePurchased(const String &s)
|
||||
{
|
||||
d->datePurchased = s;
|
||||
}
|
||||
|
||||
String OwnershipFrame::seller() const
|
||||
{
|
||||
return d->seller;
|
||||
}
|
||||
|
||||
void OwnershipFrame::setSeller(const String &s)
|
||||
{
|
||||
d->seller = s;
|
||||
}
|
||||
|
||||
String::Type OwnershipFrame::textEncoding() const
|
||||
{
|
||||
return d->textEncoding;
|
||||
}
|
||||
|
||||
void OwnershipFrame::setTextEncoding(String::Type encoding)
|
||||
{
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void OwnershipFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
int pos = 0;
|
||||
|
||||
// Get the text encoding
|
||||
d->textEncoding = String::Type(data[0]);
|
||||
pos += 1;
|
||||
|
||||
// Read the price paid this is a null terminate string
|
||||
d->pricePaid = readStringField(data, String::Latin1, &pos);
|
||||
|
||||
// If we don't have at least 8 bytes left then don't parse the rest of the
|
||||
// data
|
||||
if(data.size() - pos < 8) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Read the date purchased YYYYMMDD
|
||||
d->datePurchased = String(data.mid(pos, 8));
|
||||
pos += 8;
|
||||
|
||||
// Read the seller
|
||||
if(d->textEncoding == String::Latin1)
|
||||
d->seller = Tag::latin1StringHandler()->parse(data.mid(pos));
|
||||
else
|
||||
d->seller = String(data.mid(pos), d->textEncoding);
|
||||
}
|
||||
|
||||
ByteVector OwnershipFrame::renderFields() const
|
||||
{
|
||||
ByteVector v;
|
||||
|
||||
v.append(char(d->textEncoding));
|
||||
v.append(d->pricePaid.data(String::Latin1));
|
||||
v.append(textDelimiter(String::Latin1));
|
||||
v.append(d->datePurchased.data(String::Latin1));
|
||||
v.append(d->seller.data(d->textEncoding));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
OwnershipFrame::OwnershipFrame(const ByteVector &data, Header *h) : Frame(h)
|
||||
{
|
||||
d = new OwnershipFramePrivate;
|
||||
parseFields(fieldData(data));
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2012 by Rupert Daniel
|
||||
email : rupert@cancelmonday.com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_OWNERSHIPFRAME_H
|
||||
#define TAGLIB_OWNERSHIPFRAME_H
|
||||
|
||||
#include "id3v2frame.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! An implementation of ID3v2 "ownership"
|
||||
|
||||
/*!
|
||||
* This implements the ID3v2 ownership (OWNE frame). It consists of
|
||||
* a price paid, a date purchased (YYYYMMDD) and the name of the seller.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT OwnershipFrame : public Frame
|
||||
{
|
||||
friend class FrameFactory;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Construct an empty ownership frame.
|
||||
*/
|
||||
explicit OwnershipFrame(String::Type encoding = String::Latin1);
|
||||
|
||||
/*!
|
||||
* Construct a ownership based on the data in \a data.
|
||||
*/
|
||||
explicit OwnershipFrame(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Destroys this OwnershipFrame instance.
|
||||
*/
|
||||
virtual ~OwnershipFrame();
|
||||
|
||||
/*!
|
||||
* Returns the text of this popularimeter.
|
||||
*
|
||||
* \see text()
|
||||
*/
|
||||
virtual String toString() const;
|
||||
|
||||
/*!
|
||||
* Returns the date purchased.
|
||||
*
|
||||
* \see setDatePurchased()
|
||||
*/
|
||||
String datePurchased() const;
|
||||
|
||||
/*!
|
||||
* Set the date purchased.
|
||||
*
|
||||
* \see datePurchased()
|
||||
*/
|
||||
void setDatePurchased(const String &datePurchased);
|
||||
|
||||
/*!
|
||||
* Returns the price paid.
|
||||
*
|
||||
* \see setPricePaid()
|
||||
*/
|
||||
String pricePaid() const;
|
||||
|
||||
/*!
|
||||
* Set the price paid.
|
||||
*
|
||||
* \see pricePaid()
|
||||
*/
|
||||
void setPricePaid(const String &pricePaid);
|
||||
|
||||
/*!
|
||||
* Returns the seller.
|
||||
*
|
||||
* \see setSeller()
|
||||
*/
|
||||
String seller() const;
|
||||
|
||||
/*!
|
||||
* Set the seller.
|
||||
*
|
||||
* \see seller()
|
||||
*/
|
||||
void setSeller(const String &seller);
|
||||
|
||||
/*!
|
||||
* Returns the text encoding that will be used in rendering this frame.
|
||||
* This defaults to the type that was either specified in the constructor
|
||||
* or read from the frame when parsed.
|
||||
*
|
||||
* \see setTextEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
String::Type textEncoding() const;
|
||||
|
||||
/*!
|
||||
* Sets the text encoding to be used when rendering this frame to
|
||||
* \a encoding.
|
||||
*
|
||||
* \see textEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
void setTextEncoding(String::Type encoding);
|
||||
|
||||
protected:
|
||||
// Reimplementations.
|
||||
|
||||
virtual void parseFields(const ByteVector &data);
|
||||
virtual ByteVector renderFields() const;
|
||||
|
||||
private:
|
||||
/*!
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
OwnershipFrame(const ByteVector &data, Header *h);
|
||||
OwnershipFrame(const OwnershipFrame &);
|
||||
OwnershipFrame &operator=(const OwnershipFrame &);
|
||||
|
||||
class OwnershipFramePrivate;
|
||||
OwnershipFramePrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,137 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2008 by Lukas Lalinsky
|
||||
email : lalinsky@gmail.com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tdebug.h>
|
||||
|
||||
#include "popularimeterframe.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class PopularimeterFrame::PopularimeterFramePrivate
|
||||
{
|
||||
public:
|
||||
PopularimeterFramePrivate() : rating(0), counter(0) {}
|
||||
String email;
|
||||
int rating;
|
||||
TagLib::uint counter;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PopularimeterFrame::PopularimeterFrame() : Frame("POPM")
|
||||
{
|
||||
d = new PopularimeterFramePrivate;
|
||||
}
|
||||
|
||||
PopularimeterFrame::PopularimeterFrame(const ByteVector &data) : Frame(data)
|
||||
{
|
||||
d = new PopularimeterFramePrivate;
|
||||
setData(data);
|
||||
}
|
||||
|
||||
PopularimeterFrame::~PopularimeterFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String PopularimeterFrame::toString() const
|
||||
{
|
||||
return d->email + " rating=" + String::number(d->rating) + " counter=" + String::number(d->counter);
|
||||
}
|
||||
|
||||
String PopularimeterFrame::email() const
|
||||
{
|
||||
return d->email;
|
||||
}
|
||||
|
||||
void PopularimeterFrame::setEmail(const String &s)
|
||||
{
|
||||
d->email = s;
|
||||
}
|
||||
|
||||
int PopularimeterFrame::rating() const
|
||||
{
|
||||
return d->rating;
|
||||
}
|
||||
|
||||
void PopularimeterFrame::setRating(int s)
|
||||
{
|
||||
d->rating = s;
|
||||
}
|
||||
|
||||
TagLib::uint PopularimeterFrame::counter() const
|
||||
{
|
||||
return d->counter;
|
||||
}
|
||||
|
||||
void PopularimeterFrame::setCounter(TagLib::uint s)
|
||||
{
|
||||
d->counter = s;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PopularimeterFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
int pos = 0, size = int(data.size());
|
||||
|
||||
d->email = readStringField(data, String::Latin1, &pos);
|
||||
|
||||
d->rating = 0;
|
||||
d->counter = 0;
|
||||
if(pos < size) {
|
||||
d->rating = (unsigned char)(data[pos++]);
|
||||
if(pos < size) {
|
||||
d->counter = data.mid(pos, 4).toUInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2008 by Lukas Lalinsky
|
||||
email : lalinsky@gmail.com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_POPULARIMETERFRAME_H
|
||||
#define TAGLIB_POPULARIMETERFRAME_H
|
||||
|
||||
#include "id3v2frame.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! An implementation of ID3v2 "popularimeter"
|
||||
|
||||
/*!
|
||||
* This implements the ID3v2 popularimeter (POPM frame). It concists of
|
||||
* an email, a rating and an optional counter.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT PopularimeterFrame : public Frame
|
||||
{
|
||||
friend class FrameFactory;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Construct an empty popularimeter frame.
|
||||
*/
|
||||
explicit PopularimeterFrame();
|
||||
|
||||
/*!
|
||||
* Construct a popularimeter based on the data in \a data.
|
||||
*/
|
||||
explicit PopularimeterFrame(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Destroys this PopularimeterFrame instance.
|
||||
*/
|
||||
virtual ~PopularimeterFrame();
|
||||
|
||||
/*!
|
||||
* Returns the text of this popularimeter.
|
||||
*
|
||||
* \see text()
|
||||
*/
|
||||
virtual String toString() const;
|
||||
|
||||
/*!
|
||||
* Returns the email.
|
||||
*
|
||||
* \see setEmail()
|
||||
*/
|
||||
String email() const;
|
||||
|
||||
/*!
|
||||
* Set the email.
|
||||
*
|
||||
* \see email()
|
||||
*/
|
||||
void setEmail(const String &email);
|
||||
|
||||
/*!
|
||||
* Returns the rating.
|
||||
*
|
||||
* \see setRating()
|
||||
*/
|
||||
int rating() const;
|
||||
|
||||
/*!
|
||||
* Set the rating.
|
||||
*
|
||||
* \see rating()
|
||||
*/
|
||||
void setRating(int rating);
|
||||
|
||||
/*!
|
||||
* Returns the counter.
|
||||
*
|
||||
* \see setCounter()
|
||||
*/
|
||||
uint counter() const;
|
||||
|
||||
/*!
|
||||
* Set the counter.
|
||||
*
|
||||
* \see counter()
|
||||
*/
|
||||
void setCounter(uint counter);
|
||||
|
||||
protected:
|
||||
// Reimplementations.
|
||||
|
||||
virtual void parseFields(const ByteVector &data);
|
||||
virtual ByteVector renderFields() const;
|
||||
|
||||
private:
|
||||
/*!
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
PopularimeterFrame(const ByteVector &data, Header *h);
|
||||
PopularimeterFrame(const PopularimeterFrame &);
|
||||
PopularimeterFrame &operator=(const PopularimeterFrame &);
|
||||
|
||||
class PopularimeterFramePrivate;
|
||||
PopularimeterFramePrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,128 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2008 by Serkan Kalyoncu
|
||||
copyright : (C) 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tbytevectorlist.h>
|
||||
#include <id3v2tag.h>
|
||||
#include <tdebug.h>
|
||||
|
||||
#include "privateframe.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
|
||||
class PrivateFrame::PrivateFramePrivate
|
||||
{
|
||||
public:
|
||||
ByteVector data;
|
||||
String owner;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PrivateFrame::PrivateFrame() : Frame("PRIV")
|
||||
{
|
||||
d = new PrivateFramePrivate;
|
||||
}
|
||||
|
||||
PrivateFrame::PrivateFrame(const ByteVector &data) : Frame(data)
|
||||
{
|
||||
d = new PrivateFramePrivate;
|
||||
setData(data);
|
||||
}
|
||||
|
||||
PrivateFrame::~PrivateFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String PrivateFrame::toString() const
|
||||
{
|
||||
return d->owner;
|
||||
}
|
||||
|
||||
String PrivateFrame::owner() const
|
||||
{
|
||||
return d->owner;
|
||||
}
|
||||
|
||||
ByteVector PrivateFrame::data() const
|
||||
{
|
||||
return d->data;
|
||||
}
|
||||
|
||||
void PrivateFrame::setOwner(const String &s)
|
||||
{
|
||||
d->owner = s;
|
||||
}
|
||||
|
||||
void PrivateFrame::setData(const ByteVector & data)
|
||||
{
|
||||
d->data = data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PrivateFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
if(data.size() < 2) {
|
||||
debug("A private frame must contain at least 2 bytes.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Owner identifier is assumed to be Latin1
|
||||
|
||||
const int byteAlign = 1;
|
||||
const int endOfOwner = data.find(textDelimiter(String::Latin1), 0, byteAlign);
|
||||
|
||||
d->owner = String(data.mid(0, endOfOwner));
|
||||
d->data = data.mid(endOfOwner + 1);
|
||||
}
|
||||
|
||||
ByteVector PrivateFrame::renderFields() const
|
||||
{
|
||||
ByteVector v;
|
||||
|
||||
v.append(d->owner.data(String::Latin1));
|
||||
v.append(textDelimiter(String::Latin1));
|
||||
v.append(d->data);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PrivateFrame::PrivateFrame(const ByteVector &data, Header *h) : Frame(h)
|
||||
{
|
||||
d = new PrivateFramePrivate();
|
||||
parseFields(fieldData(data));
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2008 by Serkan Kalyoncu
|
||||
copyright : (C) 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_PRIVATEFRAME_H
|
||||
#define TAGLIB_PRIVATEFRAME_H
|
||||
|
||||
#include "id3v2frame.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! An implementation of ID3v2 privateframe
|
||||
|
||||
class TAGLIB_EXPORT PrivateFrame : public Frame
|
||||
{
|
||||
friend class FrameFactory;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Construct an empty private frame.
|
||||
*/
|
||||
PrivateFrame();
|
||||
|
||||
/*!
|
||||
* Construct a private frame based on the data in \a data.
|
||||
*
|
||||
* \note This is the constructor used when parsing the frame from a file.
|
||||
*/
|
||||
explicit PrivateFrame(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Destroys this private frame instance.
|
||||
*/
|
||||
virtual ~PrivateFrame();
|
||||
|
||||
/*!
|
||||
* Returns the text of this private frame, currently just the owner.
|
||||
*
|
||||
* \see text()
|
||||
*/
|
||||
virtual String toString() const;
|
||||
|
||||
/*!
|
||||
* \return The owner of the private frame.
|
||||
* \note This should contain an email address or link to a website.
|
||||
*/
|
||||
String owner() const;
|
||||
|
||||
/*!
|
||||
*
|
||||
*/
|
||||
ByteVector data() const;
|
||||
|
||||
/*!
|
||||
* Sets the owner of the frame to \a s.
|
||||
* \note This should contain an email address or link to a website.
|
||||
*/
|
||||
void setOwner(const String &s);
|
||||
|
||||
/*!
|
||||
*
|
||||
*/
|
||||
void setData(const ByteVector &v);
|
||||
|
||||
protected:
|
||||
// Reimplementations.
|
||||
|
||||
virtual void parseFields(const ByteVector &data);
|
||||
virtual ByteVector renderFields() const;
|
||||
|
||||
private:
|
||||
/*!
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
PrivateFrame(const ByteVector &data, Header *h);
|
||||
|
||||
PrivateFrame(const PrivateFrame &);
|
||||
PrivateFrame &operator=(const PrivateFrame &);
|
||||
|
||||
class PrivateFramePrivate;
|
||||
PrivateFramePrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,236 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tdebug.h>
|
||||
#include <tmap.h>
|
||||
|
||||
#include "relativevolumeframe.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
static inline int bitsToBytes(int i)
|
||||
{
|
||||
return i % 8 == 0 ? i / 8 : (i - i % 8) / 8 + 1;
|
||||
}
|
||||
|
||||
struct ChannelData
|
||||
{
|
||||
ChannelData() : channelType(RelativeVolumeFrame::Other), volumeAdjustment(0) {}
|
||||
|
||||
RelativeVolumeFrame::ChannelType channelType;
|
||||
short volumeAdjustment;
|
||||
RelativeVolumeFrame::PeakVolume peakVolume;
|
||||
};
|
||||
|
||||
class RelativeVolumeFrame::RelativeVolumeFramePrivate
|
||||
{
|
||||
public:
|
||||
String identification;
|
||||
Map<ChannelType, ChannelData> channels;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RelativeVolumeFrame::RelativeVolumeFrame() : Frame("RVA2")
|
||||
{
|
||||
d = new RelativeVolumeFramePrivate;
|
||||
}
|
||||
|
||||
RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data) : Frame(data)
|
||||
{
|
||||
d = new RelativeVolumeFramePrivate;
|
||||
setData(data);
|
||||
}
|
||||
|
||||
RelativeVolumeFrame::~RelativeVolumeFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String RelativeVolumeFrame::toString() const
|
||||
{
|
||||
return d->identification;
|
||||
}
|
||||
|
||||
List<RelativeVolumeFrame::ChannelType> RelativeVolumeFrame::channels() const
|
||||
{
|
||||
List<ChannelType> l;
|
||||
|
||||
Map<ChannelType, ChannelData>::ConstIterator it = d->channels.begin();
|
||||
for(; it != d->channels.end(); ++it)
|
||||
l.append((*it).first);
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
// deprecated
|
||||
|
||||
RelativeVolumeFrame::ChannelType RelativeVolumeFrame::channelType() const
|
||||
{
|
||||
return MasterVolume;
|
||||
}
|
||||
|
||||
// deprecated
|
||||
|
||||
void RelativeVolumeFrame::setChannelType(ChannelType)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
short RelativeVolumeFrame::volumeAdjustmentIndex(ChannelType type) const
|
||||
{
|
||||
return d->channels.contains(type) ? d->channels[type].volumeAdjustment : 0;
|
||||
}
|
||||
|
||||
short RelativeVolumeFrame::volumeAdjustmentIndex() const
|
||||
{
|
||||
return volumeAdjustmentIndex(MasterVolume);
|
||||
}
|
||||
|
||||
void RelativeVolumeFrame::setVolumeAdjustmentIndex(short index, ChannelType type)
|
||||
{
|
||||
d->channels[type].volumeAdjustment = index;
|
||||
}
|
||||
|
||||
void RelativeVolumeFrame::setVolumeAdjustmentIndex(short index)
|
||||
{
|
||||
setVolumeAdjustmentIndex(index, MasterVolume);
|
||||
}
|
||||
|
||||
float RelativeVolumeFrame::volumeAdjustment(ChannelType type) const
|
||||
{
|
||||
return d->channels.contains(type) ? float(d->channels[type].volumeAdjustment) / float(512) : 0;
|
||||
}
|
||||
|
||||
float RelativeVolumeFrame::volumeAdjustment() const
|
||||
{
|
||||
return volumeAdjustment(MasterVolume);
|
||||
}
|
||||
|
||||
void RelativeVolumeFrame::setVolumeAdjustment(float adjustment, ChannelType type)
|
||||
{
|
||||
d->channels[type].volumeAdjustment = short(adjustment * float(512));
|
||||
}
|
||||
|
||||
void RelativeVolumeFrame::setVolumeAdjustment(float adjustment)
|
||||
{
|
||||
setVolumeAdjustment(adjustment, MasterVolume);
|
||||
}
|
||||
|
||||
RelativeVolumeFrame::PeakVolume RelativeVolumeFrame::peakVolume(ChannelType type) const
|
||||
{
|
||||
return d->channels.contains(type) ? d->channels[type].peakVolume : PeakVolume();
|
||||
}
|
||||
|
||||
RelativeVolumeFrame::PeakVolume RelativeVolumeFrame::peakVolume() const
|
||||
{
|
||||
return peakVolume(MasterVolume);
|
||||
}
|
||||
|
||||
void RelativeVolumeFrame::setPeakVolume(const PeakVolume &peak, ChannelType type)
|
||||
{
|
||||
d->channels[type].peakVolume = peak;
|
||||
}
|
||||
|
||||
void RelativeVolumeFrame::setPeakVolume(const PeakVolume &peak)
|
||||
{
|
||||
setPeakVolume(peak, MasterVolume);
|
||||
}
|
||||
|
||||
String RelativeVolumeFrame::identification() const
|
||||
{
|
||||
return d->identification;
|
||||
}
|
||||
|
||||
void RelativeVolumeFrame::setIdentification(const String &s)
|
||||
{
|
||||
d->identification = s;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void RelativeVolumeFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
int pos = 0;
|
||||
d->identification = readStringField(data, String::Latin1, &pos);
|
||||
|
||||
// Each channel is at least 4 bytes.
|
||||
|
||||
while(pos <= (int)data.size() - 4) {
|
||||
|
||||
|
||||
ChannelType type = ChannelType(data[pos]);
|
||||
pos += 1;
|
||||
|
||||
ChannelData &channel = d->channels[type];
|
||||
|
||||
channel.volumeAdjustment = data.mid(pos, 2).toShort();
|
||||
pos += 2;
|
||||
|
||||
channel.peakVolume.bitsRepresentingPeak = data[pos];
|
||||
pos += 1;
|
||||
|
||||
int bytes = bitsToBytes(channel.peakVolume.bitsRepresentingPeak);
|
||||
channel.peakVolume.peakVolume = data.mid(pos, bytes);
|
||||
pos += bytes;
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector RelativeVolumeFrame::renderFields() const
|
||||
{
|
||||
ByteVector data;
|
||||
|
||||
data.append(d->identification.data(String::Latin1));
|
||||
data.append(textDelimiter(String::Latin1));
|
||||
|
||||
Map<ChannelType, ChannelData>::ConstIterator it = d->channels.begin();
|
||||
|
||||
for(; it != d->channels.end(); ++it) {
|
||||
ChannelType type = (*it).first;
|
||||
const ChannelData &channel = (*it).second;
|
||||
|
||||
data.append(char(type));
|
||||
data.append(ByteVector::fromShort(channel.volumeAdjustment));
|
||||
data.append(char(channel.peakVolume.bitsRepresentingPeak));
|
||||
data.append(channel.peakVolume.peakVolume);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RelativeVolumeFrame::RelativeVolumeFrame(const ByteVector &data, Header *h) : Frame(h)
|
||||
{
|
||||
d = new RelativeVolumeFramePrivate;
|
||||
parseFields(fieldData(data));
|
||||
}
|
|
@ -0,0 +1,274 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_RELATIVEVOLUMEFRAME_H
|
||||
#define TAGLIB_RELATIVEVOLUMEFRAME_H
|
||||
|
||||
#include "tlist.h"
|
||||
#include "id3v2frame.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! An ID3v2 relative volume adjustment frame implementation
|
||||
|
||||
/*!
|
||||
* This is an implementation of ID3v2 relative volume adjustment. The
|
||||
* presence of this frame makes it possible to specify an increase in volume
|
||||
* for an audio file or specific audio tracks in that file.
|
||||
*
|
||||
* Multiple relative volume adjustment frames may be present in the tag
|
||||
* each with a unique identification and describing volume adjustment for
|
||||
* different channel types.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT RelativeVolumeFrame : public Frame
|
||||
{
|
||||
friend class FrameFactory;
|
||||
|
||||
public:
|
||||
|
||||
/*!
|
||||
* This indicates the type of volume adjustment that should be applied.
|
||||
*/
|
||||
enum ChannelType {
|
||||
//! A type not enumerated below
|
||||
Other = 0x00,
|
||||
//! The master volume for the track
|
||||
MasterVolume = 0x01,
|
||||
//! The front right audio channel
|
||||
FrontRight = 0x02,
|
||||
//! The front left audio channel
|
||||
FrontLeft = 0x03,
|
||||
//! The back right audio channel
|
||||
BackRight = 0x04,
|
||||
//! The back left audio channel
|
||||
BackLeft = 0x05,
|
||||
//! The front center audio channel
|
||||
FrontCentre = 0x06,
|
||||
//! The back center audio channel
|
||||
BackCentre = 0x07,
|
||||
//! The subwoofer audio channel
|
||||
Subwoofer = 0x08
|
||||
};
|
||||
|
||||
//! Struct that stores the relevant values for ID3v2 peak volume
|
||||
|
||||
/*!
|
||||
* The peak volume is described as a series of bits that is padded to fill
|
||||
* a block of bytes. These two values should always be updated in tandem.
|
||||
*/
|
||||
struct PeakVolume
|
||||
{
|
||||
/*!
|
||||
* Constructs an empty peak volume description.
|
||||
*/
|
||||
PeakVolume() : bitsRepresentingPeak(0) {}
|
||||
/*!
|
||||
* The number of bits (in the range of 0 to 255) used to describe the
|
||||
* peak volume.
|
||||
*/
|
||||
unsigned char bitsRepresentingPeak;
|
||||
/*!
|
||||
* The array of bits (represented as a series of bytes) used to describe
|
||||
* the peak volume.
|
||||
*/
|
||||
ByteVector peakVolume;
|
||||
};
|
||||
|
||||
/*!
|
||||
* Constructs a RelativeVolumeFrame. The relevant data should be set
|
||||
* manually.
|
||||
*/
|
||||
RelativeVolumeFrame();
|
||||
|
||||
/*!
|
||||
* Constructs a RelativeVolumeFrame based on the contents of \a data.
|
||||
*/
|
||||
RelativeVolumeFrame(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Destroys the RelativeVolumeFrame instance.
|
||||
*/
|
||||
virtual ~RelativeVolumeFrame();
|
||||
|
||||
/*!
|
||||
* Returns the frame's identification.
|
||||
*
|
||||
* \see identification()
|
||||
*/
|
||||
virtual String toString() const;
|
||||
|
||||
/*!
|
||||
* Returns a list of channels with information currently in the frame.
|
||||
*/
|
||||
List<ChannelType> channels() const;
|
||||
|
||||
/*!
|
||||
* \deprecated Always returns master volume.
|
||||
*/
|
||||
ChannelType channelType() const;
|
||||
|
||||
/*!
|
||||
* \deprecated This method no longer has any effect.
|
||||
*/
|
||||
void setChannelType(ChannelType t);
|
||||
|
||||
/*
|
||||
* There was a terrible API goof here, and while this can't be changed to
|
||||
* the way it appears below for binary compaibility reasons, let's at
|
||||
* least pretend that it looks clean.
|
||||
*/
|
||||
|
||||
#ifdef DOXYGEN
|
||||
|
||||
/*!
|
||||
* Returns the relative volume adjustment "index". As indicated by the
|
||||
* ID3v2 standard this is a 16-bit signed integer that reflects the
|
||||
* decibils of adjustment when divided by 512.
|
||||
*
|
||||
* This defaults to returning the value for the master volume channel if
|
||||
* available and returns 0 if the specified channel does not exist.
|
||||
*
|
||||
* \see setVolumeAdjustmentIndex()
|
||||
* \see volumeAjustment()
|
||||
*/
|
||||
short volumeAdjustmentIndex(ChannelType type = MasterVolume) const;
|
||||
|
||||
/*!
|
||||
* Set the volume adjustment to \a index. As indicated by the ID3v2
|
||||
* standard this is a 16-bit signed integer that reflects the decibils of
|
||||
* adjustment when divided by 512.
|
||||
*
|
||||
* By default this sets the value for the master volume.
|
||||
*
|
||||
* \see volumeAdjustmentIndex()
|
||||
* \see setVolumeAjustment()
|
||||
*/
|
||||
void setVolumeAdjustmentIndex(short index, ChannelType type = MasterVolume);
|
||||
|
||||
/*!
|
||||
* Returns the relative volume adjustment in decibels.
|
||||
*
|
||||
* \note Because this is actually stored internally as an "index" to this
|
||||
* value the value returned by this method may not be identical to the
|
||||
* value set using setVolumeAdjustment().
|
||||
*
|
||||
* This defaults to returning the value for the master volume channel if
|
||||
* available and returns 0 if the specified channel does not exist.
|
||||
*
|
||||
* \see setVolumeAdjustment()
|
||||
* \see volumeAdjustmentIndex()
|
||||
*/
|
||||
float volumeAdjustment(ChannelType type = MasterVolume) const;
|
||||
|
||||
/*!
|
||||
* Set the relative volume adjustment in decibels to \a adjustment.
|
||||
*
|
||||
* By default this sets the value for the master volume.
|
||||
*
|
||||
* \note Because this is actually stored internally as an "index" to this
|
||||
* value the value set by this method may not be identical to the one
|
||||
* returned by volumeAdjustment().
|
||||
*
|
||||
* \see setVolumeAdjustment()
|
||||
* \see volumeAdjustmentIndex()
|
||||
*/
|
||||
void setVolumeAdjustment(float adjustment, ChannelType type = MasterVolume);
|
||||
|
||||
/*!
|
||||
* Returns the peak volume (represented as a length and a string of bits).
|
||||
*
|
||||
* This defaults to returning the value for the master volume channel if
|
||||
* available and returns 0 if the specified channel does not exist.
|
||||
*
|
||||
* \see setPeakVolume()
|
||||
*/
|
||||
PeakVolume peakVolume(ChannelType type = MasterVolume) const;
|
||||
|
||||
/*!
|
||||
* Sets the peak volume to \a peak.
|
||||
*
|
||||
* By default this sets the value for the master volume.
|
||||
*
|
||||
* \see peakVolume()
|
||||
*/
|
||||
void setPeakVolume(const PeakVolume &peak, ChannelType type = MasterVolume);
|
||||
|
||||
#else
|
||||
|
||||
// BIC: Combine each of the following pairs of functions (or maybe just
|
||||
// rework this junk altogether).
|
||||
|
||||
short volumeAdjustmentIndex(ChannelType type) const;
|
||||
short volumeAdjustmentIndex() const;
|
||||
|
||||
void setVolumeAdjustmentIndex(short index, ChannelType type);
|
||||
void setVolumeAdjustmentIndex(short index);
|
||||
|
||||
float volumeAdjustment(ChannelType type) const;
|
||||
float volumeAdjustment() const;
|
||||
|
||||
void setVolumeAdjustment(float adjustment, ChannelType type);
|
||||
void setVolumeAdjustment(float adjustment);
|
||||
|
||||
PeakVolume peakVolume(ChannelType type) const;
|
||||
PeakVolume peakVolume() const;
|
||||
|
||||
void setPeakVolume(const PeakVolume &peak, ChannelType type);
|
||||
void setPeakVolume(const PeakVolume &peak);
|
||||
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* Returns the identification for this frame.
|
||||
*/
|
||||
String identification() const;
|
||||
|
||||
/*!
|
||||
* Sets the identification of the frame to \a s. The string
|
||||
* is used to identify the situation and/or device where this
|
||||
* adjustment should apply.
|
||||
*/
|
||||
void setIdentification(const String &s);
|
||||
|
||||
protected:
|
||||
virtual void parseFields(const ByteVector &data);
|
||||
virtual ByteVector renderFields() const;
|
||||
|
||||
private:
|
||||
RelativeVolumeFrame(const ByteVector &data, Header *h);
|
||||
RelativeVolumeFrame(const RelativeVolumeFrame &);
|
||||
RelativeVolumeFrame &operator=(const RelativeVolumeFrame &);
|
||||
|
||||
class RelativeVolumeFramePrivate;
|
||||
RelativeVolumeFramePrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,429 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tbytevectorlist.h>
|
||||
#include <id3v2tag.h>
|
||||
#include "textidentificationframe.h"
|
||||
#include "tpropertymap.h"
|
||||
#include "id3v1genres.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class TextIdentificationFrame::TextIdentificationFramePrivate
|
||||
{
|
||||
public:
|
||||
TextIdentificationFramePrivate() : textEncoding(String::Latin1) {}
|
||||
String::Type textEncoding;
|
||||
StringList fieldList;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// TextIdentificationFrame public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TextIdentificationFrame::TextIdentificationFrame(const ByteVector &type, String::Type encoding) :
|
||||
Frame(type)
|
||||
{
|
||||
d = new TextIdentificationFramePrivate;
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data) :
|
||||
Frame(data)
|
||||
{
|
||||
d = new TextIdentificationFramePrivate;
|
||||
setData(data);
|
||||
}
|
||||
|
||||
TextIdentificationFrame *TextIdentificationFrame::createTIPLFrame(const PropertyMap &properties) // static
|
||||
{
|
||||
TextIdentificationFrame *frame = new TextIdentificationFrame("TIPL");
|
||||
StringList l;
|
||||
for(PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it){
|
||||
l.append(it->first);
|
||||
l.append(it->second.toString(",")); // comma-separated list of names
|
||||
}
|
||||
frame->setText(l);
|
||||
return frame;
|
||||
}
|
||||
|
||||
TextIdentificationFrame *TextIdentificationFrame::createTMCLFrame(const PropertyMap &properties) // static
|
||||
{
|
||||
TextIdentificationFrame *frame = new TextIdentificationFrame("TMCL");
|
||||
StringList l;
|
||||
for(PropertyMap::ConstIterator it = properties.begin(); it != properties.end(); ++it){
|
||||
if(!it->first.startsWith(instrumentPrefix)) // should not happen
|
||||
continue;
|
||||
l.append(it->first.substr(instrumentPrefix.size()));
|
||||
l.append(it->second.toString(","));
|
||||
}
|
||||
frame->setText(l);
|
||||
return frame;
|
||||
}
|
||||
|
||||
TextIdentificationFrame::~TextIdentificationFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void TextIdentificationFrame::setText(const StringList &l)
|
||||
{
|
||||
d->fieldList = l;
|
||||
}
|
||||
|
||||
void TextIdentificationFrame::setText(const String &s)
|
||||
{
|
||||
d->fieldList = s;
|
||||
}
|
||||
|
||||
String TextIdentificationFrame::toString() const
|
||||
{
|
||||
return d->fieldList.toString();
|
||||
}
|
||||
|
||||
StringList TextIdentificationFrame::fieldList() const
|
||||
{
|
||||
return d->fieldList;
|
||||
}
|
||||
|
||||
String::Type TextIdentificationFrame::textEncoding() const
|
||||
{
|
||||
return d->textEncoding;
|
||||
}
|
||||
|
||||
void TextIdentificationFrame::setTextEncoding(String::Type encoding)
|
||||
{
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
// array of allowed TIPL prefixes and their corresponding key value
|
||||
static const TagLib::uint involvedPeopleSize = 5;
|
||||
static const char* involvedPeople[][2] = {
|
||||
{"ARRANGER", "ARRANGER"},
|
||||
{"ENGINEER", "ENGINEER"},
|
||||
{"PRODUCER", "PRODUCER"},
|
||||
{"DJ-MIX", "DJMIXER"},
|
||||
{"MIX", "MIXER"},
|
||||
};
|
||||
|
||||
const KeyConversionMap &TextIdentificationFrame::involvedPeopleMap() // static
|
||||
{
|
||||
static KeyConversionMap m;
|
||||
if(m.isEmpty())
|
||||
for(uint i = 0; i < involvedPeopleSize; ++i)
|
||||
m.insert(involvedPeople[i][1], involvedPeople[i][0]);
|
||||
return m;
|
||||
}
|
||||
|
||||
PropertyMap TextIdentificationFrame::asProperties() const
|
||||
{
|
||||
if(frameID() == "TIPL")
|
||||
return makeTIPLProperties();
|
||||
if(frameID() == "TMCL")
|
||||
return makeTMCLProperties();
|
||||
PropertyMap map;
|
||||
String tagName = frameIDToKey(frameID());
|
||||
if(tagName.isNull()) {
|
||||
map.unsupportedData().append(frameID());
|
||||
return map;
|
||||
}
|
||||
StringList values = fieldList();
|
||||
if(tagName == "GENRE") {
|
||||
// Special case: Support ID3v1-style genre numbers. They are not officially supported in
|
||||
// ID3v2, however it seems that still a lot of programs use them.
|
||||
for(StringList::Iterator it = values.begin(); it != values.end(); ++it) {
|
||||
bool ok = false;
|
||||
int test = it->toInt(&ok); // test if the genre value is an integer
|
||||
if(ok)
|
||||
*it = ID3v1::genre(test);
|
||||
}
|
||||
} else if(tagName == "DATE") {
|
||||
for(StringList::Iterator it = values.begin(); it != values.end(); ++it) {
|
||||
// ID3v2 specifies ISO8601 timestamps which contain a 'T' as separator between date and time.
|
||||
// Since this is unusual in other formats, the T is removed.
|
||||
int tpos = it->find("T");
|
||||
if(tpos != -1)
|
||||
(*it)[tpos] = ' ';
|
||||
}
|
||||
}
|
||||
PropertyMap ret;
|
||||
ret.insert(tagName, values);
|
||||
return ret;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// TextIdentificationFrame protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TextIdentificationFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
// Don't try to parse invalid frames
|
||||
|
||||
if(data.size() < 2)
|
||||
return;
|
||||
|
||||
// read the string data type (the first byte of the field data)
|
||||
|
||||
d->textEncoding = String::Type(data[0]);
|
||||
|
||||
// split the byte array into chunks based on the string type (two byte delimiter
|
||||
// for unicode encodings)
|
||||
|
||||
int byteAlign = d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
|
||||
|
||||
// build a small counter to strip nulls off the end of the field
|
||||
|
||||
int dataLength = data.size() - 1;
|
||||
|
||||
while(dataLength > 0 && data[dataLength] == 0)
|
||||
dataLength--;
|
||||
|
||||
while(dataLength % byteAlign != 0)
|
||||
dataLength++;
|
||||
|
||||
ByteVectorList l = ByteVectorList::split(data.mid(1, dataLength), textDelimiter(d->textEncoding), byteAlign);
|
||||
|
||||
d->fieldList.clear();
|
||||
|
||||
// append those split values to the list and make sure that the new string's
|
||||
// type is the same specified for this frame
|
||||
|
||||
for(ByteVectorList::Iterator it = l.begin(); it != l.end(); it++) {
|
||||
if(!(*it).isEmpty()) {
|
||||
if(d->textEncoding == String::Latin1)
|
||||
d->fieldList.append(Tag::latin1StringHandler()->parse(*it));
|
||||
else
|
||||
d->fieldList.append(String(*it, d->textEncoding));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector TextIdentificationFrame::renderFields() const
|
||||
{
|
||||
String::Type encoding = checkTextEncoding(d->fieldList, d->textEncoding);
|
||||
|
||||
ByteVector v;
|
||||
|
||||
v.append(char(encoding));
|
||||
|
||||
for(StringList::ConstIterator it = d->fieldList.begin(); it != d->fieldList.end(); it++) {
|
||||
|
||||
// Since the field list is null delimited, if this is not the first
|
||||
// element in the list, append the appropriate delimiter for this
|
||||
// encoding.
|
||||
|
||||
if(it != d->fieldList.begin())
|
||||
v.append(textDelimiter(encoding));
|
||||
|
||||
v.append((*it).data(encoding));
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// TextIdentificationFrame private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TextIdentificationFrame::TextIdentificationFrame(const ByteVector &data, Header *h) : Frame(h)
|
||||
{
|
||||
d = new TextIdentificationFramePrivate;
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
|
||||
PropertyMap TextIdentificationFrame::makeTIPLProperties() const
|
||||
{
|
||||
PropertyMap map;
|
||||
if(fieldList().size() % 2 != 0){
|
||||
// according to the ID3 spec, TIPL must contain an even number of entries
|
||||
map.unsupportedData().append(frameID());
|
||||
return map;
|
||||
}
|
||||
StringList l = fieldList();
|
||||
for(StringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
|
||||
bool found = false;
|
||||
for(uint i = 0; i < involvedPeopleSize; ++i)
|
||||
if(*it == involvedPeople[i][0]) {
|
||||
map.insert(involvedPeople[i][1], (++it)->split(","));
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if(!found){
|
||||
// invalid involved role -> mark whole frame as unsupported in order to be consisten with writing
|
||||
map.clear();
|
||||
map.unsupportedData().append(frameID());
|
||||
return map;
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
PropertyMap TextIdentificationFrame::makeTMCLProperties() const
|
||||
{
|
||||
PropertyMap map;
|
||||
if(fieldList().size() % 2 != 0){
|
||||
// according to the ID3 spec, TMCL must contain an even number of entries
|
||||
map.unsupportedData().append(frameID());
|
||||
return map;
|
||||
}
|
||||
StringList l = fieldList();
|
||||
for(StringList::ConstIterator it = l.begin(); it != l.end(); ++it) {
|
||||
String instrument = it->upper();
|
||||
if(instrument.isNull()) {
|
||||
// instrument is not a valid key -> frame unsupported
|
||||
map.clear();
|
||||
map.unsupportedData().append(frameID());
|
||||
return map;
|
||||
}
|
||||
map.insert(L"PERFORMER:" + instrument, (++it)->split(","));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// UserTextIdentificationFrame public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
UserTextIdentificationFrame::UserTextIdentificationFrame(String::Type encoding) :
|
||||
TextIdentificationFrame("TXXX", encoding),
|
||||
d(0)
|
||||
{
|
||||
StringList l;
|
||||
l.append(String::null);
|
||||
l.append(String::null);
|
||||
setText(l);
|
||||
}
|
||||
|
||||
|
||||
UserTextIdentificationFrame::UserTextIdentificationFrame(const ByteVector &data) :
|
||||
TextIdentificationFrame(data)
|
||||
{
|
||||
checkFields();
|
||||
}
|
||||
|
||||
UserTextIdentificationFrame::UserTextIdentificationFrame(const String &description, const StringList &values, String::Type encoding) :
|
||||
TextIdentificationFrame("TXXX", encoding),
|
||||
d(0)
|
||||
{
|
||||
setDescription(description);
|
||||
setText(values);
|
||||
}
|
||||
|
||||
String UserTextIdentificationFrame::toString() const
|
||||
{
|
||||
return "[" + description() + "] " + fieldList().toString();
|
||||
}
|
||||
|
||||
String UserTextIdentificationFrame::description() const
|
||||
{
|
||||
return !TextIdentificationFrame::fieldList().isEmpty()
|
||||
? TextIdentificationFrame::fieldList().front()
|
||||
: String::null;
|
||||
}
|
||||
|
||||
StringList UserTextIdentificationFrame::fieldList() const
|
||||
{
|
||||
// TODO: remove this function
|
||||
|
||||
return TextIdentificationFrame::fieldList();
|
||||
}
|
||||
|
||||
void UserTextIdentificationFrame::setText(const String &text)
|
||||
{
|
||||
if(description().isEmpty())
|
||||
setDescription(String::null);
|
||||
|
||||
TextIdentificationFrame::setText(StringList(description()).append(text));
|
||||
}
|
||||
|
||||
void UserTextIdentificationFrame::setText(const StringList &fields)
|
||||
{
|
||||
if(description().isEmpty())
|
||||
setDescription(String::null);
|
||||
|
||||
TextIdentificationFrame::setText(StringList(description()).append(fields));
|
||||
}
|
||||
|
||||
void UserTextIdentificationFrame::setDescription(const String &s)
|
||||
{
|
||||
StringList l = fieldList();
|
||||
|
||||
if(l.isEmpty())
|
||||
l.append(s);
|
||||
else
|
||||
l[0] = s;
|
||||
|
||||
TextIdentificationFrame::setText(l);
|
||||
}
|
||||
|
||||
PropertyMap UserTextIdentificationFrame::asProperties() const
|
||||
{
|
||||
String tagName = description();
|
||||
|
||||
PropertyMap map;
|
||||
String key = tagName.upper();
|
||||
if(key.isNull()) // this frame's description is not a valid PropertyMap key -> add to unsupported list
|
||||
map.unsupportedData().append(L"TXXX/" + description());
|
||||
else {
|
||||
StringList v = fieldList();
|
||||
for(StringList::ConstIterator it = v.begin(); it != v.end(); ++it)
|
||||
if(*it != description())
|
||||
map.insert(key, *it);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
UserTextIdentificationFrame *UserTextIdentificationFrame::find(
|
||||
ID3v2::Tag *tag, const String &description) // static
|
||||
{
|
||||
FrameList l = tag->frameList("TXXX");
|
||||
for(FrameList::Iterator it = l.begin(); it != l.end(); ++it) {
|
||||
UserTextIdentificationFrame *f = dynamic_cast<UserTextIdentificationFrame *>(*it);
|
||||
if(f && f->description() == description)
|
||||
return f;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// UserTextIdentificationFrame private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
UserTextIdentificationFrame::UserTextIdentificationFrame(const ByteVector &data, Header *h) :
|
||||
TextIdentificationFrame(data, h)
|
||||
{
|
||||
checkFields();
|
||||
}
|
||||
|
||||
void UserTextIdentificationFrame::checkFields()
|
||||
{
|
||||
int fields = fieldList().size();
|
||||
|
||||
if(fields == 0)
|
||||
setDescription(String::null);
|
||||
if(fields <= 1)
|
||||
setText(String::null);
|
||||
}
|
|
@ -0,0 +1,313 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_TEXTIDENTIFICATIONFRAME_H
|
||||
#define TAGLIB_TEXTIDENTIFICATIONFRAME_H
|
||||
|
||||
#include "tstringlist.h"
|
||||
#include "tmap.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
#include "id3v2frame.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
class Tag;
|
||||
typedef Map<String, String> KeyConversionMap;
|
||||
|
||||
//! An ID3v2 text identification frame implementation
|
||||
|
||||
/*!
|
||||
* This is an implementation of the most common type of ID3v2 frame -- text
|
||||
* identification frames. There are a number of variations on this. Those
|
||||
* enumerated in the ID3v2.4 standard are:
|
||||
*
|
||||
* <ul>
|
||||
* <li><b>TALB</b> Album/Movie/Show title</li>
|
||||
* <li><b>TBPM</b> BPM (beats per minute)</li>
|
||||
* <li><b>TCOM</b> Composer</li>
|
||||
* <li><b>TCON</b> Content type</li>
|
||||
* <li><b>TCOP</b> Copyright message</li>
|
||||
* <li><b>TDEN</b> Encoding time</li>
|
||||
* <li><b>TDLY</b> Playlist delay</li>
|
||||
* <li><b>TDOR</b> Original release time</li>
|
||||
* <li><b>TDRC</b> Recording time</li>
|
||||
* <li><b>TDRL</b> Release time</li>
|
||||
* <li><b>TDTG</b> Tagging time</li>
|
||||
* <li><b>TENC</b> Encoded by</li>
|
||||
* <li><b>TEXT</b> Lyricist/Text writer</li>
|
||||
* <li><b>TFLT</b> File type</li>
|
||||
* <li><b>TIPL</b> Involved people list</li>
|
||||
* <li><b>TIT1</b> Content group description</li>
|
||||
* <li><b>TIT2</b> Title/songname/content description</li>
|
||||
* <li><b>TIT3</b> Subtitle/Description refinement</li>
|
||||
* <li><b>TKEY</b> Initial key</li>
|
||||
* <li><b>TLAN</b> Language(s)</li>
|
||||
* <li><b>TLEN</b> Length</li>
|
||||
* <li><b>TMCL</b> Musician credits list</li>
|
||||
* <li><b>TMED</b> Media type</li>
|
||||
* <li><b>TMOO</b> Mood</li>
|
||||
* <li><b>TOAL</b> Original album/movie/show title</li>
|
||||
* <li><b>TOFN</b> Original filename</li>
|
||||
* <li><b>TOLY</b> Original lyricist(s)/text writer(s)</li>
|
||||
* <li><b>TOPE</b> Original artist(s)/performer(s)</li>
|
||||
* <li><b>TOWN</b> File owner/licensee</li>
|
||||
* <li><b>TPE1</b> Lead performer(s)/Soloist(s)</li>
|
||||
* <li><b>TPE2</b> Band/orchestra/accompaniment</li>
|
||||
* <li><b>TPE3</b> Conductor/performer refinement</li>
|
||||
* <li><b>TPE4</b> Interpreted, remixed, or otherwise modified by</li>
|
||||
* <li><b>TPOS</b> Part of a set</li>
|
||||
* <li><b>TPRO</b> Produced notice</li>
|
||||
* <li><b>TPUB</b> Publisher</li>
|
||||
* <li><b>TRCK</b> Track number/Position in set</li>
|
||||
* <li><b>TRSN</b> Internet radio station name</li>
|
||||
* <li><b>TRSO</b> Internet radio station owner</li>
|
||||
* <li><b>TSOA</b> Album sort order</li>
|
||||
* <li><b>TSOP</b> Performer sort order</li>
|
||||
* <li><b>TSOT</b> Title sort order</li>
|
||||
* <li><b>TSRC</b> ISRC (international standard recording code)</li>
|
||||
* <li><b>TSSE</b> Software/Hardware and settings used for encoding</li>
|
||||
* <li><b>TSST</b> Set subtitle</li>
|
||||
* </ul>
|
||||
*
|
||||
* The ID3v2 Frames document gives a description of each of these formats
|
||||
* and the expected order of strings in each. ID3v2::Header::frameID() can
|
||||
* be used to determine the frame type.
|
||||
*
|
||||
* \note If non-Latin1 compatible strings are used with this class, even if
|
||||
* the text encoding is set to Latin1, the frame will be written using UTF8
|
||||
* (with the encoding flag appropriately set in the output).
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT TextIdentificationFrame : public Frame
|
||||
{
|
||||
friend class FrameFactory;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Construct an empty frame of type \a type. Uses \a encoding as the
|
||||
* default text encoding.
|
||||
*
|
||||
* \note In this case you must specify the text encoding as it
|
||||
* resolves the ambiguity between constructors.
|
||||
*
|
||||
* \note Please see the note in the class description regarding Latin1.
|
||||
*/
|
||||
TextIdentificationFrame(const ByteVector &type, String::Type encoding);
|
||||
|
||||
/*!
|
||||
* This is a dual purpose constructor. \a data can either be binary data
|
||||
* that should be parsed or (at a minimum) the frame ID.
|
||||
*/
|
||||
explicit TextIdentificationFrame(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* This is a special factory method to create a TIPL (involved people list)
|
||||
* frame from the given \a properties. Will parse key=[list of values] data
|
||||
* into the TIPL format as specified in the ID3 standard.
|
||||
*/
|
||||
static TextIdentificationFrame *createTIPLFrame(const PropertyMap &properties);
|
||||
|
||||
/*!
|
||||
* This is a special factory method to create a TMCL (musician credits list)
|
||||
* frame from the given \a properties. Will parse key=[list of values] data
|
||||
* into the TMCL format as specified in the ID3 standard, where key should be
|
||||
* of the form instrumentPrefix:instrument.
|
||||
*/
|
||||
static TextIdentificationFrame *createTMCLFrame(const PropertyMap &properties);
|
||||
/*!
|
||||
* Destroys this TextIdentificationFrame instance.
|
||||
*/
|
||||
virtual ~TextIdentificationFrame();
|
||||
|
||||
/*!
|
||||
* Text identification frames are a list of string fields.
|
||||
*
|
||||
* This function will accept either a StringList or a String (using the
|
||||
* StringList constructor that accepts a single String).
|
||||
*
|
||||
* \note This will not change the text encoding of the frame even if the
|
||||
* strings passed in are not of the same encoding. Please use
|
||||
* setEncoding(s.type()) if you wish to change the encoding of the frame.
|
||||
*/
|
||||
void setText(const StringList &l);
|
||||
|
||||
// Reimplementations.
|
||||
|
||||
virtual void setText(const String &s);
|
||||
virtual String toString() const;
|
||||
|
||||
/*!
|
||||
* Returns the text encoding that will be used in rendering this frame.
|
||||
* This defaults to the type that was either specified in the constructor
|
||||
* or read from the frame when parsed.
|
||||
*
|
||||
* \note Please see the note in the class description regarding Latin1.
|
||||
*
|
||||
* \see setTextEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
String::Type textEncoding() const;
|
||||
|
||||
/*!
|
||||
* Sets the text encoding to be used when rendering this frame to
|
||||
* \a encoding.
|
||||
*
|
||||
* \note Please see the note in the class description regarding Latin1.
|
||||
*
|
||||
* \see textEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
void setTextEncoding(String::Type encoding);
|
||||
|
||||
/*!
|
||||
* Returns a list of the strings in this frame.
|
||||
*/
|
||||
StringList fieldList() const;
|
||||
|
||||
/*!
|
||||
* Returns a KeyConversionMap mapping a role as it would be used in a PropertyMap
|
||||
* to the corresponding key used in a TIPL ID3 frame to describe that role.
|
||||
*/
|
||||
static const KeyConversionMap &involvedPeopleMap();
|
||||
|
||||
PropertyMap asProperties() const;
|
||||
|
||||
protected:
|
||||
// Reimplementations.
|
||||
|
||||
virtual void parseFields(const ByteVector &data);
|
||||
virtual ByteVector renderFields() const;
|
||||
|
||||
/*!
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
TextIdentificationFrame(const ByteVector &data, Header *h);
|
||||
|
||||
private:
|
||||
TextIdentificationFrame(const TextIdentificationFrame &);
|
||||
TextIdentificationFrame &operator=(const TextIdentificationFrame &);
|
||||
|
||||
/*!
|
||||
* Parses the special structure of a TIPL frame
|
||||
* Only the whitelisted roles "ARRANGER", "ENGINEER", "PRODUCER",
|
||||
* "DJMIXER" (ID3: "DJ-MIX") and "MIXER" (ID3: "MIX") are allowed.
|
||||
*/
|
||||
PropertyMap makeTIPLProperties() const;
|
||||
/*!
|
||||
* Parses the special structure of a TMCL frame.
|
||||
*/
|
||||
PropertyMap makeTMCLProperties() const;
|
||||
class TextIdentificationFramePrivate;
|
||||
TextIdentificationFramePrivate *d;
|
||||
};
|
||||
|
||||
/*!
|
||||
* This is a specialization of text identification frames that allows for
|
||||
* user defined entries. Each entry has a description in addition to the
|
||||
* normal list of fields that a text identification frame has.
|
||||
*
|
||||
* This description identifies the frame and must be unique.
|
||||
*/
|
||||
|
||||
//! An ID3v2 custom text identification frame implementationx
|
||||
|
||||
class TAGLIB_EXPORT UserTextIdentificationFrame : public TextIdentificationFrame
|
||||
{
|
||||
friend class FrameFactory;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Constructs an empty user defined text identification frame. For this to be
|
||||
* a useful frame both a description and text must be set.
|
||||
*/
|
||||
explicit UserTextIdentificationFrame(String::Type encoding = String::Latin1);
|
||||
|
||||
/*!
|
||||
* Creates a frame based on \a data.
|
||||
*/
|
||||
explicit UserTextIdentificationFrame(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Creates a user defined text identification frame with the given \a description
|
||||
* and \a values.
|
||||
*/
|
||||
UserTextIdentificationFrame(const String &description, const StringList &values, String::Type encoding = String::UTF8);
|
||||
|
||||
virtual String toString() const;
|
||||
|
||||
/*!
|
||||
* Returns the description for this frame.
|
||||
*/
|
||||
String description() const;
|
||||
|
||||
/*!
|
||||
* Sets the description of the frame to \a s. \a s must be unique. You can
|
||||
* check for the presence of another user defined text frame of the same type
|
||||
* using find() and testing for null.
|
||||
*/
|
||||
void setDescription(const String &s);
|
||||
|
||||
StringList fieldList() const;
|
||||
void setText(const String &text);
|
||||
void setText(const StringList &fields);
|
||||
|
||||
/*!
|
||||
* A UserTextIdentificationFrame is parsed into a PropertyMap as follows:
|
||||
* - the key is the frame's description, uppercased
|
||||
* - if the description contains '::', only the substring after that
|
||||
* separator is considered as key (compatibility with exfalso)
|
||||
* - if the above rules don't yield a valid key (e.g. containing non-ASCII
|
||||
* characters), the returned map will contain an entry "TXXX/<description>"
|
||||
* in its unsupportedData() list.
|
||||
* - The values will be copies of the fieldList().
|
||||
* - If the description() appears as value in fieldList(), it will be omitted
|
||||
* in the value list, in order to be compatible with TagLib which copies
|
||||
* the description() into the fieldList().
|
||||
*/
|
||||
PropertyMap asProperties() const;
|
||||
|
||||
/*!
|
||||
* Searches for the user defined text frame with the description \a description
|
||||
* in \a tag. This returns null if no matching frames were found.
|
||||
*/
|
||||
static UserTextIdentificationFrame *find(Tag *tag, const String &description);
|
||||
|
||||
private:
|
||||
UserTextIdentificationFrame(const ByteVector &data, Header *h);
|
||||
UserTextIdentificationFrame(const TextIdentificationFrame &);
|
||||
UserTextIdentificationFrame &operator=(const UserTextIdentificationFrame &);
|
||||
|
||||
void checkFields();
|
||||
|
||||
class UserTextIdentificationFramePrivate;
|
||||
UserTextIdentificationFramePrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,118 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tbytevectorlist.h>
|
||||
#include <tdebug.h>
|
||||
|
||||
#include "uniquefileidentifierframe.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class UniqueFileIdentifierFrame::UniqueFileIdentifierFramePrivate
|
||||
{
|
||||
public:
|
||||
String owner;
|
||||
ByteVector identifier;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
UniqueFileIdentifierFrame::UniqueFileIdentifierFrame(const ByteVector &data) :
|
||||
ID3v2::Frame(data)
|
||||
{
|
||||
d = new UniqueFileIdentifierFramePrivate;
|
||||
setData(data);
|
||||
}
|
||||
|
||||
UniqueFileIdentifierFrame::UniqueFileIdentifierFrame(const String &owner, const ByteVector &id) :
|
||||
ID3v2::Frame("UFID")
|
||||
{
|
||||
d = new UniqueFileIdentifierFramePrivate;
|
||||
d->owner = owner;
|
||||
d->identifier = id;
|
||||
}
|
||||
|
||||
UniqueFileIdentifierFrame::~UniqueFileIdentifierFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String UniqueFileIdentifierFrame::owner() const
|
||||
{
|
||||
return d->owner;
|
||||
}
|
||||
|
||||
ByteVector UniqueFileIdentifierFrame::identifier() const
|
||||
{
|
||||
return d->identifier;
|
||||
}
|
||||
|
||||
void UniqueFileIdentifierFrame::setOwner(const String &s)
|
||||
{
|
||||
d->owner = s;
|
||||
}
|
||||
|
||||
void UniqueFileIdentifierFrame::setIdentifier(const ByteVector &v)
|
||||
{
|
||||
d->identifier = v;
|
||||
}
|
||||
|
||||
String UniqueFileIdentifierFrame::toString() const
|
||||
{
|
||||
return String::null;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_UNIQUEFILEIDENTIFIERFRAME
|
||||
#define TAGLIB_UNIQUEFILEIDENTIFIERFRAME
|
||||
|
||||
#include "id3v2frame.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
/*!
|
||||
* This is an implementation of ID3v2 unique file identifier frames. This
|
||||
* frame is used to identify the file in an arbitrary database identified
|
||||
* by the owner field.
|
||||
*/
|
||||
|
||||
//! An implementation of ID3v2 unique identifier frames
|
||||
|
||||
class TAGLIB_EXPORT UniqueFileIdentifierFrame : public ID3v2::Frame
|
||||
{
|
||||
friend class FrameFactory;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Creates a uniqe file identifier frame based on \a data.
|
||||
*/
|
||||
UniqueFileIdentifierFrame(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Creates a unique file identifier frame with the owner \a owner and
|
||||
* the identification \a id.
|
||||
*/
|
||||
UniqueFileIdentifierFrame(const String &owner, const ByteVector &id);
|
||||
|
||||
/*!
|
||||
* Destroys the frame.
|
||||
*/
|
||||
~UniqueFileIdentifierFrame();
|
||||
|
||||
/*!
|
||||
* Returns the owner for the frame; essentially this is the key for
|
||||
* determining which identification scheme this key belongs to. This
|
||||
* will usually either be an email address or URL for the person or tool
|
||||
* used to create the unique identifier.
|
||||
*
|
||||
* \see setOwner()
|
||||
*/
|
||||
String owner() const;
|
||||
|
||||
/*!
|
||||
* Returns the unique identifier. Though sometimes this is a text string
|
||||
* it also may be binary data and as much should be assumed when handling
|
||||
* it.
|
||||
*/
|
||||
ByteVector identifier() const;
|
||||
|
||||
/*!
|
||||
* Sets the owner of the identification scheme to \a s.
|
||||
*
|
||||
* \see owner()
|
||||
*/
|
||||
void setOwner(const String &s);
|
||||
|
||||
/*!
|
||||
* Sets the unique file identifier to \a v.
|
||||
*
|
||||
* \see identifier()
|
||||
*/
|
||||
void setIdentifier(const ByteVector &v);
|
||||
|
||||
virtual String toString() const;
|
||||
|
||||
protected:
|
||||
virtual void parseFields(const ByteVector &data);
|
||||
virtual ByteVector renderFields() const;
|
||||
|
||||
private:
|
||||
UniqueFileIdentifierFrame(const UniqueFileIdentifierFrame &);
|
||||
UniqueFileIdentifierFrame &operator=(const UniqueFileIdentifierFrame &);
|
||||
|
||||
UniqueFileIdentifierFrame(const ByteVector &data, Header *h);
|
||||
|
||||
class UniqueFileIdentifierFramePrivate;
|
||||
UniqueFileIdentifierFramePrivate *d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,84 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include "unknownframe.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class UnknownFrame::UnknownFramePrivate
|
||||
{
|
||||
public:
|
||||
ByteVector fieldData;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
UnknownFrame::UnknownFrame(const ByteVector &data) : Frame(data)
|
||||
{
|
||||
d = new UnknownFramePrivate;
|
||||
setData(data);
|
||||
}
|
||||
|
||||
UnknownFrame::~UnknownFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String UnknownFrame::toString() const
|
||||
{
|
||||
return String::null;
|
||||
}
|
||||
|
||||
ByteVector UnknownFrame::data() const
|
||||
{
|
||||
return d->fieldData;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void UnknownFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
d->fieldData = data;
|
||||
}
|
||||
|
||||
ByteVector UnknownFrame::renderFields() const
|
||||
{
|
||||
return d->fieldData;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
UnknownFrame::UnknownFrame(const ByteVector &data, Header *h) : Frame(h)
|
||||
{
|
||||
d = new UnknownFramePrivate;
|
||||
parseFields(fieldData(data));
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_UNKNOWNFRAME_H
|
||||
#define TAGLIB_UNKNOWNFRAME_H
|
||||
|
||||
#include "id3v2frame.h"
|
||||
#include "taglib_export.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! A frame type \e unknown to TagLib.
|
||||
|
||||
/*!
|
||||
* This class represents a frame type not known (or more often simply
|
||||
* unimplemented) in TagLib. This is here provide a basic API for
|
||||
* manipulating the binary data of unknown frames and to provide a means
|
||||
* of rendering such \e unknown frames.
|
||||
*
|
||||
* Please note that a cleaner way of handling frame types that TagLib
|
||||
* does not understand is to subclass ID3v2::Frame and ID3v2::FrameFactory
|
||||
* to have your frame type supported through the standard ID3v2 mechanism.
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT UnknownFrame : public Frame
|
||||
{
|
||||
friend class FrameFactory;
|
||||
|
||||
public:
|
||||
UnknownFrame(const ByteVector &data);
|
||||
virtual ~UnknownFrame();
|
||||
|
||||
virtual String toString() const;
|
||||
|
||||
/*!
|
||||
* Returns the field data (everything but the header) for this frame.
|
||||
*/
|
||||
ByteVector data() const;
|
||||
|
||||
protected:
|
||||
virtual void parseFields(const ByteVector &data);
|
||||
virtual ByteVector renderFields() const;
|
||||
|
||||
private:
|
||||
UnknownFrame(const ByteVector &data, Header *h);
|
||||
UnknownFrame(const UnknownFrame &);
|
||||
UnknownFrame &operator=(const UnknownFrame &);
|
||||
|
||||
class UnknownFramePrivate;
|
||||
UnknownFramePrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,193 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
copyright : (C) 2006 by Urs Fleisch
|
||||
email : ufleisch@users.sourceforge.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include "unsynchronizedlyricsframe.h"
|
||||
#include <tbytevectorlist.h>
|
||||
#include <id3v2tag.h>
|
||||
#include <tdebug.h>
|
||||
#include <tpropertymap.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class UnsynchronizedLyricsFrame::UnsynchronizedLyricsFramePrivate
|
||||
{
|
||||
public:
|
||||
UnsynchronizedLyricsFramePrivate() : textEncoding(String::Latin1) {}
|
||||
String::Type textEncoding;
|
||||
ByteVector language;
|
||||
String description;
|
||||
String text;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(String::Type encoding) :
|
||||
Frame("USLT")
|
||||
{
|
||||
d = new UnsynchronizedLyricsFramePrivate;
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(const ByteVector &data) :
|
||||
Frame(data)
|
||||
{
|
||||
d = new UnsynchronizedLyricsFramePrivate;
|
||||
setData(data);
|
||||
}
|
||||
|
||||
UnsynchronizedLyricsFrame::~UnsynchronizedLyricsFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String UnsynchronizedLyricsFrame::toString() const
|
||||
{
|
||||
return d->text;
|
||||
}
|
||||
|
||||
ByteVector UnsynchronizedLyricsFrame::language() const
|
||||
{
|
||||
return d->language;
|
||||
}
|
||||
|
||||
String UnsynchronizedLyricsFrame::description() const
|
||||
{
|
||||
return d->description;
|
||||
}
|
||||
|
||||
String UnsynchronizedLyricsFrame::text() const
|
||||
{
|
||||
return d->text;
|
||||
}
|
||||
|
||||
void UnsynchronizedLyricsFrame::setLanguage(const ByteVector &languageEncoding)
|
||||
{
|
||||
d->language = languageEncoding.mid(0, 3);
|
||||
}
|
||||
|
||||
void UnsynchronizedLyricsFrame::setDescription(const String &s)
|
||||
{
|
||||
d->description = s;
|
||||
}
|
||||
|
||||
void UnsynchronizedLyricsFrame::setText(const String &s)
|
||||
{
|
||||
d->text = s;
|
||||
}
|
||||
|
||||
|
||||
String::Type UnsynchronizedLyricsFrame::textEncoding() const
|
||||
{
|
||||
return d->textEncoding;
|
||||
}
|
||||
|
||||
void UnsynchronizedLyricsFrame::setTextEncoding(String::Type encoding)
|
||||
{
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
PropertyMap UnsynchronizedLyricsFrame::asProperties() const
|
||||
{
|
||||
PropertyMap map;
|
||||
String key = description().upper();
|
||||
if(key.isEmpty() || key.upper() == "LYRICS")
|
||||
map.insert("LYRICS", text());
|
||||
else if(key.isNull())
|
||||
map.unsupportedData().append(L"USLT/" + description());
|
||||
else
|
||||
map.insert("LYRICS:" + key, text());
|
||||
return map;
|
||||
}
|
||||
|
||||
UnsynchronizedLyricsFrame *UnsynchronizedLyricsFrame::findByDescription(const ID3v2::Tag *tag, const String &d) // static
|
||||
{
|
||||
ID3v2::FrameList lyrics = tag->frameList("USLT");
|
||||
|
||||
for(ID3v2::FrameList::ConstIterator it = lyrics.begin(); it != lyrics.end(); ++it){
|
||||
UnsynchronizedLyricsFrame *frame = dynamic_cast<UnsynchronizedLyricsFrame *>(*it);
|
||||
if(frame && frame->description() == d)
|
||||
return frame;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void UnsynchronizedLyricsFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
if(data.size() < 5) {
|
||||
debug("An unsynchronized lyrics frame must contain at least 5 bytes.");
|
||||
return;
|
||||
}
|
||||
|
||||
d->textEncoding = String::Type(data[0]);
|
||||
d->language = data.mid(1, 3);
|
||||
|
||||
int byteAlign
|
||||
= d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8 ? 1 : 2;
|
||||
|
||||
ByteVectorList l =
|
||||
ByteVectorList::split(data.mid(4), textDelimiter(d->textEncoding), byteAlign, 2);
|
||||
|
||||
if(l.size() == 2) {
|
||||
if(d->textEncoding == String::Latin1) {
|
||||
d->description = Tag::latin1StringHandler()->parse(l.front());
|
||||
d->text = Tag::latin1StringHandler()->parse(l.back());
|
||||
} else {
|
||||
d->description = String(l.front(), d->textEncoding);
|
||||
d->text = String(l.back(), d->textEncoding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ByteVector UnsynchronizedLyricsFrame::renderFields() const
|
||||
{
|
||||
ByteVector v;
|
||||
|
||||
v.append(char(d->textEncoding));
|
||||
v.append(d->language.size() == 3 ? d->language : "XXX");
|
||||
v.append(d->description.data(d->textEncoding));
|
||||
v.append(textDelimiter(d->textEncoding));
|
||||
v.append(d->text.data(d->textEncoding));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
UnsynchronizedLyricsFrame::UnsynchronizedLyricsFrame(const ByteVector &data, Header *h)
|
||||
: Frame(h)
|
||||
{
|
||||
d = new UnsynchronizedLyricsFramePrivate();
|
||||
parseFields(fieldData(data));
|
||||
}
|
|
@ -0,0 +1,179 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
copyright : (C) 2006 by Urs Fleisch
|
||||
email : ufleisch@users.sourceforge.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_UNSYNCHRONIZEDLYRICSFRAME_H
|
||||
#define TAGLIB_UNSYNCHRONIZEDLYRICSFRAME_H
|
||||
|
||||
#include "id3v2frame.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! ID3v2 unsynchronized lyrics frame
|
||||
/*!
|
||||
* An implementation of ID3v2 unsynchronized lyrics.
|
||||
*/
|
||||
class TAGLIB_EXPORT UnsynchronizedLyricsFrame : public Frame
|
||||
{
|
||||
friend class FrameFactory;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Construct an empty unsynchronized lyrics frame that will use the text encoding
|
||||
* \a encoding.
|
||||
*/
|
||||
explicit UnsynchronizedLyricsFrame(String::Type encoding = String::Latin1);
|
||||
|
||||
/*!
|
||||
* Construct a unsynchronized lyrics frame based on the data in \a data.
|
||||
*/
|
||||
explicit UnsynchronizedLyricsFrame(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Destroys this UnsynchronizedLyricsFrame instance.
|
||||
*/
|
||||
virtual ~UnsynchronizedLyricsFrame();
|
||||
|
||||
/*!
|
||||
* Returns the text of this unsynchronized lyrics frame.
|
||||
*
|
||||
* \see text()
|
||||
*/
|
||||
virtual String toString() const;
|
||||
|
||||
/*!
|
||||
* Returns the language encoding as a 3 byte encoding as specified by
|
||||
* <a href="http://en.wikipedia.org/wiki/ISO_639">ISO-639-2</a>.
|
||||
*
|
||||
* \note Most taggers simply ignore this value.
|
||||
*
|
||||
* \see setLanguage()
|
||||
*/
|
||||
ByteVector language() const;
|
||||
|
||||
/*!
|
||||
* Returns the description of this unsynchronized lyrics frame.
|
||||
*
|
||||
* \note Most taggers simply ignore this value.
|
||||
*
|
||||
* \see setDescription()
|
||||
*/
|
||||
String description() const;
|
||||
|
||||
/*!
|
||||
* Returns the text of this unsynchronized lyrics frame.
|
||||
*
|
||||
* \see setText()
|
||||
*/
|
||||
String text() const;
|
||||
|
||||
/*!
|
||||
* Set the language using the 3 byte language code from
|
||||
* <a href="http://en.wikipedia.org/wiki/ISO_639">ISO-639-2</a> to
|
||||
* \a languageCode.
|
||||
*
|
||||
* \see language()
|
||||
*/
|
||||
void setLanguage(const ByteVector &languageCode);
|
||||
|
||||
/*!
|
||||
* Sets the description of the unsynchronized lyrics frame to \a s.
|
||||
*
|
||||
* \see decription()
|
||||
*/
|
||||
void setDescription(const String &s);
|
||||
|
||||
/*!
|
||||
* Sets the text portion of the unsynchronized lyrics frame to \a s.
|
||||
*
|
||||
* \see text()
|
||||
*/
|
||||
virtual void setText(const String &s);
|
||||
|
||||
/*!
|
||||
* Returns the text encoding that will be used in rendering this frame.
|
||||
* This defaults to the type that was either specified in the constructor
|
||||
* or read from the frame when parsed.
|
||||
*
|
||||
* \see setTextEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
String::Type textEncoding() const;
|
||||
|
||||
/*!
|
||||
* Sets the text encoding to be used when rendering this frame to
|
||||
* \a encoding.
|
||||
*
|
||||
* \see textEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
void setTextEncoding(String::Type encoding);
|
||||
|
||||
|
||||
/*! Parses this frame as PropertyMap with a single key.
|
||||
* - if description() is empty or "LYRICS", the key will be "LYRICS"
|
||||
* - if description() is not a valid PropertyMap key, the frame will be
|
||||
* marked unsupported by an entry "USLT/<description>" in the unsupportedData()
|
||||
* attribute of the returned map.
|
||||
* - otherwise, the key will be "LYRICS:<description>"
|
||||
* - The single value will be the frame's text().
|
||||
* Note that currently the language() field is not supported by the PropertyMap
|
||||
* interface.
|
||||
*/
|
||||
PropertyMap asProperties() const;
|
||||
|
||||
/*!
|
||||
* LyricsFrames each have a unique description. This searches for a lyrics
|
||||
* frame with the decription \a d and returns a pointer to it. If no
|
||||
* frame is found that matches the given description null is returned.
|
||||
*
|
||||
* \see description()
|
||||
*/
|
||||
static UnsynchronizedLyricsFrame *findByDescription(const Tag *tag, const String &d);
|
||||
|
||||
protected:
|
||||
// Reimplementations.
|
||||
|
||||
virtual void parseFields(const ByteVector &data);
|
||||
virtual ByteVector renderFields() const;
|
||||
|
||||
private:
|
||||
/*!
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
UnsynchronizedLyricsFrame(const ByteVector &data, Header *h);
|
||||
UnsynchronizedLyricsFrame(const UnsynchronizedLyricsFrame &);
|
||||
UnsynchronizedLyricsFrame &operator=(const UnsynchronizedLyricsFrame &);
|
||||
|
||||
class UnsynchronizedLyricsFramePrivate;
|
||||
UnsynchronizedLyricsFramePrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,230 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
copyright : (C) 2006 by Urs Fleisch
|
||||
email : ufleisch@users.sourceforge.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include "urllinkframe.h"
|
||||
#include "id3v2tag.h"
|
||||
#include <tdebug.h>
|
||||
#include <tstringlist.h>
|
||||
#include <tpropertymap.h>
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class UrlLinkFrame::UrlLinkFramePrivate
|
||||
{
|
||||
public:
|
||||
String url;
|
||||
};
|
||||
|
||||
class UserUrlLinkFrame::UserUrlLinkFramePrivate
|
||||
{
|
||||
public:
|
||||
UserUrlLinkFramePrivate() : textEncoding(String::Latin1) {}
|
||||
String::Type textEncoding;
|
||||
String description;
|
||||
};
|
||||
|
||||
UrlLinkFrame::UrlLinkFrame(const ByteVector &data) :
|
||||
Frame(data)
|
||||
{
|
||||
d = new UrlLinkFramePrivate;
|
||||
setData(data);
|
||||
}
|
||||
|
||||
UrlLinkFrame::~UrlLinkFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void UrlLinkFrame::setUrl(const String &s)
|
||||
{
|
||||
d->url = s;
|
||||
}
|
||||
|
||||
String UrlLinkFrame::url() const
|
||||
{
|
||||
return d->url;
|
||||
}
|
||||
|
||||
void UrlLinkFrame::setText(const String &s)
|
||||
{
|
||||
setUrl(s);
|
||||
}
|
||||
|
||||
String UrlLinkFrame::toString() const
|
||||
{
|
||||
return url();
|
||||
}
|
||||
|
||||
PropertyMap UrlLinkFrame::asProperties() const
|
||||
{
|
||||
String key = frameIDToKey(frameID());
|
||||
PropertyMap map;
|
||||
if(key.isNull())
|
||||
// unknown W*** frame - this normally shouldn't happen
|
||||
map.unsupportedData().append(frameID());
|
||||
else
|
||||
map.insert(key, url());
|
||||
return map;
|
||||
}
|
||||
|
||||
void UrlLinkFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
d->url = String(data);
|
||||
}
|
||||
|
||||
ByteVector UrlLinkFrame::renderFields() const
|
||||
{
|
||||
return d->url.data(String::Latin1);
|
||||
}
|
||||
|
||||
UrlLinkFrame::UrlLinkFrame(const ByteVector &data, Header *h) : Frame(h)
|
||||
{
|
||||
d = new UrlLinkFramePrivate;
|
||||
parseFields(fieldData(data));
|
||||
}
|
||||
|
||||
|
||||
UserUrlLinkFrame::UserUrlLinkFrame(String::Type encoding) :
|
||||
UrlLinkFrame("WXXX")
|
||||
{
|
||||
d = new UserUrlLinkFramePrivate;
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
UserUrlLinkFrame::UserUrlLinkFrame(const ByteVector &data) :
|
||||
UrlLinkFrame(data)
|
||||
{
|
||||
d = new UserUrlLinkFramePrivate;
|
||||
setData(data);
|
||||
}
|
||||
|
||||
UserUrlLinkFrame::~UserUrlLinkFrame()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
String UserUrlLinkFrame::toString() const
|
||||
{
|
||||
return "[" + description() + "] " + url();
|
||||
}
|
||||
|
||||
String::Type UserUrlLinkFrame::textEncoding() const
|
||||
{
|
||||
return d->textEncoding;
|
||||
}
|
||||
|
||||
void UserUrlLinkFrame::setTextEncoding(String::Type encoding)
|
||||
{
|
||||
d->textEncoding = encoding;
|
||||
}
|
||||
|
||||
String UserUrlLinkFrame::description() const
|
||||
{
|
||||
return d->description;
|
||||
}
|
||||
|
||||
void UserUrlLinkFrame::setDescription(const String &s)
|
||||
{
|
||||
d->description = s;
|
||||
}
|
||||
|
||||
PropertyMap UserUrlLinkFrame::asProperties() const
|
||||
{
|
||||
PropertyMap map;
|
||||
String key = description().upper();
|
||||
if(key.isEmpty() || key.upper() == "URL")
|
||||
map.insert("URL", url());
|
||||
else if(key.isNull())
|
||||
map.unsupportedData().append(L"WXXX/" + description());
|
||||
else
|
||||
map.insert("URL:" + key, url());
|
||||
return map;
|
||||
}
|
||||
|
||||
UserUrlLinkFrame *UserUrlLinkFrame::find(ID3v2::Tag *tag, const String &description) // static
|
||||
{
|
||||
FrameList l = tag->frameList("WXXX");
|
||||
for(FrameList::Iterator it = l.begin(); it != l.end(); ++it) {
|
||||
UserUrlLinkFrame *f = dynamic_cast<UserUrlLinkFrame *>(*it);
|
||||
if(f && f->description() == description)
|
||||
return f;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void UserUrlLinkFrame::parseFields(const ByteVector &data)
|
||||
{
|
||||
if(data.size() < 2) {
|
||||
debug("A user URL link frame must contain at least 2 bytes.");
|
||||
return;
|
||||
}
|
||||
|
||||
int pos = 0;
|
||||
|
||||
d->textEncoding = String::Type(data[0]);
|
||||
pos += 1;
|
||||
|
||||
if(d->textEncoding == String::Latin1 || d->textEncoding == String::UTF8) {
|
||||
int offset = data.find(textDelimiter(d->textEncoding), pos);
|
||||
if(offset < pos)
|
||||
return;
|
||||
|
||||
d->description = String(data.mid(pos, offset - pos), d->textEncoding);
|
||||
pos = offset + 1;
|
||||
}
|
||||
else {
|
||||
int len = data.mid(pos).find(textDelimiter(d->textEncoding), 0, 2);
|
||||
if(len < 0)
|
||||
return;
|
||||
|
||||
d->description = String(data.mid(pos, len), d->textEncoding);
|
||||
pos += len + 2;
|
||||
}
|
||||
|
||||
setUrl(String(data.mid(pos)));
|
||||
}
|
||||
|
||||
ByteVector UserUrlLinkFrame::renderFields() const
|
||||
{
|
||||
ByteVector v;
|
||||
|
||||
String::Type encoding = checkTextEncoding(d->description, d->textEncoding);
|
||||
|
||||
v.append(char(encoding));
|
||||
v.append(d->description.data(encoding));
|
||||
v.append(textDelimiter(encoding));
|
||||
v.append(url().data(String::Latin1));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
UserUrlLinkFrame::UserUrlLinkFrame(const ByteVector &data, Header *h) : UrlLinkFrame(data, h)
|
||||
{
|
||||
d = new UserUrlLinkFramePrivate;
|
||||
parseFields(fieldData(data));
|
||||
}
|
|
@ -0,0 +1,189 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
copyright : (C) 2006 by Urs Fleisch
|
||||
email : ufleisch@users.sourceforge.net
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_URLLINKFRAME_H
|
||||
#define TAGLIB_URLLINKFRAME_H
|
||||
|
||||
#include "id3v2frame.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! ID3v2 URL frame
|
||||
/*!
|
||||
* An implementation of ID3v2 URL link frames.
|
||||
*/
|
||||
class TAGLIB_EXPORT UrlLinkFrame : public Frame
|
||||
{
|
||||
friend class FrameFactory;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* This is a dual purpose constructor. \a data can either be binary data
|
||||
* that should be parsed or (at a minimum) the frame ID.
|
||||
*/
|
||||
explicit UrlLinkFrame(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Destroys this UrlLinkFrame instance.
|
||||
*/
|
||||
virtual ~UrlLinkFrame();
|
||||
|
||||
/*!
|
||||
* Returns the URL.
|
||||
*/
|
||||
virtual String url() const;
|
||||
|
||||
/*!
|
||||
* Sets the URL to \a s.
|
||||
*/
|
||||
virtual void setUrl(const String &s);
|
||||
|
||||
// Reimplementations.
|
||||
|
||||
virtual void setText(const String &s);
|
||||
virtual String toString() const;
|
||||
PropertyMap asProperties() const;
|
||||
|
||||
protected:
|
||||
virtual void parseFields(const ByteVector &data);
|
||||
virtual ByteVector renderFields() const;
|
||||
|
||||
/*!
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
UrlLinkFrame(const ByteVector &data, Header *h);
|
||||
|
||||
private:
|
||||
UrlLinkFrame(const UrlLinkFrame &);
|
||||
UrlLinkFrame &operator=(const UrlLinkFrame &);
|
||||
|
||||
class UrlLinkFramePrivate;
|
||||
UrlLinkFramePrivate *d;
|
||||
};
|
||||
|
||||
//! ID3v2 User defined URL frame
|
||||
|
||||
/*!
|
||||
* This is a specialization of URL link frames that allows for
|
||||
* user defined entries. Each entry has a description in addition to the
|
||||
* normal list of fields that a URL link frame has.
|
||||
*
|
||||
* This description identifies the frame and must be unique.
|
||||
*/
|
||||
class TAGLIB_EXPORT UserUrlLinkFrame : public UrlLinkFrame
|
||||
{
|
||||
friend class FrameFactory;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Constructs an empty user defined URL link frame. For this to be
|
||||
* a useful frame both a description and text must be set.
|
||||
*/
|
||||
explicit UserUrlLinkFrame(String::Type encoding = String::Latin1);
|
||||
|
||||
/*!
|
||||
* This is a dual purpose constructor. \a data can either be binary data
|
||||
* that should be parsed or (at a minimum) the frame ID.
|
||||
*/
|
||||
explicit UserUrlLinkFrame(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Destroys this UserUrlLinkFrame instance.
|
||||
*/
|
||||
virtual ~UserUrlLinkFrame();
|
||||
|
||||
// Reimplementations.
|
||||
|
||||
virtual String toString() const;
|
||||
|
||||
/*!
|
||||
* Returns the text encoding that will be used in rendering this frame.
|
||||
* This defaults to the type that was either specified in the constructor
|
||||
* or read from the frame when parsed.
|
||||
*
|
||||
* \see setTextEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
String::Type textEncoding() const;
|
||||
|
||||
/*!
|
||||
* Sets the text encoding to be used when rendering this frame to
|
||||
* \a encoding.
|
||||
*
|
||||
* \see textEncoding()
|
||||
* \see render()
|
||||
*/
|
||||
void setTextEncoding(String::Type encoding);
|
||||
|
||||
/*!
|
||||
* Returns the description for this frame.
|
||||
*/
|
||||
String description() const;
|
||||
|
||||
/*!
|
||||
* Sets the description of the frame to \a s. \a s must be unique.
|
||||
*/
|
||||
void setDescription(const String &s);
|
||||
|
||||
/*!
|
||||
* Parses the UserUrlLinkFrame as PropertyMap. The description() is taken as key,
|
||||
* and the URL as single value.
|
||||
* - if description() is empty, the key will be "URL".
|
||||
* - otherwise, if description() is not a valid key (e.g. containing non-ASCII
|
||||
* characters), the returned map will contain an entry "WXXX/<description>"
|
||||
* in its unsupportedData() list.
|
||||
*/
|
||||
PropertyMap asProperties() const;
|
||||
|
||||
/*!
|
||||
* Searches for the user defined url frame with the description \a description
|
||||
* in \a tag. This returns null if no matching frames were found.
|
||||
*/
|
||||
static UserUrlLinkFrame *find(Tag *tag, const String &description);
|
||||
|
||||
protected:
|
||||
virtual void parseFields(const ByteVector &data);
|
||||
virtual ByteVector renderFields() const;
|
||||
|
||||
/*!
|
||||
* The constructor used by the FrameFactory.
|
||||
*/
|
||||
UserUrlLinkFrame(const ByteVector &data, Header *h);
|
||||
|
||||
private:
|
||||
UserUrlLinkFrame(const UserUrlLinkFrame &);
|
||||
UserUrlLinkFrame &operator=(const UserUrlLinkFrame &);
|
||||
|
||||
class UserUrlLinkFramePrivate;
|
||||
UserUrlLinkFramePrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,733 @@
|
|||
|
||||
Informal standard M. Nilsson
|
||||
Document: id3v2.4.0-structure.txt 16 September 2001
|
||||
|
||||
|
||||
ID3 tag version 2.4.0 - Main Structure
|
||||
|
||||
Status of this document
|
||||
|
||||
This document is an informal standard and replaces the ID3v2.3.0
|
||||
standard [ID3v2]. A formal standard will use another revision number
|
||||
even if the content is identical to document. The contents in this
|
||||
document may change for clarifications but never for added or altered
|
||||
functionallity.
|
||||
|
||||
Distribution of this document is unlimited.
|
||||
|
||||
|
||||
Abstract
|
||||
|
||||
This document describes the main structure of ID3v2.4.0, which is a
|
||||
revised version of the ID3v2 informal standard [ID3v2] version
|
||||
2.3.0. The ID3v2 offers a flexible way of storing audio meta
|
||||
information within the audio file itself. The information may be
|
||||
technical information, such as equalisation curves, as well as
|
||||
title, performer, copyright etc.
|
||||
|
||||
ID3v2.4.0 is meant to be as close as possible to ID3v2.3.0 in order
|
||||
to allow for implementations to be revised as easily as possible.
|
||||
|
||||
|
||||
1. Table of contents
|
||||
|
||||
Status of this document
|
||||
Abstract
|
||||
1. Table of contents
|
||||
2. Conventions in this document
|
||||
2. Standard overview
|
||||
3. ID3v2 overview
|
||||
3.1. ID3v2 header
|
||||
3.2. ID3v2 extended header
|
||||
3.3. Padding
|
||||
3.4. ID3v2 footer
|
||||
4. ID3v2 frames overview
|
||||
4.1. Frame header flags
|
||||
4.1.1. Frame status flags
|
||||
4.1.2. Frame format flags
|
||||
5. Tag location
|
||||
6. Unsynchronisation
|
||||
6.1. The unsynchronisation scheme
|
||||
6.2. Synchsafe integers
|
||||
7. Copyright
|
||||
8. References
|
||||
9. Author's Address
|
||||
|
||||
|
||||
2. Conventions in this document
|
||||
|
||||
Text within "" is a text string exactly as it appears in a tag.
|
||||
Numbers preceded with $ are hexadecimal and numbers preceded with %
|
||||
are binary. $xx is used to indicate a byte with unknown content. %x
|
||||
is used to indicate a bit with unknown content. The most significant
|
||||
bit (MSB) of a byte is called 'bit 7' and the least significant bit
|
||||
(LSB) is called 'bit 0'.
|
||||
|
||||
A tag is the whole tag described in this document. A frame is a block
|
||||
of information in the tag. The tag consists of a header, frames and
|
||||
optional padding. A field is a piece of information; one value, a
|
||||
string etc. A numeric string is a string that consists of the
|
||||
characters "0123456789" only.
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
|
||||
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
|
||||
document are to be interpreted as described in RFC 2119 [KEYWORDS].
|
||||
|
||||
|
||||
3. ID3v2 overview
|
||||
|
||||
ID3v2 is a general tagging format for audio, which makes it possible
|
||||
to store meta data about the audio inside the audio file itself. The
|
||||
ID3 tag described in this document is mainly targeted at files
|
||||
encoded with MPEG-1/2 layer I, MPEG-1/2 layer II, MPEG-1/2 layer III
|
||||
and MPEG-2.5, but may work with other types of encoded audio or as a
|
||||
stand alone format for audio meta data.
|
||||
|
||||
ID3v2 is designed to be as flexible and expandable as possible to
|
||||
meet new meta information needs that might arise. To achieve that
|
||||
ID3v2 is constructed as a container for several information blocks,
|
||||
called frames, whose format need not be known to the software that
|
||||
encounters them. At the start of every frame is an unique and
|
||||
predefined identifier, a size descriptor that allows software to skip
|
||||
unknown frames and a flags field. The flags describes encoding
|
||||
details and if the frame should remain in the tag, should it be
|
||||
unknown to the software, if the file is altered.
|
||||
|
||||
The bitorder in ID3v2 is most significant bit first (MSB). The
|
||||
byteorder in multibyte numbers is most significant byte first (e.g.
|
||||
$12345678 would be encoded $12 34 56 78), also known as big endian
|
||||
and network byte order.
|
||||
|
||||
Overall tag structure:
|
||||
|
||||
+-----------------------------+
|
||||
| Header (10 bytes) |
|
||||
+-----------------------------+
|
||||
| Extended Header |
|
||||
| (variable length, OPTIONAL) |
|
||||
+-----------------------------+
|
||||
| Frames (variable length) |
|
||||
+-----------------------------+
|
||||
| Padding |
|
||||
| (variable length, OPTIONAL) |
|
||||
+-----------------------------+
|
||||
| Footer (10 bytes, OPTIONAL) |
|
||||
+-----------------------------+
|
||||
|
||||
In general, padding and footer are mutually exclusive. See details in
|
||||
sections 3.3, 3.4 and 5.
|
||||
|
||||
|
||||
3.1. ID3v2 header
|
||||
|
||||
The first part of the ID3v2 tag is the 10 byte tag header, laid out
|
||||
as follows:
|
||||
|
||||
ID3v2/file identifier "ID3"
|
||||
ID3v2 version $04 00
|
||||
ID3v2 flags %abcd0000
|
||||
ID3v2 size 4 * %0xxxxxxx
|
||||
|
||||
The first three bytes of the tag are always "ID3", to indicate that
|
||||
this is an ID3v2 tag, directly followed by the two version bytes. The
|
||||
first byte of ID3v2 version is its major version, while the second
|
||||
byte is its revision number. In this case this is ID3v2.4.0. All
|
||||
revisions are backwards compatible while major versions are not. If
|
||||
software with ID3v2.4.0 and below support should encounter version
|
||||
five or higher it should simply ignore the whole tag. Version or
|
||||
revision will never be $FF.
|
||||
|
||||
The version is followed by the ID3v2 flags field, of which currently
|
||||
four flags are used.
|
||||
|
||||
|
||||
a - Unsynchronisation
|
||||
|
||||
Bit 7 in the 'ID3v2 flags' indicates whether or not
|
||||
unsynchronisation is applied on all frames (see section 6.1 for
|
||||
details); a set bit indicates usage.
|
||||
|
||||
|
||||
b - Extended header
|
||||
|
||||
The second bit (bit 6) indicates whether or not the header is
|
||||
followed by an extended header. The extended header is described in
|
||||
section 3.2. A set bit indicates the presence of an extended
|
||||
header.
|
||||
|
||||
|
||||
c - Experimental indicator
|
||||
|
||||
The third bit (bit 5) is used as an 'experimental indicator'. This
|
||||
flag SHALL always be set when the tag is in an experimental stage.
|
||||
|
||||
|
||||
d - Footer present
|
||||
|
||||
Bit 4 indicates that a footer (section 3.4) is present at the very
|
||||
end of the tag. A set bit indicates the presence of a footer.
|
||||
|
||||
|
||||
All the other flags MUST be cleared. If one of these undefined flags
|
||||
are set, the tag might not be readable for a parser that does not
|
||||
know the flags function.
|
||||
|
||||
The ID3v2 tag size is stored as a 32 bit synchsafe integer (section
|
||||
6.2), making a total of 28 effective bits (representing up to 256MB).
|
||||
|
||||
The ID3v2 tag size is the sum of the byte length of the extended
|
||||
header, the padding and the frames after unsynchronisation. If a
|
||||
footer is present this equals to ('total size' - 20) bytes, otherwise
|
||||
('total size' - 10) bytes.
|
||||
|
||||
An ID3v2 tag can be detected with the following pattern:
|
||||
$49 44 33 yy yy xx zz zz zz zz
|
||||
Where yy is less than $FF, xx is the 'flags' byte and zz is less than
|
||||
$80.
|
||||
|
||||
|
||||
3.2. Extended header
|
||||
|
||||
The extended header contains information that can provide further
|
||||
insight in the structure of the tag, but is not vital to the correct
|
||||
parsing of the tag information; hence the extended header is
|
||||
optional.
|
||||
|
||||
Extended header size 4 * %0xxxxxxx
|
||||
Number of flag bytes $01
|
||||
Extended Flags $xx
|
||||
|
||||
Where the 'Extended header size' is the size of the whole extended
|
||||
header, stored as a 32 bit synchsafe integer. An extended header can
|
||||
thus never have a size of fewer than six bytes.
|
||||
|
||||
The extended flags field, with its size described by 'number of flag
|
||||
bytes', is defined as:
|
||||
|
||||
%0bcd0000
|
||||
|
||||
Each flag that is set in the extended header has data attached, which
|
||||
comes in the order in which the flags are encountered (i.e. the data
|
||||
for flag 'b' comes before the data for flag 'c'). Unset flags cannot
|
||||
have any attached data. All unknown flags MUST be unset and their
|
||||
corresponding data removed when a tag is modified.
|
||||
|
||||
Every set flag's data starts with a length byte, which contains a
|
||||
value between 0 and 127 ($00 - $7f), followed by data that has the
|
||||
field length indicated by the length byte. If a flag has no attached
|
||||
data, the value $00 is used as length byte.
|
||||
|
||||
|
||||
b - Tag is an update
|
||||
|
||||
If this flag is set, the present tag is an update of a tag found
|
||||
earlier in the present file or stream. If frames defined as unique
|
||||
are found in the present tag, they are to override any
|
||||
corresponding ones found in the earlier tag. This flag has no
|
||||
corresponding data.
|
||||
|
||||
Flag data length $00
|
||||
|
||||
c - CRC data present
|
||||
|
||||
If this flag is set, a CRC-32 [ISO-3309] data is included in the
|
||||
extended header. The CRC is calculated on all the data between the
|
||||
header and footer as indicated by the header's tag length field,
|
||||
minus the extended header. Note that this includes the padding (if
|
||||
there is any), but excludes the footer. The CRC-32 is stored as an
|
||||
35 bit synchsafe integer, leaving the upper four bits always
|
||||
zeroed.
|
||||
|
||||
Flag data length $05
|
||||
Total frame CRC 5 * %0xxxxxxx
|
||||
|
||||
d - Tag restrictions
|
||||
|
||||
For some applications it might be desired to restrict a tag in more
|
||||
ways than imposed by the ID3v2 specification. Note that the
|
||||
presence of these restrictions does not affect how the tag is
|
||||
decoded, merely how it was restricted before encoding. If this flag
|
||||
is set the tag is restricted as follows:
|
||||
|
||||
Flag data length $01
|
||||
Restrictions %ppqrrstt
|
||||
|
||||
p - Tag size restrictions
|
||||
|
||||
00 No more than 128 frames and 1 MB total tag size.
|
||||
01 No more than 64 frames and 128 KB total tag size.
|
||||
10 No more than 32 frames and 40 KB total tag size.
|
||||
11 No more than 32 frames and 4 KB total tag size.
|
||||
|
||||
q - Text encoding restrictions
|
||||
|
||||
0 No restrictions
|
||||
1 Strings are only encoded with ISO-8859-1 [ISO-8859-1] or
|
||||
UTF-8 [UTF-8].
|
||||
|
||||
r - Text fields size restrictions
|
||||
|
||||
00 No restrictions
|
||||
01 No string is longer than 1024 characters.
|
||||
10 No string is longer than 128 characters.
|
||||
11 No string is longer than 30 characters.
|
||||
|
||||
Note that nothing is said about how many bytes is used to
|
||||
represent those characters, since it is encoding dependent. If a
|
||||
text frame consists of more than one string, the sum of the
|
||||
strungs is restricted as stated.
|
||||
|
||||
s - Image encoding restrictions
|
||||
|
||||
0 No restrictions
|
||||
1 Images are encoded only with PNG [PNG] or JPEG [JFIF].
|
||||
|
||||
t - Image size restrictions
|
||||
|
||||
00 No restrictions
|
||||
01 All images are 256x256 pixels or smaller.
|
||||
10 All images are 64x64 pixels or smaller.
|
||||
11 All images are exactly 64x64 pixels, unless required
|
||||
otherwise.
|
||||
|
||||
|
||||
3.3. Padding
|
||||
|
||||
It is OPTIONAL to include padding after the final frame (at the end
|
||||
of the ID3 tag), making the size of all the frames together smaller
|
||||
than the size given in the tag header. A possible purpose of this
|
||||
padding is to allow for adding a few additional frames or enlarge
|
||||
existing frames within the tag without having to rewrite the entire
|
||||
file. The value of the padding bytes must be $00. A tag MUST NOT have
|
||||
any padding between the frames or between the tag header and the
|
||||
frames. Furthermore it MUST NOT have any padding when a tag footer is
|
||||
added to the tag.
|
||||
|
||||
|
||||
3.4. ID3v2 footer
|
||||
|
||||
To speed up the process of locating an ID3v2 tag when searching from
|
||||
the end of a file, a footer can be added to the tag. It is REQUIRED
|
||||
to add a footer to an appended tag, i.e. a tag located after all
|
||||
audio data. The footer is a copy of the header, but with a different
|
||||
identifier.
|
||||
|
||||
ID3v2 identifier "3DI"
|
||||
ID3v2 version $04 00
|
||||
ID3v2 flags %abcd0000
|
||||
ID3v2 size 4 * %0xxxxxxx
|
||||
|
||||
|
||||
4. ID3v2 frame overview
|
||||
|
||||
All ID3v2 frames consists of one frame header followed by one or more
|
||||
fields containing the actual information. The header is always 10
|
||||
bytes and laid out as follows:
|
||||
|
||||
Frame ID $xx xx xx xx (four characters)
|
||||
Size 4 * %0xxxxxxx
|
||||
Flags $xx xx
|
||||
|
||||
The frame ID is made out of the characters capital A-Z and 0-9.
|
||||
Identifiers beginning with "X", "Y" and "Z" are for experimental
|
||||
frames and free for everyone to use, without the need to set the
|
||||
experimental bit in the tag header. Bear in mind that someone else
|
||||
might have used the same identifier as you. All other identifiers are
|
||||
either used or reserved for future use.
|
||||
|
||||
The frame ID is followed by a size descriptor containing the size of
|
||||
the data in the final frame, after encryption, compression and
|
||||
unsynchronisation. The size is excluding the frame header ('total
|
||||
frame size' - 10 bytes) and stored as a 32 bit synchsafe integer.
|
||||
|
||||
In the frame header the size descriptor is followed by two flag
|
||||
bytes. These flags are described in section 4.1.
|
||||
|
||||
There is no fixed order of the frames' appearance in the tag,
|
||||
although it is desired that the frames are arranged in order of
|
||||
significance concerning the recognition of the file. An example of
|
||||
such order: UFID, TIT2, MCDI, TRCK ...
|
||||
|
||||
A tag MUST contain at least one frame. A frame must be at least 1
|
||||
byte big, excluding the header.
|
||||
|
||||
If nothing else is said, strings, including numeric strings and URLs
|
||||
[URL], are represented as ISO-8859-1 [ISO-8859-1] characters in the
|
||||
range $20 - $FF. Such strings are represented in frame descriptions
|
||||
as <text string>, or <full text string> if newlines are allowed. If
|
||||
nothing else is said newline character is forbidden. In ISO-8859-1 a
|
||||
newline is represented, when allowed, with $0A only.
|
||||
|
||||
Frames that allow different types of text encoding contains a text
|
||||
encoding description byte. Possible encodings:
|
||||
|
||||
$00 ISO-8859-1 [ISO-8859-1]. Terminated with $00.
|
||||
$01 UTF-16 [UTF-16] encoded Unicode [UNICODE] with BOM. All
|
||||
strings in the same frame SHALL have the same byteorder.
|
||||
Terminated with $00 00.
|
||||
$02 UTF-16BE [UTF-16] encoded Unicode [UNICODE] without BOM.
|
||||
Terminated with $00 00.
|
||||
$03 UTF-8 [UTF-8] encoded Unicode [UNICODE]. Terminated with $00.
|
||||
|
||||
Strings dependent on encoding are represented in frame descriptions
|
||||
as <text string according to encoding>, or <full text string
|
||||
according to encoding> if newlines are allowed. Any empty strings of
|
||||
type $01 which are NULL-terminated may have the Unicode BOM followed
|
||||
by a Unicode NULL ($FF FE 00 00 or $FE FF 00 00).
|
||||
|
||||
The timestamp fields are based on a subset of ISO 8601. When being as
|
||||
precise as possible the format of a time string is
|
||||
yyyy-MM-ddTHH:mm:ss (year, "-", month, "-", day, "T", hour (out of
|
||||
24), ":", minutes, ":", seconds), but the precision may be reduced by
|
||||
removing as many time indicators as wanted. Hence valid timestamps
|
||||
are
|
||||
yyyy, yyyy-MM, yyyy-MM-dd, yyyy-MM-ddTHH, yyyy-MM-ddTHH:mm and
|
||||
yyyy-MM-ddTHH:mm:ss. All time stamps are UTC. For durations, use
|
||||
the slash character as described in 8601, and for multiple non-
|
||||
contiguous dates, use multiple strings, if allowed by the frame
|
||||
definition.
|
||||
|
||||
The three byte language field, present in several frames, is used to
|
||||
describe the language of the frame's content, according to ISO-639-2
|
||||
[ISO-639-2]. The language should be represented in lower case. If the
|
||||
language is not known the string "XXX" should be used.
|
||||
|
||||
All URLs [URL] MAY be relative, e.g. "picture.png", "../doc.txt".
|
||||
|
||||
If a frame is longer than it should be, e.g. having more fields than
|
||||
specified in this document, that indicates that additions to the
|
||||
frame have been made in a later version of the ID3v2 standard. This
|
||||
is reflected by the revision number in the header of the tag.
|
||||
|
||||
|
||||
4.1. Frame header flags
|
||||
|
||||
In the frame header the size descriptor is followed by two flag
|
||||
bytes. All unused flags MUST be cleared. The first byte is for
|
||||
'status messages' and the second byte is a format description. If an
|
||||
unknown flag is set in the first byte the frame MUST NOT be changed
|
||||
without that bit cleared. If an unknown flag is set in the second
|
||||
byte the frame is likely to not be readable. Some flags in the second
|
||||
byte indicates that extra information is added to the header. These
|
||||
fields of extra information is ordered as the flags that indicates
|
||||
them. The flags field is defined as follows (l and o left out because
|
||||
ther resemblence to one and zero):
|
||||
|
||||
%0abc0000 %0h00kmnp
|
||||
|
||||
Some frame format flags indicate that additional information fields
|
||||
are added to the frame. This information is added after the frame
|
||||
header and before the frame data in the same order as the flags that
|
||||
indicates them. I.e. the four bytes of decompressed size will precede
|
||||
the encryption method byte. These additions affects the 'frame size'
|
||||
field, but are not subject to encryption or compression.
|
||||
|
||||
The default status flags setting for a frame is, unless stated
|
||||
otherwise, 'preserved if tag is altered' and 'preserved if file is
|
||||
altered', i.e. %00000000.
|
||||
|
||||
|
||||
4.1.1. Frame status flags
|
||||
|
||||
a - Tag alter preservation
|
||||
|
||||
This flag tells the tag parser what to do with this frame if it is
|
||||
unknown and the tag is altered in any way. This applies to all
|
||||
kinds of alterations, including adding more padding and reordering
|
||||
the frames.
|
||||
|
||||
0 Frame should be preserved.
|
||||
1 Frame should be discarded.
|
||||
|
||||
|
||||
b - File alter preservation
|
||||
|
||||
This flag tells the tag parser what to do with this frame if it is
|
||||
unknown and the file, excluding the tag, is altered. This does not
|
||||
apply when the audio is completely replaced with other audio data.
|
||||
|
||||
0 Frame should be preserved.
|
||||
1 Frame should be discarded.
|
||||
|
||||
|
||||
c - Read only
|
||||
|
||||
This flag, if set, tells the software that the contents of this
|
||||
frame are intended to be read only. Changing the contents might
|
||||
break something, e.g. a signature. If the contents are changed,
|
||||
without knowledge of why the frame was flagged read only and
|
||||
without taking the proper means to compensate, e.g. recalculating
|
||||
the signature, the bit MUST be cleared.
|
||||
|
||||
|
||||
4.1.2. Frame format flags
|
||||
|
||||
h - Grouping identity
|
||||
|
||||
This flag indicates whether or not this frame belongs in a group
|
||||
with other frames. If set, a group identifier byte is added to the
|
||||
frame. Every frame with the same group identifier belongs to the
|
||||
same group.
|
||||
|
||||
0 Frame does not contain group information
|
||||
1 Frame contains group information
|
||||
|
||||
|
||||
k - Compression
|
||||
|
||||
This flag indicates whether or not the frame is compressed.
|
||||
A 'Data Length Indicator' byte MUST be included in the frame.
|
||||
|
||||
0 Frame is not compressed.
|
||||
1 Frame is compressed using zlib [zlib] deflate method.
|
||||
If set, this requires the 'Data Length Indicator' bit
|
||||
to be set as well.
|
||||
|
||||
|
||||
m - Encryption
|
||||
|
||||
This flag indicates whether or not the frame is encrypted. If set,
|
||||
one byte indicating with which method it was encrypted will be
|
||||
added to the frame. See description of the ENCR frame for more
|
||||
information about encryption method registration. Encryption
|
||||
should be done after compression. Whether or not setting this flag
|
||||
requires the presence of a 'Data Length Indicator' depends on the
|
||||
specific algorithm used.
|
||||
|
||||
0 Frame is not encrypted.
|
||||
1 Frame is encrypted.
|
||||
|
||||
n - Unsynchronisation
|
||||
|
||||
This flag indicates whether or not unsynchronisation was applied
|
||||
to this frame. See section 6 for details on unsynchronisation.
|
||||
If this flag is set all data from the end of this header to the
|
||||
end of this frame has been unsynchronised. Although desirable, the
|
||||
presence of a 'Data Length Indicator' is not made mandatory by
|
||||
unsynchronisation.
|
||||
|
||||
0 Frame has not been unsynchronised.
|
||||
1 Frame has been unsyrchronised.
|
||||
|
||||
p - Data length indicator
|
||||
|
||||
This flag indicates that a data length indicator has been added to
|
||||
the frame. The data length indicator is the value one would write
|
||||
as the 'Frame length' if all of the frame format flags were
|
||||
zeroed, represented as a 32 bit synchsafe integer.
|
||||
|
||||
0 There is no Data Length Indicator.
|
||||
1 A data length Indicator has been added to the frame.
|
||||
|
||||
|
||||
5. Tag location
|
||||
|
||||
The default location of an ID3v2 tag is prepended to the audio so
|
||||
that players can benefit from the information when the data is
|
||||
streamed. It is however possible to append the tag, or make a
|
||||
prepend/append combination. When deciding upon where an unembedded
|
||||
tag should be located, the following order of preference SHOULD be
|
||||
considered.
|
||||
|
||||
1. Prepend the tag.
|
||||
|
||||
2. Prepend a tag with all vital information and add a second tag at
|
||||
the end of the file, before tags from other tagging systems. The
|
||||
first tag is required to have a SEEK frame.
|
||||
|
||||
3. Add a tag at the end of the file, before tags from other tagging
|
||||
systems.
|
||||
|
||||
In case 2 and 3 the tag can simply be appended if no other known tags
|
||||
are present. The suggested method to find ID3v2 tags are:
|
||||
|
||||
1. Look for a prepended tag using the pattern found in section 3.1.
|
||||
|
||||
2. If a SEEK frame was found, use its values to guide further
|
||||
searching.
|
||||
|
||||
3. Look for a tag footer, scanning from the back of the file.
|
||||
|
||||
For every new tag that is found, the old tag should be discarded
|
||||
unless the update flag in the extended header (section 3.2) is set.
|
||||
|
||||
|
||||
6. Unsynchronisation
|
||||
|
||||
The only purpose of unsynchronisation is to make the ID3v2 tag as
|
||||
compatible as possible with existing software and hardware. There is
|
||||
no use in 'unsynchronising' tags if the file is only to be processed
|
||||
only by ID3v2 aware software and hardware. Unsynchronisation is only
|
||||
useful with tags in MPEG 1/2 layer I, II and III, MPEG 2.5 and AAC
|
||||
files.
|
||||
|
||||
|
||||
6.1. The unsynchronisation scheme
|
||||
|
||||
Whenever a false synchronisation is found within the tag, one zeroed
|
||||
byte is inserted after the first false synchronisation byte. The
|
||||
format of synchronisations that should be altered by ID3 encoders is
|
||||
as follows:
|
||||
|
||||
%11111111 111xxxxx
|
||||
|
||||
and should be replaced with:
|
||||
|
||||
%11111111 00000000 111xxxxx
|
||||
|
||||
This has the side effect that all $FF 00 combinations have to be
|
||||
altered, so they will not be affected by the decoding process.
|
||||
Therefore all the $FF 00 combinations have to be replaced with the
|
||||
$FF 00 00 combination during the unsynchronisation.
|
||||
|
||||
To indicate usage of the unsynchronisation, the unsynchronisation
|
||||
flag in the frame header should be set. This bit MUST be set if the
|
||||
frame was altered by the unsynchronisation and SHOULD NOT be set if
|
||||
unaltered. If all frames in the tag are unsynchronised the
|
||||
unsynchronisation flag in the tag header SHOULD be set. It MUST NOT
|
||||
be set if the tag has a frame which is not unsynchronised.
|
||||
|
||||
Assume the first byte of the audio to be $FF. The special case when
|
||||
the last byte of the last frame is $FF and no padding nor footer is
|
||||
used will then introduce a false synchronisation. This can be solved
|
||||
by adding a footer, adding padding or unsynchronising the frame and
|
||||
add $00 to the end of the frame data, thus adding more byte to the
|
||||
frame size than a normal unsynchronisation would. Although not
|
||||
preferred, it is allowed to apply the last method on all frames
|
||||
ending with $FF.
|
||||
|
||||
It is preferred that the tag is either completely unsynchronised or
|
||||
not unsynchronised at all. A completely unsynchronised tag has no
|
||||
false synchonisations in it, as defined above, and does not end with
|
||||
$FF. A completely non-unsynchronised tag contains no unsynchronised
|
||||
frames, and thus the unsynchronisation flag in the header is cleared.
|
||||
|
||||
Do bear in mind, that if compression or encryption is used, the
|
||||
unsynchronisation scheme MUST be applied afterwards. When decoding an
|
||||
unsynchronised frame, the unsynchronisation scheme MUST be reversed
|
||||
first, encryption and decompression afterwards.
|
||||
|
||||
|
||||
6.2. Synchsafe integers
|
||||
|
||||
In some parts of the tag it is inconvenient to use the
|
||||
unsychronisation scheme because the size of unsynchronised data is
|
||||
not known in advance, which is particularly problematic with size
|
||||
descriptors. The solution in ID3v2 is to use synchsafe integers, in
|
||||
which there can never be any false synchs. Synchsafe integers are
|
||||
integers that keep its highest bit (bit 7) zeroed, making seven bits
|
||||
out of eight available. Thus a 32 bit synchsafe integer can store 28
|
||||
bits of information.
|
||||
|
||||
Example:
|
||||
|
||||
255 (%11111111) encoded as a 16 bit synchsafe integer is 383
|
||||
(%00000001 01111111).
|
||||
|
||||
|
||||
7. Copyright
|
||||
|
||||
Copyright (C) Martin Nilsson 2000. All Rights Reserved.
|
||||
|
||||
This document and translations of it may be copied and furnished to
|
||||
others, and derivative works that comment on or otherwise explain it
|
||||
or assist in its implementation may be prepared, copied, published
|
||||
and distributed, in whole or in part, without restriction of any
|
||||
kind, provided that a reference to this document is included on all
|
||||
such copies and derivative works. However, this document itself may
|
||||
not be modified in any way and reissued as the original document.
|
||||
|
||||
The limited permissions granted above are perpetual and will not be
|
||||
revoked.
|
||||
|
||||
This document and the information contained herein is provided on an
|
||||
'AS IS' basis and THE AUTHORS DISCLAIMS ALL WARRANTIES, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF
|
||||
THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
|
||||
8. References
|
||||
|
||||
[ID3v2] Martin Nilsson, 'ID3v2 informal standard'.
|
||||
|
||||
<url:http://www.id3.org/id3v2.3.0.txt>
|
||||
|
||||
[ISO-639-2] ISO/FDIS 639-2.
|
||||
'Codes for the representation of names of languages, Part 2: Alpha-3
|
||||
code.' Technical committee / subcommittee: TC 37 / SC 2
|
||||
|
||||
[ISO-3309] ISO 3309
|
||||
'Information Processing Systems--Data Communication High-Level Data
|
||||
Link Control Procedure--Frame Structure', IS 3309, October 1984, 3rd
|
||||
Edition.
|
||||
|
||||
[ISO-8859-1] ISO/IEC DIS 8859-1.
|
||||
'8-bit single-byte coded graphic character sets, Part 1: Latin
|
||||
alphabet No. 1.' Technical committee / subcommittee: JTC 1 / SC 2
|
||||
|
||||
[JFIF] 'JPEG File Interchange Format, version 1.02'
|
||||
|
||||
<url:http://www.w3.org/Graphics/JPEG/jfif.txt>
|
||||
|
||||
[KEYWORDS] S. Bradner, 'Key words for use in RFCs to Indicate
|
||||
Requirement Levels', RFC 2119, March 1997.
|
||||
|
||||
<url:ftp://ftp.isi.edu/in-notes/rfc2119.txt>
|
||||
|
||||
[MPEG] ISO/IEC 11172-3:1993.
|
||||
'Coding of moving pictures and associated audio for digital storage
|
||||
media at up to about 1,5 Mbit/s, Part 3: Audio.'
|
||||
Technical committee / subcommittee: JTC 1 / SC 29
|
||||
and
|
||||
ISO/IEC 13818-3:1995
|
||||
'Generic coding of moving pictures and associated audio information,
|
||||
Part 3: Audio.'
|
||||
Technical committee / subcommittee: JTC 1 / SC 29
|
||||
and
|
||||
ISO/IEC DIS 13818-3
|
||||
'Generic coding of moving pictures and associated audio information,
|
||||
Part 3: Audio (Revision of ISO/IEC 13818-3:1995)'
|
||||
|
||||
[PNG] 'Portable Network Graphics, version 1.0'
|
||||
|
||||
<url:http://www.w3.org/TR/REC-png-multi.html>
|
||||
|
||||
[UNICODE] The Unicode Consortium,
|
||||
'The Unicode Standard Version 3.0', ISBN 0-201-61633-5.
|
||||
|
||||
<url:http://www.unicode.org/unicode/standard/versions/Unicode3.0.htm>
|
||||
|
||||
[URL] T. Berners-Lee, L. Masinter & M. McCahill, 'Uniform Resource
|
||||
Locators (URL)', RFC 1738, December 1994.
|
||||
|
||||
<url:ftp://ftp.isi.edu/in-notes/rfc1738.txt>
|
||||
|
||||
[UTF-8] F. Yergeau, 'UTF-8, a transformation format of ISO 10646',
|
||||
RFC 2279, January 1998.
|
||||
|
||||
<url:ftp://ftp.isi.edu/in-notes/rfc2279.txt>
|
||||
|
||||
[UTF-16] F. Yergeau, 'UTF-16, an encoding of ISO 10646', RFC 2781,
|
||||
February 2000.
|
||||
|
||||
<url:ftp://ftp.isi.edu/in-notes/rfc2781.txt>
|
||||
|
||||
[ZLIB] P. Deutsch, Aladdin Enterprises & J-L. Gailly, 'ZLIB
|
||||
Compressed Data Format Specification version 3.3', RFC 1950,
|
||||
May 1996.
|
||||
|
||||
<url:ftp://ftp.isi.edu/in-notes/rfc1950.txt>
|
||||
|
||||
|
||||
9. Author's Address
|
||||
|
||||
Written by
|
||||
|
||||
Martin Nilsson
|
||||
Rydsvägen 246 C. 30
|
||||
SE-584 34 Linköping
|
||||
Sweden
|
||||
|
||||
Email: nilsson@id3.org
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include "id3v2extendedheader.h"
|
||||
#include "id3v2synchdata.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class ExtendedHeader::ExtendedHeaderPrivate
|
||||
{
|
||||
public:
|
||||
ExtendedHeaderPrivate() : size(0) {}
|
||||
|
||||
uint size;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ExtendedHeader::ExtendedHeader()
|
||||
{
|
||||
d = new ExtendedHeaderPrivate();
|
||||
}
|
||||
|
||||
ExtendedHeader::~ExtendedHeader()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
TagLib::uint ExtendedHeader::size() const
|
||||
{
|
||||
return d->size;
|
||||
}
|
||||
|
||||
void ExtendedHeader::setData(const ByteVector &data)
|
||||
{
|
||||
parse(data);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ExtendedHeader::parse(const ByteVector &data)
|
||||
{
|
||||
d->size = SynchData::toUInt(data.mid(0, 4)); // (structure 3.2 "Extended header size")
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_ID3V2EXTENDEDHEADER_H
|
||||
#define TAGLIB_ID3V2EXTENDEDHEADER_H
|
||||
|
||||
#include "taglib_export.h"
|
||||
#include "tbytevector.h"
|
||||
#include "taglib.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
namespace ID3v2 {
|
||||
|
||||
//! ID3v2 extended header implementation
|
||||
|
||||
/*!
|
||||
* This class implements ID3v2 extended headers. It attempts to follow,
|
||||
* both semantically and programatically, the structure specified in
|
||||
* the ID3v2 standard. The API is based on the properties of ID3v2 extended
|
||||
* headers specified there. If any of the terms used in this documentation
|
||||
* are unclear please check the specification in the linked section.
|
||||
* (Structure, <a href="id3v2-structure.html#3.2">3.2</a>)
|
||||
*/
|
||||
|
||||
class TAGLIB_EXPORT ExtendedHeader
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* Constructs an empty ID3v2 extended header.
|
||||
*/
|
||||
ExtendedHeader();
|
||||
|
||||
/*!
|
||||
* Destroys the extended header.
|
||||
*/
|
||||
virtual ~ExtendedHeader();
|
||||
|
||||
/*!
|
||||
* Returns the size of the extended header. This is variable for the
|
||||
* extended header.
|
||||
*/
|
||||
uint size() const;
|
||||
|
||||
/*!
|
||||
* Sets the data that will be used as the extended header. Since the
|
||||
* length is not known before the extended header has been parsed, this
|
||||
* should just be a pointer to the first byte of the extended header. It
|
||||
* will determine the length internally and make that available through
|
||||
* size().
|
||||
*/
|
||||
void setData(const ByteVector &data);
|
||||
|
||||
protected:
|
||||
/*!
|
||||
* Called by setData() to parse the extended header data. It makes this
|
||||
* information available through the public API.
|
||||
*/
|
||||
void parse(const ByteVector &data);
|
||||
|
||||
private:
|
||||
ExtendedHeader(const ExtendedHeader &);
|
||||
ExtendedHeader &operator=(const ExtendedHeader &);
|
||||
|
||||
class ExtendedHeaderPrivate;
|
||||
ExtendedHeaderPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,60 @@
|
|||
/***************************************************************************
|
||||
copyright : (C) 2002 - 2008 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA *
|
||||
* 02110-1301 USA *
|
||||
* *
|
||||
* Alternatively, this file is available under the Mozilla Public *
|
||||
* License Version 1.1. You may obtain a copy of the License at *
|
||||
* http://www.mozilla.org/MPL/ *
|
||||
***************************************************************************/
|
||||
|
||||
#include "id3v2footer.h"
|
||||
#include "id3v2header.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace ID3v2;
|
||||
|
||||
class Footer::FooterPrivate
|
||||
{
|
||||
public:
|
||||
static const uint size = 10;
|
||||
};
|
||||
|
||||
Footer::Footer()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Footer::~Footer()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
TagLib::uint Footer::size()
|
||||
{
|
||||
return FooterPrivate::size;
|
||||
}
|
||||
|
||||
ByteVector Footer::render(const Header *header) const
|
||||
{
|
||||
ByteVector headerData = header->render();
|
||||
headerData[0] = '3';
|
||||
headerData[1] = 'D';
|
||||
headerData[2] = 'I';
|
||||
return headerData;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue