mirror of
https://github.com/taglib/taglib.git
synced 2025-07-22 23:14:33 -04:00
One more step. Wow, this was impressively broken.
git-svn-id: svn://anonsvn.kde.org/home/kde/trunk/kdesupport/taglib@588016 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
This commit is contained in:
1
ape/CMakeLists.txt
Normal file
1
ape/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
||||
INSTALL( FILES apetag.h apefooter.h apeitem.h DESTINATION ${INCLUDE_INSTALL_DIR}/taglib)
|
13
ape/Makefile.am
Normal file
13
ape/Makefile.am
Normal file
@ -0,0 +1,13 @@
|
||||
INCLUDES = \
|
||||
-I$(top_srcdir)/taglib \
|
||||
-I$(top_srcdir)/taglib/toolkit \
|
||||
$(all_includes)
|
||||
|
||||
noinst_LTLIBRARIES = libape.la
|
||||
|
||||
libape_la_SOURCES = apetag.cpp apefooter.cpp apeitem.cpp
|
||||
|
||||
taglib_include_HEADERS = apetag.h apefooter.h apeitem.h
|
||||
taglib_includedir = $(includedir)/taglib
|
||||
|
||||
EXTRA_DIST = $(libape_la_SOURCES) $(taglib_include_HEADERS)
|
170
ape/ape-tag-format.txt
Normal file
170
ape/ape-tag-format.txt
Normal file
@ -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
|
232
ape/apefooter.cpp
Normal file
232
ape/apefooter.cpp
Normal file
@ -0,0 +1,232 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2004 by Allan Sandfeld Jensen
|
||||
(C) 2002, 2003 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
* USA *
|
||||
***************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
#include <bitset>
|
||||
|
||||
#include <tstring.h>
|
||||
#include <tdebug.h>
|
||||
|
||||
#include "apefooter.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace APE;
|
||||
|
||||
class 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 Footer::size()
|
||||
{
|
||||
return FooterPrivate::size;
|
||||
}
|
||||
|
||||
ByteVector Footer::fileIdentifier()
|
||||
{
|
||||
return ByteVector::fromCString("APETAGEX");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Footer::Footer()
|
||||
{
|
||||
d = new FooterPrivate;
|
||||
}
|
||||
|
||||
Footer::Footer(const ByteVector &data)
|
||||
{
|
||||
d = new FooterPrivate;
|
||||
parse(data);
|
||||
}
|
||||
|
||||
Footer::~Footer()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
TagLib::uint Footer::version() const
|
||||
{
|
||||
return d->version;
|
||||
}
|
||||
|
||||
bool Footer::headerPresent() const
|
||||
{
|
||||
return d->headerPresent;
|
||||
}
|
||||
|
||||
bool Footer::footerPresent() const
|
||||
{
|
||||
return d->footerPresent;
|
||||
}
|
||||
|
||||
bool Footer::isHeader() const
|
||||
{
|
||||
return d->isHeader;
|
||||
}
|
||||
|
||||
void Footer::setHeaderPresent(bool b) const
|
||||
{
|
||||
d->headerPresent = b;
|
||||
}
|
||||
|
||||
TagLib::uint Footer::itemCount() const
|
||||
{
|
||||
return d->itemCount;
|
||||
}
|
||||
|
||||
void Footer::setItemCount(uint s)
|
||||
{
|
||||
d->itemCount = s;
|
||||
}
|
||||
|
||||
TagLib::uint Footer::tagSize() const
|
||||
{
|
||||
return d->tagSize;
|
||||
}
|
||||
|
||||
TagLib::uint Footer::completeTagSize() const
|
||||
{
|
||||
if(d->headerPresent)
|
||||
return d->tagSize + d->size;
|
||||
else
|
||||
return d->tagSize;
|
||||
}
|
||||
|
||||
void Footer::setTagSize(uint s)
|
||||
{
|
||||
d->tagSize = s;
|
||||
}
|
||||
|
||||
void Footer::setData(const ByteVector &data)
|
||||
{
|
||||
parse(data);
|
||||
}
|
||||
|
||||
ByteVector Footer::renderFooter() const
|
||||
{
|
||||
return render(false);
|
||||
}
|
||||
|
||||
ByteVector Footer::renderHeader() const
|
||||
{
|
||||
if (!d->headerPresent) return ByteVector();
|
||||
|
||||
return render(true);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void 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(data.mid(20, 4).toUInt(false));
|
||||
|
||||
d->headerPresent = flags[31];
|
||||
d->footerPresent = !flags[30];
|
||||
d->isHeader = flags[29];
|
||||
|
||||
}
|
||||
|
||||
ByteVector 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;
|
||||
}
|
168
ape/apefooter.h
Normal file
168
ape/apefooter.h
Normal file
@ -0,0 +1,168 @@
|
||||
/***************************************************************************
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
* USA *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_APEFOOTER_H
|
||||
#define TAGLIB_APEFOOTER_H
|
||||
|
||||
#include "tbytevector.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 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
|
220
ape/apeitem.cpp
Normal file
220
ape/apeitem.cpp
Normal file
@ -0,0 +1,220 @@
|
||||
/***************************************************************************
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
* USA *
|
||||
***************************************************************************/
|
||||
|
||||
#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 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::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->text = value;
|
||||
}
|
||||
|
||||
void APE::Item::setValues(const StringList &value)
|
||||
{
|
||||
d->text = value;
|
||||
}
|
||||
|
||||
void APE::Item::appendValue(const String &value)
|
||||
{
|
||||
d->text.append(value);
|
||||
}
|
||||
|
||||
void APE::Item::appendValues(const StringList &values)
|
||||
{
|
||||
d->text.append(values);
|
||||
}
|
||||
|
||||
int APE::Item::size() const
|
||||
{
|
||||
return 8 + d->key.size() + 1 + d->value.size();
|
||||
}
|
||||
|
||||
StringList APE::Item::toStringList() 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 0:
|
||||
case 1:
|
||||
if(d->text.isEmpty())
|
||||
return true;
|
||||
if(d->text.size() == 1 && d->text.front().isEmpty())
|
||||
return true;
|
||||
return false;
|
||||
case 2:
|
||||
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(int(d->type) < 2)
|
||||
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 != Item::Binary) {
|
||||
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;
|
||||
}
|
193
ape/apeitem.h
Normal file
193
ape/apeitem.h
Normal file
@ -0,0 +1,193 @@
|
||||
/***************************************************************************
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
* USA *
|
||||
***************************************************************************/
|
||||
|
||||
#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 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 an item with \a key and \a value.
|
||||
*/
|
||||
Item(const String &key, const String &value);
|
||||
|
||||
/*!
|
||||
* Constructs an item with \a key and \a values.
|
||||
*/
|
||||
Item(const String &key, const StringList &values);
|
||||
|
||||
/*!
|
||||
* 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.
|
||||
*
|
||||
* \deprecated This will be removed in the next binary incompatible version
|
||||
* as it is not kept in sync with the things that are set using setValue()
|
||||
* and friends.
|
||||
*/
|
||||
ByteVector value() const;
|
||||
|
||||
/*!
|
||||
* Sets the key for the item to \a key.
|
||||
*/
|
||||
void setKey(const String &key);
|
||||
|
||||
/*!
|
||||
* Sets the value of the item to \a value and clears any previous contents.
|
||||
*
|
||||
* \see toString()
|
||||
*/
|
||||
void setValue(const String &value);
|
||||
|
||||
/*!
|
||||
* Sets the 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 values.
|
||||
*
|
||||
* \see toString()
|
||||
*/
|
||||
void appendValue(const String &value);
|
||||
|
||||
/*!
|
||||
* Appends \a values to extend the current list of 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;
|
||||
|
||||
/*!
|
||||
* Returns the value as a string list.
|
||||
*/
|
||||
StringList toStringList() 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
|
||||
|
||||
|
255
ape/apetag.cpp
Normal file
255
ape/apetag.cpp
Normal file
@ -0,0 +1,255 @@
|
||||
/***************************************************************************
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
* USA *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tdebug.h>
|
||||
#include <tfile.h>
|
||||
#include <tstring.h>
|
||||
#include <tmap.h>
|
||||
|
||||
#include "apetag.h"
|
||||
#include "apefooter.h"
|
||||
#include "apeitem.h"
|
||||
|
||||
using namespace TagLib;
|
||||
using namespace APE;
|
||||
|
||||
class APE::Tag::TagPrivate
|
||||
{
|
||||
public:
|
||||
TagPrivate() : file(0), tagOffset(-1), tagLength(0) {}
|
||||
|
||||
File *file;
|
||||
long tagOffset;
|
||||
long tagLength;
|
||||
|
||||
Footer footer;
|
||||
|
||||
ItemListMap itemListMap;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
APE::Tag::Tag() : TagLib::Tag()
|
||||
{
|
||||
d = new TagPrivate;
|
||||
}
|
||||
|
||||
APE::Tag::Tag(File *file, long tagOffset) : TagLib::Tag()
|
||||
{
|
||||
d = new TagPrivate;
|
||||
d->file = file;
|
||||
d->tagOffset = tagOffset;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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(!value.isEmpty()) {
|
||||
if(d->itemListMap.contains(key) || !replace)
|
||||
d->itemListMap[key.upper()].appendValue(value);
|
||||
else
|
||||
setItem(key, Item(key, value));
|
||||
}
|
||||
}
|
||||
|
||||
void APE::Tag::setItem(const String &key, const Item &item)
|
||||
{
|
||||
d->itemListMap.insert(key.upper(), item);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected methods
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void APE::Tag::read()
|
||||
{
|
||||
if(d->file && d->file->isValid()) {
|
||||
|
||||
d->file->seek(d->tagOffset);
|
||||
d->footer.setData(d->file->readBlock(Footer::size()));
|
||||
|
||||
if(d->footer.tagSize() == 0 ||
|
||||
d->footer.tagSize() > uint(d->file->length()))
|
||||
return;
|
||||
|
||||
d->file->seek(d->tagOffset + 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();
|
||||
}
|
||||
}
|
157
ape/apetag.h
Normal file
157
ape/apetag.h
Normal file
@ -0,0 +1,157 @@
|
||||
/***************************************************************************
|
||||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
* USA *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_APETAG_H
|
||||
#define TAGLIB_APETAG_H
|
||||
|
||||
#include "tag.h"
|
||||
#include "tbytevector.h"
|
||||
#include "tmap.h"
|
||||
#include "tstring.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 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(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 "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);
|
||||
|
||||
/*!
|
||||
* 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.
|
||||
*
|
||||
* \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 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.
|
||||
*/
|
||||
void addValue(const String &key, const String &value, bool replace = true);
|
||||
|
||||
/*!
|
||||
* 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);
|
||||
|
||||
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
|
Reference in New Issue
Block a user