mirror of
https://github.com/taglib/taglib.git
synced 2025-07-18 21:14:23 -04:00
This commit was manufactured by cvs2svn to accommodate
a server-side copy/move. git-svn-id: svn://anonsvn.kde.org/home/kde/trunk/kdesupport/taglib@288617 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
This commit is contained in:
16
toolkit/Makefile.am
Normal file
16
toolkit/Makefile.am
Normal file
@ -0,0 +1,16 @@
|
||||
INCLUDES = $(all_includes)
|
||||
|
||||
noinst_LTLIBRARIES = libtoolkit.la
|
||||
|
||||
libtoolkit_la_SOURCES = \
|
||||
tstring.cpp tstringlist.cpp tbytevector.cpp \
|
||||
tbytevectorlist.cpp tfile.cpp tdebug.cpp unicode.cpp
|
||||
|
||||
taglib_include_HEADERS = \
|
||||
taglib.h tstring.h tlist.h tlist.tcc tstringlist.h \
|
||||
tbytevector.h tbytevectorlist.h tfile.h tdebug.h \
|
||||
tmap.h tmap.tcc
|
||||
|
||||
taglib_includedir = $(includedir)/taglib
|
||||
|
||||
EXTRA_DIST = $(libtoolkit_la_SOURCES) $(taglib_include_HEADERS)
|
148
toolkit/taglib.h
Normal file
148
toolkit/taglib.h
Normal file
@ -0,0 +1,148 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
* USA *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_H
|
||||
#define TAGLIB_H
|
||||
|
||||
#define TAGLIB_MAJOR_VERSION 0
|
||||
#define TAGLIB_MINOR_VERSION 96
|
||||
|
||||
#include <string>
|
||||
|
||||
//! A namespace for all TagLib related classes and functions
|
||||
|
||||
/*!
|
||||
* This namespace contains everything in TagLib. For projects working with
|
||||
* TagLib extensively it may be conveniten to add a
|
||||
* \code
|
||||
* using namespace TagLib;
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
class String;
|
||||
|
||||
typedef wchar_t wchar;
|
||||
typedef unsigned char uchar;
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned long ulong;
|
||||
|
||||
/*!
|
||||
* Unfortunately std::wstring isn't defined on some systems, (i.e. GCC < 3)
|
||||
* so I'm providing something here that should be constant.
|
||||
*/
|
||||
typedef std::basic_string<wchar> wstring;
|
||||
|
||||
#ifndef DO_NOT_DOCUMENT // Tell Doxygen to skip this class.
|
||||
/*!
|
||||
* \internal
|
||||
* This is just used as a base class for shared classes in TagLib.
|
||||
*
|
||||
* \warning This <b>is not</b> part of the TagLib public API!
|
||||
*/
|
||||
|
||||
class RefCounter
|
||||
{
|
||||
public:
|
||||
RefCounter() : refCount(1) {}
|
||||
void ref() { refCount++; }
|
||||
bool deref() { return ! --refCount ; }
|
||||
int count() { return refCount; }
|
||||
private:
|
||||
uint refCount;
|
||||
};
|
||||
|
||||
/*!
|
||||
* A simple strdup implementation since the standard one creates some wierdness
|
||||
* with delete.
|
||||
*/
|
||||
static inline char *strdup(const char *s)
|
||||
{
|
||||
const int l = ::strlen(s);
|
||||
char *buffer = new char[l];
|
||||
::memcpy(buffer, s, l);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
#endif // DO_NOT_DOCUMENT
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
* \mainpage TagLib
|
||||
* \section intro Introduction
|
||||
* TagLib, is well, a library for reading and editing audio meta data, commonly know as \e tags.
|
||||
*
|
||||
* Some goals of TagLib:
|
||||
* - A clean, high level, C++ API to handling audio meta data.
|
||||
* - Support for at least ID3v1, ID3v2 and Ogg Vorbis \e comments.
|
||||
* - A generic, \e simple API for the most common tagging related functions.
|
||||
* - Binary compatibility between minor releases using the standard KDE/Qt techniques for C++ binary compatibility.
|
||||
* - Make the tagging framework extensible by library users; i.e. it will be possible for libarary users to implement
|
||||
* additional ID3v2 frames, without modifying the TagLib source (through the use of <i>Abstract Factories</i> and
|
||||
* such.
|
||||
*
|
||||
* Because TagLib desires to be toolkit agnostic, in hope of being widely adopted and the most flexible in licensing
|
||||
* TagLib provides many of its own toolkit classes; in fact the only external dependancy that TagLib has, it a
|
||||
* semi-sane STL implementation.
|
||||
*
|
||||
* \section why Why TagLib?
|
||||
*
|
||||
* TagLib was written to fill a gap in the Open Source/Free Software community. Currently there is a lack in the
|
||||
* OSS/FS for a homogenous API to the most common music types. In fact the only semi-portable implementation of the
|
||||
* ID3v2 standard available on Linux is id3lib, which unfortunately is poorly written, poorly documented and which
|
||||
* cycles through maintainers at least once a year (I took my turn some time ago.).
|
||||
*
|
||||
* As TagLib will be initially injected into the KDE community, while I am not linking to any of the KDE or Qt libraries
|
||||
* I have tried to follow the coding style of those libraries. Again, this is in sharp contrast to id3lib, which
|
||||
* basically provides a hybrid C/C++ API and uses a dubious object model.
|
||||
*
|
||||
* I get asked rather frequently why I am replacing id3lib (mostly by people that have never worked with id3lib), if
|
||||
* you are concerned about this please email me; I can provide my lengthy standard rant. :-)
|
||||
*
|
||||
* \section examples Examples:
|
||||
*
|
||||
* I've talked a lot about the \e homogenous API to common music formats. Here's an example of how things (will) work:
|
||||
*
|
||||
* \code
|
||||
*
|
||||
* TagLib::FileRef f("Latex Solar Beef.mp3");
|
||||
* TagLib::String artist = f.tag()->artist(); // artist == "Frank Zappa"
|
||||
*
|
||||
* f.tag()->setAlbum("Fillmore East");
|
||||
* f.save();
|
||||
*
|
||||
* TagLib::FileRef g("Free City Rhymes.ogg");
|
||||
* TagLib::String album = g.tag()->album(); // album == "NYC Ghosts & Flowers"
|
||||
*
|
||||
* g.tag()->setTrack(1);
|
||||
* g.save();
|
||||
*
|
||||
* \endcode
|
||||
*
|
||||
* Notice that these high level functions work for both Ogg \e and MP3. For this high level API, which is suitable for
|
||||
* most applications, the differences between ID3v2, ID3v1, MPEG and Ogg Vorbis can all be ignored.
|
||||
*
|
||||
* \author Scott Wheeler <wheeler@kde.org>
|
||||
*/
|
||||
|
||||
#endif
|
604
toolkit/tbytevector.cpp
Normal file
604
toolkit/tbytevector.cpp
Normal file
@ -0,0 +1,604 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002, 2003 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
* USA *
|
||||
***************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <tstring.h>
|
||||
#include <tdebug.h>
|
||||
|
||||
#include "tbytevector.h"
|
||||
|
||||
namespace TagLib {
|
||||
static const uint crcTable[256] = {
|
||||
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
|
||||
0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
|
||||
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
|
||||
0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
|
||||
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
|
||||
0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
|
||||
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
|
||||
0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
|
||||
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
|
||||
0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
|
||||
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
|
||||
0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
|
||||
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
|
||||
0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
|
||||
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
|
||||
0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
|
||||
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
|
||||
0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
|
||||
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
|
||||
0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
|
||||
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
|
||||
0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
|
||||
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
|
||||
0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
|
||||
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
|
||||
0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
|
||||
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
|
||||
0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
|
||||
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
|
||||
0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
|
||||
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
|
||||
0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
|
||||
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
|
||||
0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
|
||||
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
|
||||
0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
|
||||
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
|
||||
0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
|
||||
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
|
||||
0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
|
||||
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
|
||||
0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
|
||||
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
|
||||
};
|
||||
|
||||
/*!
|
||||
* A templatized find that works both with a ByteVector and a ByteVectorMirror.
|
||||
*/
|
||||
|
||||
template <class Vector>
|
||||
int vectorFind(const Vector &v, const Vector &pattern, uint offset, int byteAlign)
|
||||
{
|
||||
if(pattern.size() > v.size() || offset >= v.size() - 1)
|
||||
return -1;
|
||||
|
||||
// if an offset was specified, just do a recursive call on the substring
|
||||
|
||||
if(offset > 0) {
|
||||
|
||||
// start at the next byte aligned block
|
||||
|
||||
Vector section = v.mid(offset + byteAlign - 1 - offset % byteAlign);
|
||||
int match = section.find(pattern, 0, byteAlign);
|
||||
return match >= 0 ? int(match + offset) : -1;
|
||||
}
|
||||
|
||||
// this is a simplified Boyer-Moore string searching algorithm
|
||||
|
||||
uchar lastOccurrence[256];
|
||||
|
||||
|
||||
for(uint i = 0; i < 256; ++i)
|
||||
lastOccurrence[i] = uchar(pattern.size());
|
||||
|
||||
for(uint i = 0; i < pattern.size() - 1; ++i)
|
||||
lastOccurrence[unsigned(pattern[i])] = uchar(pattern.size() - i - 1);
|
||||
|
||||
for(uint i = pattern.size() - 1; i < v.size(); i += lastOccurrence[uchar(v.at(i))]) {
|
||||
int iBuffer = i;
|
||||
int iPattern = pattern.size() - 1;
|
||||
|
||||
while(iPattern >= 0 && v.at(iBuffer) == pattern[iPattern]) {
|
||||
--iBuffer;
|
||||
--iPattern;
|
||||
}
|
||||
|
||||
if(-1 == iPattern && (iBuffer + 1) % byteAlign == 0)
|
||||
return iBuffer + 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Wraps the accessors to a ByteVector to make the search algorithm access the
|
||||
* elements in reverse.
|
||||
*
|
||||
* \see vectorFind()
|
||||
* \see ByteVector::rfind()
|
||||
*/
|
||||
|
||||
class ByteVectorMirror
|
||||
{
|
||||
public:
|
||||
ByteVectorMirror(const ByteVector &source) : v(source) {}
|
||||
const char operator[](int index) const
|
||||
{
|
||||
return v[v.size() - index - 1];
|
||||
}
|
||||
|
||||
const char at(int index) const
|
||||
{
|
||||
return v.at(v.size() - index - 1);
|
||||
}
|
||||
|
||||
ByteVectorMirror mid(uint index, uint length = 0xffffffff) const
|
||||
{
|
||||
return length == 0xffffffff ? v.mid(0, index) : v.mid(index - length, length);
|
||||
}
|
||||
|
||||
uint size() const
|
||||
{
|
||||
return v.size();
|
||||
}
|
||||
|
||||
int find(const ByteVectorMirror &pattern, uint offset = 0, int byteAlign = 1) const
|
||||
{
|
||||
ByteVectorMirror v(*this);
|
||||
|
||||
const int pos = vectorFind<ByteVectorMirror>(v, pattern, offset, byteAlign);
|
||||
|
||||
// If the offset is zero then we need to adjust the location in the search
|
||||
// to be appropriately reversed. If not we need to account for the fact
|
||||
// that the recursive call (called from the above line) has already ajusted
|
||||
// for this but that the normal templatized find above will add the offset
|
||||
// to the returned value.
|
||||
//
|
||||
// This is a little confusing at first if you don't first stop to think
|
||||
// through the logic involved in the forward search.
|
||||
|
||||
if(pos == -1)
|
||||
return -1;
|
||||
|
||||
if(offset == 0)
|
||||
return size() - pos - pattern.size();
|
||||
else
|
||||
return pos - offset;
|
||||
}
|
||||
|
||||
private:
|
||||
const ByteVector v;
|
||||
};
|
||||
}
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class ByteVector::ByteVectorPrivate : public RefCounter
|
||||
{
|
||||
public:
|
||||
ByteVectorPrivate() : RefCounter() {}
|
||||
ByteVectorPrivate(const std::vector<char> &v) : RefCounter(), data(v) {}
|
||||
ByteVectorPrivate(TagLib::uint size, char value) : RefCounter(), data(size, value) {}
|
||||
|
||||
std::vector<char> data;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// static members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ByteVector ByteVector::null;
|
||||
|
||||
ByteVector ByteVector::fromCString(const char *s, uint length)
|
||||
{
|
||||
ByteVector v;
|
||||
|
||||
if(length == 0xffffffff)
|
||||
v.setData(s);
|
||||
else
|
||||
v.setData(s, length);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
ByteVector ByteVector::fromUInt(uint value, bool mostSignificantByteFirst)
|
||||
{
|
||||
ByteVector v(4, 0);
|
||||
|
||||
for(int i = 0; i < 4; i++)
|
||||
v[i] = uchar(value >> ((mostSignificantByteFirst ? 3 - i : i) * 8) & 0xff);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
ByteVector ByteVector::fromLongLong(long long value, bool mostSignificantByteFirst)
|
||||
{
|
||||
ByteVector v(8, 0);
|
||||
|
||||
for(int i = 0; i < 8; i++)
|
||||
v[i] = uchar(value >> ((mostSignificantByteFirst ? 7 - i : i) * 8) & 0xff);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ByteVector::ByteVector()
|
||||
{
|
||||
d = new ByteVectorPrivate;
|
||||
}
|
||||
|
||||
ByteVector::ByteVector(uint size, char value)
|
||||
{
|
||||
d = new ByteVectorPrivate(size, value);
|
||||
}
|
||||
|
||||
ByteVector::ByteVector(const ByteVector &v) : d(v.d)
|
||||
{
|
||||
d->ref();
|
||||
}
|
||||
|
||||
ByteVector::ByteVector(char c)
|
||||
{
|
||||
d = new ByteVectorPrivate;
|
||||
d->data.push_back(c);
|
||||
}
|
||||
|
||||
ByteVector::ByteVector(const char *data, uint length)
|
||||
{
|
||||
d = new ByteVectorPrivate;
|
||||
setData(data, length);
|
||||
}
|
||||
|
||||
ByteVector::ByteVector(const char *data)
|
||||
{
|
||||
d = new ByteVectorPrivate;
|
||||
setData(data);
|
||||
}
|
||||
|
||||
ByteVector::~ByteVector()
|
||||
{
|
||||
if(d->deref())
|
||||
delete d;
|
||||
}
|
||||
|
||||
void ByteVector::setData(const char *data, uint length)
|
||||
{
|
||||
detach();
|
||||
|
||||
for(uint i = 0; i < length; i++)
|
||||
d->data.push_back(data[i]);
|
||||
}
|
||||
|
||||
void ByteVector::setData(const char *data)
|
||||
{
|
||||
detach();
|
||||
|
||||
for(uint i = 0; data[i] != 0; i++)
|
||||
d->data.push_back(data[i]);
|
||||
}
|
||||
|
||||
char *ByteVector::data()
|
||||
{
|
||||
// A rather obscure feature of the C++ spec that I hadn't thought of that makes
|
||||
// working with C libs much more effecient. There's more here:
|
||||
//
|
||||
// http://www.informit.com/isapi/product_id~{9C84DAB4-FE6E-49C5-BB0A-FB50331233EA}/content/index.asp
|
||||
|
||||
detach();
|
||||
return &(d->data[0]);
|
||||
}
|
||||
|
||||
const char *ByteVector::data() const
|
||||
{
|
||||
return &(d->data[0]);
|
||||
}
|
||||
|
||||
ByteVector ByteVector::mid(uint index, uint length) const
|
||||
{
|
||||
ByteVector v;
|
||||
|
||||
ConstIterator endIt;
|
||||
|
||||
if(length < 0xffffffff && length + index < size())
|
||||
endIt = d->data.begin() + index + length;
|
||||
else
|
||||
endIt = d->data.end();
|
||||
|
||||
v.d->data.insert(v.d->data.begin(), ConstIterator(d->data.begin() + index), endIt);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
char ByteVector::at(uint index) const
|
||||
{
|
||||
return index < size() ? d->data[index] : 0;
|
||||
}
|
||||
|
||||
int ByteVector::find(const ByteVector &pattern, uint offset, int byteAlign) const
|
||||
{
|
||||
return vectorFind<ByteVector>(*this, pattern, offset, byteAlign);
|
||||
}
|
||||
|
||||
int ByteVector::rfind(const ByteVector &pattern, uint offset, int byteAlign) const
|
||||
{
|
||||
// Ok, this is a little goofy, but pretty cool after it sinks in. Instead of
|
||||
// reversing the find method's Boyer-Moore search algorithm I created a "mirror"
|
||||
// for a ByteVector to reverse the behavior of the accessors.
|
||||
|
||||
ByteVectorMirror v(*this);
|
||||
ByteVectorMirror p(pattern);
|
||||
|
||||
return v.find(p, offset, byteAlign);
|
||||
}
|
||||
|
||||
bool ByteVector::containsAt(const ByteVector &pattern, uint offset, uint patternOffset, uint patternLength) const
|
||||
{
|
||||
if(pattern.size() < patternLength)
|
||||
patternLength = pattern.size();
|
||||
|
||||
// do some sanity checking -- all of these things are needed for the search to be valid
|
||||
|
||||
if(patternLength > size() || offset >= size() || patternOffset >= pattern.size() || patternLength == 0)
|
||||
return false;
|
||||
|
||||
// loop through looking for a mismatch
|
||||
|
||||
for(uint i = 0; i < patternLength - patternOffset; i++) {
|
||||
if(at(i + offset) != pattern[i + patternOffset])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ByteVector::startsWith(const ByteVector &pattern) const
|
||||
{
|
||||
return containsAt(pattern, 0);
|
||||
}
|
||||
|
||||
bool ByteVector::endsWith(const ByteVector &pattern) const
|
||||
{
|
||||
return containsAt(pattern, size() - pattern.size());
|
||||
}
|
||||
|
||||
int ByteVector::endsWithPartialMatch(const ByteVector &pattern) const
|
||||
{
|
||||
if(pattern.size() > size())
|
||||
return -1;
|
||||
|
||||
const int startIndex = size() - pattern.size();
|
||||
|
||||
// try to match the last n-1 bytes from the vector (where n is the pattern
|
||||
// size) -- continue trying to match n-2, n-3...1 bytes
|
||||
|
||||
for(uint i = 1; i < pattern.size(); i++) {
|
||||
if(containsAt(pattern, startIndex + i, 0, pattern.size() - i))
|
||||
return startIndex + i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void ByteVector::append(const ByteVector &v)
|
||||
{
|
||||
detach();
|
||||
|
||||
for(uint i = 0; i < v.size(); i++)
|
||||
d->data.push_back(v[i]);
|
||||
}
|
||||
|
||||
void ByteVector::clear()
|
||||
{
|
||||
detach();
|
||||
d->data.clear();
|
||||
}
|
||||
|
||||
TagLib::uint ByteVector::size() const
|
||||
{
|
||||
return d->data.size();
|
||||
}
|
||||
|
||||
ByteVector &ByteVector::resize(uint size, char padding)
|
||||
{
|
||||
if(d->data.size() < size) {
|
||||
d->data.reserve(size);
|
||||
d->data.insert(d->data.end(), size - d->data.size(), padding);
|
||||
}
|
||||
else
|
||||
d->data.erase(d->data.begin() + size, d->data.end());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
ByteVector::Iterator ByteVector::begin()
|
||||
{
|
||||
return d->data.begin();
|
||||
}
|
||||
|
||||
ByteVector::ConstIterator ByteVector::begin() const
|
||||
{
|
||||
return d->data.begin();
|
||||
}
|
||||
|
||||
ByteVector::Iterator ByteVector::end()
|
||||
{
|
||||
return d->data.end();
|
||||
}
|
||||
|
||||
ByteVector::ConstIterator ByteVector::end() const
|
||||
{
|
||||
return d->data.end();
|
||||
}
|
||||
|
||||
bool ByteVector::isNull() const
|
||||
{
|
||||
return d == null.d;
|
||||
}
|
||||
|
||||
bool ByteVector::isEmpty() const
|
||||
{
|
||||
return d->data.size() == 0;
|
||||
}
|
||||
|
||||
TagLib::uint ByteVector::checksum() const
|
||||
{
|
||||
uint sum = 0;
|
||||
for(ByteVector::ConstIterator it = begin(); it != end(); ++it)
|
||||
sum = (sum << 8) ^ crcTable[((sum >> 24) & 0xff) ^ uchar(*it)];
|
||||
return sum;
|
||||
}
|
||||
|
||||
TagLib::uint ByteVector::toUInt(bool mostSignificantByteFirst) const
|
||||
{
|
||||
uint sum = 0;
|
||||
int last = d->data.size() > 4 ? 3 : d->data.size() - 1;
|
||||
|
||||
for(int i = 0; i <= last; i++)
|
||||
sum |= uchar(d->data[i]) << ((mostSignificantByteFirst ? last - i : i) * 8);
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
long long ByteVector::toLongLong(bool mostSignificantByteFirst) const
|
||||
{
|
||||
// Just do all of the bit operations on the unsigned value and use an implicit
|
||||
// cast on the way out.
|
||||
|
||||
unsigned long long sum = 0;
|
||||
int last = d->data.size() > 8 ? 7 : d->data.size() - 1;
|
||||
|
||||
for(int i = 0; i <= last; i++)
|
||||
sum |= (unsigned long long) uchar(d->data[i]) << ((mostSignificantByteFirst ? last - i : i) * 8);
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
const char &ByteVector::operator[](int index) const
|
||||
{
|
||||
return d->data[index];
|
||||
}
|
||||
|
||||
char &ByteVector::operator[](int index)
|
||||
{
|
||||
detach();
|
||||
|
||||
return d->data[index];
|
||||
}
|
||||
|
||||
bool ByteVector::operator==(const ByteVector &v) const
|
||||
{
|
||||
if(size() != v.size())
|
||||
return false;
|
||||
|
||||
for(uint i = 0; i < size(); i++) {
|
||||
if(at(i) != v.at(i))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ByteVector::operator!=(const ByteVector &v) const
|
||||
{
|
||||
return !operator==(v);
|
||||
}
|
||||
|
||||
bool ByteVector::operator==(const char *s) const
|
||||
{
|
||||
return operator==(fromCString(s));
|
||||
}
|
||||
|
||||
bool ByteVector::operator!=(const char *s) const
|
||||
{
|
||||
return !operator==(s);
|
||||
}
|
||||
|
||||
bool ByteVector::operator<(const ByteVector &v) const
|
||||
{
|
||||
for(uint i = 0; i < size() && i < v.size(); i++) {
|
||||
if(at(i) < v.at(i))
|
||||
return true;
|
||||
else if(at(i) > v.at(i))
|
||||
return false;
|
||||
}
|
||||
|
||||
return size() < v.size();
|
||||
}
|
||||
|
||||
bool ByteVector::operator>(const ByteVector &v) const
|
||||
{
|
||||
return !operator<(v);
|
||||
}
|
||||
|
||||
ByteVector ByteVector::operator+(const ByteVector &v) const
|
||||
{
|
||||
ByteVector sum(*this);
|
||||
sum.append(v);
|
||||
return sum;
|
||||
}
|
||||
|
||||
ByteVector &ByteVector::operator=(const ByteVector &v)
|
||||
{
|
||||
if(&v == this)
|
||||
return *this;
|
||||
|
||||
if(d->deref())
|
||||
delete d;
|
||||
|
||||
d = v.d;
|
||||
d->ref();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ByteVector &ByteVector::operator=(char c)
|
||||
{
|
||||
if(d->deref())
|
||||
delete d;
|
||||
*this = ByteVector(c);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ByteVector &ByteVector::operator=(const char *data)
|
||||
{
|
||||
if(d->deref())
|
||||
delete d;
|
||||
*this = ByteVector(data);
|
||||
return *this;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ByteVector::detach()
|
||||
{
|
||||
if(d->count() > 1) {
|
||||
d->deref();
|
||||
d = new ByteVectorPrivate(d->data);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// related functions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::ostream &operator<<(std::ostream &s, const ByteVector &v)
|
||||
{
|
||||
for(TagLib::uint i = 0; i < v.size(); i++)
|
||||
s << v[i];
|
||||
return s;
|
||||
}
|
377
toolkit/tbytevector.h
Normal file
377
toolkit/tbytevector.h
Normal file
@ -0,0 +1,377 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002, 2003 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
* USA *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_BYTEVECTOR_H
|
||||
#define TAGLIB_BYTEVECTOR_H
|
||||
|
||||
#include "taglib.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
//! A byte vector
|
||||
|
||||
/*!
|
||||
* This class provides a byte vector with some methods that are useful for
|
||||
* tagging purposes. Many of the search functions are tailored to what is
|
||||
* useful for finding tag related paterns in a data array.
|
||||
*/
|
||||
|
||||
class ByteVector
|
||||
{
|
||||
public:
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
typedef std::vector<char>::iterator Iterator;
|
||||
typedef std::vector<char>::const_iterator ConstIterator;
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* Constructs an empty byte vector.
|
||||
*/
|
||||
ByteVector();
|
||||
|
||||
/*!
|
||||
* Construct a vector of size \a size with all values set to \a value by
|
||||
* default.
|
||||
*/
|
||||
ByteVector(uint size, char value = 0);
|
||||
|
||||
/*!
|
||||
* Contructs a byte vector that is a copy of \a v.
|
||||
*/
|
||||
ByteVector(const ByteVector &v);
|
||||
|
||||
/*!
|
||||
* Contructs a byte vector that contains \a c.
|
||||
*/
|
||||
ByteVector(char c);
|
||||
|
||||
/*!
|
||||
* Constructs a byte vector that copies \a data for up to \a length bytes.
|
||||
*/
|
||||
ByteVector(const char *data, uint length);
|
||||
|
||||
/*!
|
||||
* Constructs a byte vector that copies \a data up to the first null
|
||||
* byte. The behavior is undefined if \a data is not null terminated.
|
||||
* This is particularly useful for constructing byte arrays from string
|
||||
* constants.
|
||||
*/
|
||||
ByteVector(const char *data);
|
||||
|
||||
/*!
|
||||
* Destroys this ByteVector instance.
|
||||
*/
|
||||
virtual ~ByteVector();
|
||||
|
||||
/*!
|
||||
* Sets the data for the byte array using the first \a length bytes of \a data
|
||||
*/
|
||||
void setData(const char *data, uint length);
|
||||
|
||||
/*!
|
||||
* Sets the data for the byte array copies \a data up to the first null
|
||||
* byte. The behavior is undefined if \a data is not null terminated.
|
||||
*/
|
||||
void setData(const char *data);
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the internal data structure.
|
||||
*
|
||||
* \warning Care should be taken when modifying this data structure as it is
|
||||
* easy to corrupt the ByteVector when doing so. Specifically, while the
|
||||
* data may be changed, its length may not be.
|
||||
*/
|
||||
char *data();
|
||||
|
||||
/*!
|
||||
* Returns a pointer to the internal data structure which may not be modified.
|
||||
*/
|
||||
const char *data() const;
|
||||
|
||||
/*!
|
||||
* Returns a byte vector made up of the bytes starting at \a index and
|
||||
* for \a length bytes. If \a length is not specified it will return the bytes
|
||||
* from \a index to the end of the vector.
|
||||
*/
|
||||
ByteVector mid(uint index, uint length = 0xffffffff) const;
|
||||
|
||||
/*!
|
||||
* This essentially performs the same as operator[](), but instead of causing
|
||||
* a runtime error if the index is out of bounds, it will return a null byte.
|
||||
*/
|
||||
char at(uint index) const;
|
||||
|
||||
/*!
|
||||
* Searches the ByteVector for \a pattern starting at \a offset and returns
|
||||
* the offset. Returns -1 if the pattern was not found. If \a byteAlign is
|
||||
* specified the pattern will only be matched if it starts on a byteDivisible
|
||||
* by \a byteAlign.
|
||||
*/
|
||||
int find(const ByteVector &pattern, uint offset = 0, int byteAlign = 1) const;
|
||||
|
||||
/*!
|
||||
* Searches the ByteVector for \a pattern starting from either the end of the
|
||||
* vector or \a offset and returns the offset. Returns -1 if the pattern was
|
||||
* not found. If \a byteAlign is specified the pattern will only be matched
|
||||
* if it starts on a byteDivisible by \a byteAlign.
|
||||
*/
|
||||
int rfind(const ByteVector &pattern, uint offset = 0, int byteAlign = 1) const;
|
||||
|
||||
/*!
|
||||
* Checks to see if the vector contains the \a pattern starting at position
|
||||
* \a offset. Optionally, if you only want to search for part of the pattern
|
||||
* you can specify an offset within the pattern to start from. Also, you can
|
||||
* specify to only check for the first \a patternLength bytes of \a pattern with
|
||||
* the \a patternLength argument.
|
||||
*/
|
||||
bool containsAt(const ByteVector &pattern, uint offset, uint patternOffset = 0, uint patternLength = 0xffffffff) const;
|
||||
|
||||
/*!
|
||||
* Returns true if the vector starts with \a pattern.
|
||||
*/
|
||||
bool startsWith(const ByteVector &pattern) const;
|
||||
|
||||
/*!
|
||||
* Returns true if the vector ends with \a pattern.
|
||||
*/
|
||||
bool endsWith(const ByteVector &pattern) const;
|
||||
|
||||
/*!
|
||||
* Checks for a partial match of \a pattern at the end of the vector. It
|
||||
* returns the offset of the partial match within the vector, or -1 if the
|
||||
* pattern is not found. This method is particularly useful when searching for
|
||||
* patterns that start in one vector and end in another. When combined with
|
||||
* startsWith() it can be used to find a pattern that overlaps two buffers.
|
||||
*
|
||||
* \note This will not match the complete pattern at the end of the string; use
|
||||
* endsWith() for that.
|
||||
*/
|
||||
int endsWithPartialMatch(const ByteVector &pattern) const;
|
||||
|
||||
/*!
|
||||
* Appends \a v to the end of the ByteVector.
|
||||
*/
|
||||
void append(const ByteVector &v);
|
||||
|
||||
/*!
|
||||
* Clears the data.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/*!
|
||||
* Returns the size of the array.
|
||||
*/
|
||||
uint size() const;
|
||||
|
||||
/*!
|
||||
* Resize the vector to \a size. If the vector is currently less than
|
||||
* \a size, pad the remaining spaces with \a padding. Returns a reference
|
||||
* to the resized vector.
|
||||
*/
|
||||
ByteVector &resize(uint size, char padding = 0);
|
||||
|
||||
/*!
|
||||
* Returns an Iterator that points to the front of the vector.
|
||||
*/
|
||||
Iterator begin();
|
||||
|
||||
/*!
|
||||
* Returns a ConstIterator that points to the front of the vector.
|
||||
*/
|
||||
ConstIterator begin() const;
|
||||
|
||||
/*!
|
||||
* Returns an Iterator that points to the back of the vector.
|
||||
*/
|
||||
Iterator end();
|
||||
|
||||
/*!
|
||||
* Returns a ConstIterator that points to the back of the vector.
|
||||
*/
|
||||
ConstIterator end() const;
|
||||
|
||||
/*!
|
||||
* Returns true if the vector is null.
|
||||
*
|
||||
* \note A vector may be empty without being null.
|
||||
* \see isEmpty()
|
||||
*/
|
||||
bool isNull() const;
|
||||
|
||||
/*!
|
||||
* Returns true if the ByteVector is empty.
|
||||
*
|
||||
* \see size()
|
||||
* \see isNull()
|
||||
*/
|
||||
bool isEmpty() const;
|
||||
|
||||
/*!
|
||||
* Returns a CRC checksum of the byte vector's data.
|
||||
*/
|
||||
uint checksum() const;
|
||||
|
||||
/*!
|
||||
* Converts the first 4 bytes of the vector to an unsigned integer.
|
||||
*
|
||||
* If \a mostSignificantByteFirst is true this will operate left to right
|
||||
* evaluating the integer. For example if \a mostSignificantByteFirst is
|
||||
* true then $00 $00 $00 $01 == 0x00000001 == 1, if false, $01 00 00 00 ==
|
||||
* 0x01000000 == 1.
|
||||
*
|
||||
* \see fromUInt()
|
||||
*/
|
||||
uint toUInt(bool mostSignificantByteFirst = true) const;
|
||||
|
||||
|
||||
/*!
|
||||
* Converts the first 8 bytes of the vector to a (signed) long long.
|
||||
*
|
||||
* If \a mostSignificantByteFirst is true this will operate left to right
|
||||
* evaluating the integer. For example if \a mostSignificantByteFirst is
|
||||
* true then $00 00 00 00 00 00 00 01 == 0x0000000000000001 == 1,
|
||||
* if false, $01 00 00 00 00 00 00 00 == 0x0100000000000000 == 1.
|
||||
*
|
||||
* \see fromUInt()
|
||||
*/
|
||||
long long toLongLong(bool mostSignificantByteFirst = true) const;
|
||||
|
||||
/*!
|
||||
* Creates a 4 byte ByteVector based on \a value. If
|
||||
* \a mostSignificantByteFirst is true, then this will operate left to right
|
||||
* in building the ByteVector. For example if \a mostSignificantByteFirst is
|
||||
* true then $00 00 00 01 == 0x00000001 == 1, if false, $01 00 00 00 ==
|
||||
* 0x01000000 == 1.
|
||||
*
|
||||
* \see toUInt()
|
||||
*/
|
||||
static ByteVector fromUInt(uint value, bool mostSignificantByteFirst = true);
|
||||
|
||||
/*!
|
||||
* Creates a 8 byte ByteVector based on \a value. If
|
||||
* \a mostSignificantByteFirst is true, then this will operate left to right
|
||||
* in building the ByteVector. For example if \a mostSignificantByteFirst is
|
||||
* true then $00 00 00 01 == 0x0000000000000001 == 1, if false,
|
||||
* $01 00 00 00 00 00 00 00 == 0x0100000000000000 == 1.
|
||||
*
|
||||
* \see toLongLong()
|
||||
*/
|
||||
static ByteVector fromLongLong(long long value, bool mostSignificantByteFirst = true);
|
||||
|
||||
/*!
|
||||
* Returns a ByteVector based on the CString \a s.
|
||||
*/
|
||||
static ByteVector fromCString(const char *s, uint length = 0xffffffff);
|
||||
|
||||
/*!
|
||||
* Returns a const refernence to the byte at \a index.
|
||||
*/
|
||||
const char &operator[](int index) const;
|
||||
|
||||
/*!
|
||||
* Returns a reference to the byte at \a index.
|
||||
*/
|
||||
char &operator[](int index);
|
||||
|
||||
/*!
|
||||
* Returns true if this ByteVector and \a v are equal.
|
||||
*/
|
||||
bool operator==(const ByteVector &v) const;
|
||||
|
||||
/*!
|
||||
* Returns true if this ByteVector and \a v are not equal.
|
||||
*/
|
||||
bool operator!=(const ByteVector &v) const;
|
||||
|
||||
/*!
|
||||
* Returns true if this ByteVector and the null terminated C string \a s
|
||||
* contain the same data.
|
||||
*/
|
||||
bool operator==(const char *s) const;
|
||||
|
||||
/*!
|
||||
* Returns true if this ByteVector and the null terminated C string \a s
|
||||
* do not contain the same data.
|
||||
*/
|
||||
bool operator!=(const char *s) const;
|
||||
|
||||
/*!
|
||||
* Returns true if this ByteVector is less than \a v. The value of the
|
||||
* vectors is determined by evaluating the character from left to right, and
|
||||
* in the event one vector is a superset of the other, the size is used.
|
||||
*/
|
||||
bool operator<(const ByteVector &v) const;
|
||||
|
||||
/*!
|
||||
* Returns true if this ByteVector is greater than \a v.
|
||||
*/
|
||||
bool operator>(const ByteVector &v) const;
|
||||
|
||||
/*!
|
||||
* Returns a vector that is \a v appended to this vector.
|
||||
*/
|
||||
ByteVector operator+(const ByteVector &v) const;
|
||||
|
||||
/*!
|
||||
* Copies ByteVector \a v.
|
||||
*/
|
||||
ByteVector &operator=(const ByteVector &v);
|
||||
|
||||
/*!
|
||||
* Copies ByteVector \a v.
|
||||
*/
|
||||
ByteVector &operator=(char c);
|
||||
|
||||
/*!
|
||||
* Copies ByteVector \a v.
|
||||
*/
|
||||
ByteVector &operator=(const char *data);
|
||||
|
||||
/*!
|
||||
* A static, empty ByteVector which is convenient and fast (since returning
|
||||
* an empty or "null" value does not require instantiating a new ByteVector).
|
||||
*/
|
||||
static ByteVector null;
|
||||
|
||||
protected:
|
||||
/*
|
||||
* If this ByteVector is being shared via implicit sharing, do a deep copy
|
||||
* of the data and separate from the shared members. This should be called
|
||||
* by all non-const subclass members.
|
||||
*/
|
||||
void detach();
|
||||
|
||||
private:
|
||||
class ByteVectorPrivate;
|
||||
ByteVectorPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
* \relates TagLib::ByteVector
|
||||
* Streams the ByteVector \a v to the output stream \a s.
|
||||
*/
|
||||
std::ostream &operator<<(std::ostream &s, const TagLib::ByteVector &v);
|
||||
|
||||
#endif
|
77
toolkit/tbytevectorlist.h
Normal file
77
toolkit/tbytevectorlist.h
Normal file
@ -0,0 +1,77 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002, 2003 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
* USA *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_BYTEVECTORLIST_H
|
||||
#define TAGLIB_BYTEVECTORLIST_H
|
||||
|
||||
#include "tbytevector.h"
|
||||
#include "tlist.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
//! A list of ByteVectors
|
||||
|
||||
/*!
|
||||
* A List specialization with some handy features useful for ByteVectors.
|
||||
*/
|
||||
|
||||
class ByteVectorList : public List<ByteVector>
|
||||
{
|
||||
public:
|
||||
|
||||
/*!
|
||||
* Construct an empty ByteVectorList.
|
||||
*/
|
||||
ByteVectorList();
|
||||
|
||||
/*!
|
||||
* Destroys this ByteVectorList instance.
|
||||
*/
|
||||
virtual ~ByteVectorList();
|
||||
|
||||
/*!
|
||||
* Make a shallow, implicitly shared, copy of \a l. Because this is
|
||||
* implicitly shared, this method is lightweight and suitable for
|
||||
* pass-by-value usage.
|
||||
*/
|
||||
ByteVectorList(const ByteVectorList &l);
|
||||
|
||||
/*!
|
||||
* Convert the ByteVectorList to a ByteVector separated by \a separator. By
|
||||
* default a space is used.
|
||||
*/
|
||||
ByteVector toByteVector(const ByteVector &separator = " ") const;
|
||||
|
||||
/*!
|
||||
* Splits the ByteVector \a v into several strings at \a pattern. This will
|
||||
* not include the pattern in the returned ByteVectors.
|
||||
*/
|
||||
static ByteVectorList split(const ByteVector &v, const ByteVector &pattern,
|
||||
int byteAlign = 1);
|
||||
|
||||
private:
|
||||
class ByteVectorListPrivate;
|
||||
ByteVectorListPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
51
toolkit/tdebug.cpp
Normal file
51
toolkit/tdebug.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002, 2003 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
* USA *
|
||||
***************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
#include <bitset>
|
||||
|
||||
#include "tdebug.h"
|
||||
#include "tstring.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
#ifndef NDEBUG
|
||||
void TagLib::debug(const String &s)
|
||||
{
|
||||
std::cerr << "TagLib: " << s << std::endl;
|
||||
}
|
||||
|
||||
void TagLib::debugData(const ByteVector &v)
|
||||
{
|
||||
for(uint i = 0; i < v.size(); i++) {
|
||||
|
||||
std::cout << "*** [" << i << "] - '" << char(v[i]) << "' - int " << int(v[i])
|
||||
<< std::endl;
|
||||
|
||||
std::bitset<8> b(v[i]);
|
||||
|
||||
for(int j = 0; j < 8; j++)
|
||||
std::cout << i << ":" << j << " " << b.test(j) << std::endl;
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
#endif
|
67
toolkit/tdebug.h
Normal file
67
toolkit/tdebug.h
Normal file
@ -0,0 +1,67 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002, 2003 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
* USA *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_DEBUG_H
|
||||
#define TAGLIB_DEBUG_H
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
class String;
|
||||
class ByteVector;
|
||||
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
#ifndef NDEBUG
|
||||
|
||||
/*!
|
||||
* A simple function that prints debugging output to cerr if debugging is
|
||||
* not disabled.
|
||||
*
|
||||
* \warning Do not use this outside of TagLib, it could lead to undefined
|
||||
* symbols in your build if TagLib is built with NDEBUG defined and your
|
||||
* application is not.
|
||||
*
|
||||
* \internal
|
||||
*/
|
||||
void debug(const String &s);
|
||||
|
||||
/*!
|
||||
* For debugging binary data.
|
||||
*
|
||||
* \warning Do not use this outside of TagLib, it could lead to undefined
|
||||
* symbols in your build if TagLib is built with NDEBUG defined and your
|
||||
* application is not.
|
||||
*
|
||||
* \internal
|
||||
*/
|
||||
void debugData(const ByteVector &v);
|
||||
|
||||
#else
|
||||
|
||||
// Define these to an empty statement if debugging is disabled.
|
||||
|
||||
#define debug(x)
|
||||
#define debugData(x)
|
||||
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
484
toolkit/tfile.cpp
Normal file
484
toolkit/tfile.cpp
Normal file
@ -0,0 +1,484 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002, 2003 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
* USA *
|
||||
***************************************************************************/
|
||||
|
||||
#include "tfile.h"
|
||||
#include "tstring.h"
|
||||
#include "tdebug.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class File::FilePrivate
|
||||
{
|
||||
public:
|
||||
FilePrivate(const char *fileName) :
|
||||
file(0),
|
||||
name(fileName),
|
||||
readOnly(true),
|
||||
valid(true)
|
||||
{}
|
||||
|
||||
~FilePrivate()
|
||||
{
|
||||
delete [] name;
|
||||
}
|
||||
|
||||
FILE *file;
|
||||
const char *name;
|
||||
bool readOnly;
|
||||
bool valid;
|
||||
static const uint bufferSize = 1024;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
File::File(const char *file)
|
||||
{
|
||||
d = new FilePrivate(strdup(file));
|
||||
|
||||
d->readOnly = !isWritable(file);
|
||||
d->file = fopen(file, d->readOnly ? "r" : "r+");
|
||||
|
||||
if(!d->file)
|
||||
debug("Could not open file " + String(file));
|
||||
}
|
||||
|
||||
File::~File()
|
||||
{
|
||||
if(d->file)
|
||||
fclose(d->file);
|
||||
delete d;
|
||||
}
|
||||
|
||||
const char *File::name() const
|
||||
{
|
||||
return d->name;
|
||||
}
|
||||
|
||||
ByteVector File::readBlock(ulong length)
|
||||
{
|
||||
if(!d->file) {
|
||||
debug("File::readBlock() -- Invalid File");
|
||||
return ByteVector::null;
|
||||
}
|
||||
|
||||
ByteVector v(static_cast<uint>(length));
|
||||
const int count = fread(v.data(), sizeof(char), length, d->file);
|
||||
v.resize(count);
|
||||
return v;
|
||||
}
|
||||
|
||||
void File::writeBlock(const ByteVector &data)
|
||||
{
|
||||
if(!d->file)
|
||||
return;
|
||||
|
||||
if(d->readOnly) {
|
||||
debug("File::writeBlock() -- attempted to write to a file that is not writable");
|
||||
return;
|
||||
}
|
||||
|
||||
fwrite(data.data(), sizeof(char), data.size(), d->file);
|
||||
}
|
||||
|
||||
long File::find(const ByteVector &pattern, long fromOffset, const ByteVector &before)
|
||||
{
|
||||
if(!d->file || pattern.size() > d->bufferSize)
|
||||
return -1;
|
||||
|
||||
// The position in the file that the current buffer starts at.
|
||||
|
||||
long bufferOffset = fromOffset;
|
||||
ByteVector buffer;
|
||||
|
||||
// These variables are used to keep track of a partial match that happens at
|
||||
// the end of a buffer.
|
||||
|
||||
int previousPartialMatch = -1;
|
||||
int beforePreviousPartialMatch = -1;
|
||||
|
||||
// Save the location of the current read pointer. We will restore the
|
||||
// position using seek() before all returns.
|
||||
|
||||
long originalPosition = tell();
|
||||
|
||||
// Start the search at the offset.
|
||||
|
||||
seek(fromOffset);
|
||||
|
||||
// This loop is the crux of the find method. There are three cases that we
|
||||
// want to account for:
|
||||
//
|
||||
// (1) The previously searched buffer contained a partial match of the search
|
||||
// pattern and we want to see if the next one starts with the remainder of
|
||||
// that pattern.
|
||||
//
|
||||
// (2) The search pattern is wholly contained within the current buffer.
|
||||
//
|
||||
// (3) The current buffer ends with a partial match of the pattern. We will
|
||||
// note this for use in the next itteration, where we will check for the rest
|
||||
// of the pattern.
|
||||
//
|
||||
// All three of these are done in two steps. First we check for the pattern
|
||||
// and do things appropriately if a match (or partial match) is found. We
|
||||
// then check for "before". The order is important because it gives priority
|
||||
// to "real" matches.
|
||||
|
||||
for(buffer = readBlock(d->bufferSize); buffer.size() > 0; buffer = readBlock(d->bufferSize)) {
|
||||
|
||||
// (1) previous partial match
|
||||
|
||||
if(previousPartialMatch >= 0 && int(d->bufferSize) > previousPartialMatch) {
|
||||
const int patternOffset = (d->bufferSize - previousPartialMatch);
|
||||
if(buffer.containsAt(pattern, 0, patternOffset)) {
|
||||
seek(originalPosition);
|
||||
return bufferOffset - d->bufferSize + previousPartialMatch;
|
||||
}
|
||||
}
|
||||
|
||||
if(!before.isNull() && beforePreviousPartialMatch >= 0 && int(d->bufferSize) > beforePreviousPartialMatch) {
|
||||
const int beforeOffset = (d->bufferSize - beforePreviousPartialMatch);
|
||||
if(buffer.containsAt(before, 0, beforeOffset)) {
|
||||
seek(originalPosition);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// (2) pattern contained in current buffer
|
||||
|
||||
long location = buffer.find(pattern);
|
||||
if(location >= 0) {
|
||||
seek(originalPosition);
|
||||
return bufferOffset + location;
|
||||
}
|
||||
|
||||
if(!before.isNull() && buffer.find(before) >= 0) {
|
||||
seek(originalPosition);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// (3) partial match
|
||||
|
||||
previousPartialMatch = buffer.endsWithPartialMatch(pattern);
|
||||
|
||||
if(!before.isNull())
|
||||
beforePreviousPartialMatch = buffer.endsWithPartialMatch(before);
|
||||
|
||||
bufferOffset += d->bufferSize;
|
||||
}
|
||||
|
||||
// Since we hit the end of the file, reset the status before continuing.
|
||||
|
||||
clear();
|
||||
|
||||
seek(originalPosition);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
long File::rfind(const ByteVector &pattern, long fromOffset, const ByteVector &before)
|
||||
{
|
||||
if(!d->file || pattern.size() > d->bufferSize)
|
||||
return -1;
|
||||
|
||||
// The position in the file that the current buffer starts at.
|
||||
|
||||
ByteVector buffer;
|
||||
|
||||
// These variables are used to keep track of a partial match that happens at
|
||||
// the end of a buffer.
|
||||
|
||||
/*
|
||||
int previousPartialMatch = -1;
|
||||
int beforePreviousPartialMatch = -1;
|
||||
*/
|
||||
|
||||
// Save the location of the current read pointer. We will restore the
|
||||
// position using seek() before all returns.
|
||||
|
||||
long originalPosition = tell();
|
||||
|
||||
// Start the search at the offset.
|
||||
|
||||
long bufferOffset;
|
||||
if(fromOffset == 0) {
|
||||
seek(-1 * d->bufferSize, End);
|
||||
bufferOffset = tell();
|
||||
}
|
||||
else {
|
||||
seek(fromOffset + -1 * d->bufferSize, Beginning);
|
||||
bufferOffset = tell();
|
||||
}
|
||||
|
||||
// See the notes in find() for an explanation of this algorithm.
|
||||
|
||||
for(buffer = readBlock(d->bufferSize); buffer.size() > 0; buffer = readBlock(d->bufferSize)) {
|
||||
|
||||
// TODO: (1) previous partial match
|
||||
|
||||
// (2) pattern contained in current buffer
|
||||
|
||||
long location = buffer.rfind(pattern);
|
||||
if(location >= 0) {
|
||||
seek(originalPosition);
|
||||
return bufferOffset + location;
|
||||
}
|
||||
|
||||
if(!before.isNull() && buffer.find(before) >= 0) {
|
||||
seek(originalPosition);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TODO: (3) partial match
|
||||
|
||||
bufferOffset -= d->bufferSize;
|
||||
seek(bufferOffset);
|
||||
}
|
||||
|
||||
// Since we hit the end of the file, reset the status before continuing.
|
||||
|
||||
clear();
|
||||
|
||||
seek(originalPosition);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void File::insert(const ByteVector &data, ulong start, ulong replace)
|
||||
{
|
||||
if(!d->file)
|
||||
return;
|
||||
|
||||
if(data.size() == replace) {
|
||||
seek(start);
|
||||
writeBlock(data);
|
||||
return;
|
||||
}
|
||||
else if(data.size() < replace) {
|
||||
seek(start);
|
||||
writeBlock(data);
|
||||
removeBlock(start + data.size(), replace - data.size());
|
||||
return;
|
||||
}
|
||||
|
||||
// Woohoo! Faster (about 20%) than id3lib at last. I had to get hardcore
|
||||
// and avoid TagLib's high level API for rendering just copying parts of
|
||||
// the file that don't contain tag data.
|
||||
//
|
||||
// Now I'll explain the steps in this ugliness:
|
||||
|
||||
// First, make sure that we're working with a buffer that is longer than
|
||||
// the *differnce* in the tag sizes. We want to avoid overwriting parts
|
||||
// that aren't yet in memory, so this is necessary.
|
||||
|
||||
ulong bufferLength = bufferSize();
|
||||
while(data.size() - replace > bufferLength)
|
||||
bufferLength += bufferSize();
|
||||
|
||||
// Set where to start the reading and writing.
|
||||
|
||||
long readPosition = start + replace;
|
||||
long writePosition = start;
|
||||
|
||||
ByteVector buffer;
|
||||
ByteVector aboutToOverwrite(static_cast<uint>(bufferLength));
|
||||
|
||||
// This is basically a special case of the loop below. Here we're just
|
||||
// doing the same steps as below, but since we aren't using the same buffer
|
||||
// size -- instead we're using the tag size -- this has to be handled as a
|
||||
// special case. We're also using File::writeBlock() just for the tag.
|
||||
// That's a bit slower than using char *'s so, we're only doing it here.
|
||||
|
||||
seek(readPosition);
|
||||
int bytesRead = fread(aboutToOverwrite.data(), sizeof(char), bufferLength, d->file);
|
||||
readPosition += bufferLength;
|
||||
|
||||
seek(writePosition);
|
||||
writeBlock(data);
|
||||
writePosition += data.size();
|
||||
|
||||
buffer = aboutToOverwrite;
|
||||
|
||||
// Ok, here's the main loop. We want to loop until the read fails, which
|
||||
// means that we hit the end of the file.
|
||||
|
||||
while(bytesRead != 0) {
|
||||
|
||||
// Seek to the current read position and read the data that we're about
|
||||
// to overwrite. Appropriately increment the readPosition.
|
||||
|
||||
seek(readPosition);
|
||||
bytesRead = fread(aboutToOverwrite.data(), sizeof(char), bufferLength, d->file);
|
||||
aboutToOverwrite.resize(bytesRead);
|
||||
readPosition += bufferLength;
|
||||
|
||||
// Check to see if we just read the last block. We need to call clear()
|
||||
// if we did so that the last write succeeds.
|
||||
|
||||
if(ulong(bytesRead) < bufferLength)
|
||||
clear();
|
||||
|
||||
// Seek to the write position and write our buffer. Increment the
|
||||
// writePosition.
|
||||
|
||||
seek(writePosition);
|
||||
fwrite(buffer.data(), sizeof(char), bufferLength, d->file);
|
||||
writePosition += bufferLength;
|
||||
|
||||
// Make the current buffer the data that we read in the beginning.
|
||||
|
||||
buffer = aboutToOverwrite;
|
||||
|
||||
// Again, we need this for the last write. We don't want to write garbage
|
||||
// at the end of our file, so we need to set the buffer size to the amount
|
||||
// that we actually read.
|
||||
|
||||
bufferLength = bytesRead;
|
||||
}
|
||||
}
|
||||
|
||||
void File::removeBlock(ulong start, ulong length)
|
||||
{
|
||||
if(!d->file)
|
||||
return;
|
||||
|
||||
ulong bufferLength = bufferSize();
|
||||
|
||||
long readPosition = start + length;
|
||||
long writePosition = start;
|
||||
|
||||
ByteVector buffer(static_cast<uint>(bufferLength));
|
||||
|
||||
ulong bytesRead = true;
|
||||
|
||||
while(bytesRead != 0) {
|
||||
seek(readPosition);
|
||||
bytesRead = fread(buffer.data(), sizeof(char), bufferLength, d->file);
|
||||
buffer.resize(bytesRead);
|
||||
readPosition += bytesRead;
|
||||
|
||||
// Check to see if we just read the last block. We need to call clear()
|
||||
// if we did so that the last write succeeds.
|
||||
|
||||
if(bytesRead < bufferLength)
|
||||
clear();
|
||||
|
||||
seek(writePosition);
|
||||
fwrite(buffer.data(), sizeof(char), bytesRead, d->file);
|
||||
writePosition += bytesRead;
|
||||
}
|
||||
truncate(writePosition);
|
||||
}
|
||||
|
||||
bool File::readOnly() const
|
||||
{
|
||||
return d->readOnly;
|
||||
}
|
||||
|
||||
bool File::isReadable(const char *file)
|
||||
{
|
||||
return access(file, R_OK) == 0;
|
||||
}
|
||||
|
||||
bool File::isOpen() const
|
||||
{
|
||||
return d->file;
|
||||
}
|
||||
|
||||
bool File::isValid() const
|
||||
{
|
||||
return d->file && d->valid;
|
||||
}
|
||||
|
||||
void File::seek(long offset, Position p)
|
||||
{
|
||||
if(!d->file) {
|
||||
debug("File::seek() -- trying to seek in a file that isn't opened.");
|
||||
return;
|
||||
}
|
||||
|
||||
switch(p) {
|
||||
case Beginning:
|
||||
fseek(d->file, offset, SEEK_SET);
|
||||
break;
|
||||
case Current:
|
||||
fseek(d->file, offset, SEEK_CUR);
|
||||
break;
|
||||
case End:
|
||||
fseek(d->file, offset, SEEK_END);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void File::clear()
|
||||
{
|
||||
clearerr(d->file);
|
||||
}
|
||||
|
||||
long File::tell() const
|
||||
{
|
||||
return ftell(d->file);
|
||||
}
|
||||
|
||||
long File::length()
|
||||
{
|
||||
if(!d->file)
|
||||
return 0;
|
||||
|
||||
long curpos = tell();
|
||||
|
||||
seek(0, End);
|
||||
long endpos = tell();
|
||||
|
||||
seek(curpos, Beginning);
|
||||
|
||||
return endpos;
|
||||
}
|
||||
|
||||
bool File::isWritable(const char *file)
|
||||
{
|
||||
return access(file, W_OK) == 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void File::setValid(bool valid)
|
||||
{
|
||||
d->valid = valid;
|
||||
}
|
||||
|
||||
void File::truncate(long length)
|
||||
{
|
||||
ftruncate(fileno(d->file), length);
|
||||
}
|
||||
|
||||
TagLib::uint File::bufferSize()
|
||||
{
|
||||
return FilePrivate::bufferSize;
|
||||
}
|
240
toolkit/tfile.h
Normal file
240
toolkit/tfile.h
Normal file
@ -0,0 +1,240 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002, 2003 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
* USA *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_FILE_H
|
||||
#define TAGLIB_FILE_H
|
||||
|
||||
#include "taglib.h"
|
||||
#include "tbytevector.h"
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
class String;
|
||||
class Tag;
|
||||
class AudioProperties;
|
||||
|
||||
//! A file class with some useful methods for tag manipulation
|
||||
|
||||
/*!
|
||||
* This class is a basic file class with some methods that are particularly
|
||||
* useful for tag editors. It has methods to take advantage of
|
||||
* ByteVector and a binary search method for finding patterns in a file.
|
||||
*/
|
||||
|
||||
class File
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* Position in the file used for seeking.
|
||||
*/
|
||||
enum Position {
|
||||
//! Seek from the beginning of the file.
|
||||
Beginning,
|
||||
//! Seek from the current position in the file.
|
||||
Current,
|
||||
//! Seek from the end of the file.
|
||||
End
|
||||
};
|
||||
|
||||
/*!
|
||||
* Destroys this File instance.
|
||||
*/
|
||||
virtual ~File();
|
||||
|
||||
/*!
|
||||
* Returns the file name in the local file system encoding.
|
||||
*/
|
||||
const char *name() const;
|
||||
|
||||
/*!
|
||||
* Returns a pointer to this file's tag. This should be reimplemented in
|
||||
* the concrete subclasses.
|
||||
*/
|
||||
virtual Tag *tag() const = 0;
|
||||
|
||||
/*!
|
||||
* Returns a pointer to this file's audio properties. This should be
|
||||
* reimplemented in the concrete subclasses. If no audio properties were
|
||||
* read then this will return a null pointer.
|
||||
*/
|
||||
virtual AudioProperties *audioProperties() const = 0;
|
||||
|
||||
/*!
|
||||
* Save the file and its associated tags. This should be reimplemented in
|
||||
* the concrete subclasses.
|
||||
*/
|
||||
virtual void save() = 0;
|
||||
|
||||
/*!
|
||||
* Reads a block of size \a length at the current get pointer.
|
||||
*/
|
||||
ByteVector readBlock(ulong length);
|
||||
|
||||
/*!
|
||||
* Attempts to write the block \a data at the current get pointer. If the
|
||||
* file is currently only opened read only -- i.e. readOnly() returns true --
|
||||
* this attempts to reopen the file in read/write mode.
|
||||
*
|
||||
* \note This should be used instead of using the streaming output operator
|
||||
* for a ByteVector. And even this function is significantly slower than
|
||||
* doing output with a char[].
|
||||
*/
|
||||
void writeBlock(const ByteVector &data);
|
||||
|
||||
/*!
|
||||
* Returns the offset in the file that \a pattern occurs at or -1 if it can
|
||||
* not be found. If \a before is set, the search will only continue until the
|
||||
* pattern \a before is found. This is useful for tagging purposes to search
|
||||
* for a tag before the synch frame.
|
||||
*
|
||||
* Searching starts at \a fromOffset, which defaults to the beginning of the
|
||||
* file.
|
||||
*
|
||||
* \note This has the practial limitation that \a pattern can not be longer
|
||||
* than the buffer size used by readBlock(). Currently this is 1024 bytes.
|
||||
*/
|
||||
long find(const ByteVector &pattern,
|
||||
long fromOffset = 0,
|
||||
const ByteVector &before = ByteVector::null);
|
||||
|
||||
/*!
|
||||
* Returns the offset in the file that \a pattern occurs at or -1 if it can
|
||||
* not be found. If \a before is set, the search will only continue until the
|
||||
* pattern \a before is found. This is useful for tagging purposes to search
|
||||
* for a tag before the synch frame.
|
||||
*
|
||||
* Searching starts at \a fromOffset and proceeds from the that point to the
|
||||
* beginning of the file and defaults to the end of the file.
|
||||
*
|
||||
* \note This has the practial limitation that \a pattern can not be longer
|
||||
* than the buffer size used by readBlock(). Currently this is 1024 bytes.
|
||||
*/
|
||||
long rfind(const ByteVector &pattern,
|
||||
long fromOffset = 0,
|
||||
const ByteVector &before = ByteVector::null);
|
||||
|
||||
/*!
|
||||
* Insert \a data at position \a start in the file overwriting \a replace
|
||||
* bytes of the original content.
|
||||
*
|
||||
* \note This method is slow since it requires rewriting all of the file
|
||||
* after the insertion point.
|
||||
*/
|
||||
void insert(const ByteVector &data, ulong start = 0, ulong replace = 0);
|
||||
|
||||
/*!
|
||||
* Removes a block of the file starting a \a start and continuing for
|
||||
* \a length bytes.
|
||||
*
|
||||
* \note This method is slow since it involves rewriting all of the file
|
||||
* after the removed portion.
|
||||
*/
|
||||
void removeBlock(ulong start = 0, ulong length = 0);
|
||||
|
||||
/*!
|
||||
* Returns true if the file is read only (or if the file can not be opened).
|
||||
*/
|
||||
bool readOnly() const;
|
||||
|
||||
/*!
|
||||
* Since the file can currently only be opened as an argument to the
|
||||
* constructor (sort-of by design), this returns if that open succeeded.
|
||||
*/
|
||||
bool isOpen() const;
|
||||
|
||||
/*!
|
||||
* Returns true if the file is open and readble and valid information for
|
||||
* the Tag and / or AudioProperties was found.
|
||||
*/
|
||||
bool isValid() const;
|
||||
|
||||
/*!
|
||||
* Move the I/O pointer to \a offset in the file from position \a p. This
|
||||
* defaults to seeking from the beginning of the file.
|
||||
*
|
||||
* \see Position
|
||||
*/
|
||||
void seek(long offset, Position p = Beginning);
|
||||
|
||||
/*!
|
||||
* Reset the end-of-file and error flags on the file.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/*!
|
||||
* Returns the current offset withing the file.
|
||||
*/
|
||||
long tell() const;
|
||||
|
||||
/*!
|
||||
* Returns the length of the file.
|
||||
*/
|
||||
long length();
|
||||
|
||||
/*!
|
||||
* Returns true if \a file can be opened for reading. If the file does not
|
||||
* exist, this will return false.
|
||||
*/
|
||||
static bool isReadable(const char *file);
|
||||
|
||||
/*!
|
||||
* Returns true if \a file can be opened for writing.
|
||||
*/
|
||||
static bool isWritable(const char *name);
|
||||
|
||||
protected:
|
||||
/*!
|
||||
* Construct a File object and opens the \a file. \a file should be a
|
||||
* be a C-string in the local file system encoding.
|
||||
*
|
||||
* \note Constructor is protected since this class should only be
|
||||
* instantiated through subclasses.
|
||||
*/
|
||||
File(const char *file);
|
||||
|
||||
/*!
|
||||
* Marks the file as valid or invalid.
|
||||
*
|
||||
* \see isValid()
|
||||
*/
|
||||
void setValid(bool valid);
|
||||
|
||||
/*!
|
||||
* Truncates the file to a \a length.
|
||||
*/
|
||||
void truncate(long length);
|
||||
|
||||
/*!
|
||||
* Returns the buffer size that is used for internal buffering.
|
||||
*/
|
||||
static uint bufferSize();
|
||||
|
||||
private:
|
||||
File(const File &);
|
||||
File &operator=(const File &);
|
||||
|
||||
class FilePrivate;
|
||||
FilePrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
234
toolkit/tlist.h
Normal file
234
toolkit/tlist.h
Normal file
@ -0,0 +1,234 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
* USA *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_LIST_H
|
||||
#define TAGLIB_LIST_H
|
||||
|
||||
#include "taglib.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
//! A generic, implicitly shared list.
|
||||
|
||||
/*!
|
||||
* This is basic generic list that's somewhere between a std::list and a
|
||||
* QValueList. This class is implicitly shared. For example:
|
||||
*
|
||||
* \code
|
||||
*
|
||||
* TagLib::List<int> l = someOtherIntList;
|
||||
*
|
||||
* \endcode
|
||||
*
|
||||
* The above example is very cheap. This also makes lists suitable for the
|
||||
* return types of functions. The above example will just copy a pointer rather
|
||||
* than copying the data in the list. When your \e shared list's data changes,
|
||||
* only \e then will the data be copied.
|
||||
*/
|
||||
|
||||
template <class T> class List
|
||||
{
|
||||
public:
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
typedef typename std::list<T>::iterator Iterator;
|
||||
typedef typename std::list<T>::const_iterator ConstIterator;
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* Constructs an empty list.
|
||||
*/
|
||||
List();
|
||||
|
||||
/*!
|
||||
* Make a shallow, implicitly shared, copy of \a l. Because this is
|
||||
* implicitly shared, this method is lightweight and suitable for
|
||||
* pass-by-value usage.
|
||||
*/
|
||||
List(const List<T> &l);
|
||||
|
||||
/*!
|
||||
* Destroys this List instance. If auto deletion is enabled and this list
|
||||
* contains a pointer type all of the memebers are also deleted.
|
||||
*/
|
||||
virtual ~List();
|
||||
|
||||
/*!
|
||||
* Returns an STL style iterator to the beginning of the list. See
|
||||
* std::list::const_iterator for the semantics.
|
||||
*/
|
||||
Iterator begin();
|
||||
|
||||
/*!
|
||||
* Returns an STL style constant iterator to the beginning of the list. See
|
||||
* std::list::iterator for the semantics.
|
||||
*/
|
||||
ConstIterator begin() const;
|
||||
|
||||
/*!
|
||||
* Returns an STL style iterator to the end of the list. See
|
||||
* std::list::iterator for the semantics.
|
||||
*/
|
||||
Iterator end();
|
||||
|
||||
/*!
|
||||
* Returns an STL style constant iterator to the end of the list. See
|
||||
* std::list::const_iterator for the semantics.
|
||||
*/
|
||||
ConstIterator end() const;
|
||||
|
||||
/*!
|
||||
* Inserts a copy of \a value before \a it.
|
||||
*/
|
||||
void insert(Iterator it, const T &value);
|
||||
|
||||
/*!
|
||||
* Inserts the \a value into the list. This assumes that the list is
|
||||
* currently sorted. If \a unique is true then the value will not
|
||||
* be inserted if it is already in the list.
|
||||
*/
|
||||
void sortedInsert(const T &value, bool unique = false);
|
||||
|
||||
/*!
|
||||
* Appends \a item to the end of the list.
|
||||
*/
|
||||
void append(const T &item);
|
||||
|
||||
/*!
|
||||
* Appends all of the values in \a l to the end of the list.
|
||||
*/
|
||||
void append(const List<T> &l);
|
||||
|
||||
/*!
|
||||
* Clears the list. If auto deletion is enabled and this list contains a
|
||||
* pointer type the members are also deleted.
|
||||
*
|
||||
* \see setAutoDelete()
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/*!
|
||||
* Returns the number of elements in the list.
|
||||
*/
|
||||
uint size() const;
|
||||
bool isEmpty() const;
|
||||
|
||||
/*!
|
||||
* Find the first occurance of \a value.
|
||||
*/
|
||||
Iterator find(const T &value);
|
||||
|
||||
/*!
|
||||
* Find the first occurance of \a value.
|
||||
*/
|
||||
ConstIterator find(const T &value) const;
|
||||
|
||||
/*!
|
||||
* Returns true if the list contains \a value.
|
||||
*/
|
||||
bool contains(const T &value) const;
|
||||
|
||||
/*!
|
||||
* Erase the item at \a it from the list.
|
||||
*/
|
||||
void erase(Iterator it);
|
||||
|
||||
/*!
|
||||
* Returns a reference to the first item in the list.
|
||||
*/
|
||||
const T &front() const;
|
||||
|
||||
/*!
|
||||
* Returns a reference to the first item in the list.
|
||||
*/
|
||||
T &front();
|
||||
|
||||
/*!
|
||||
* Returns a reference to the last item in the list.
|
||||
*/
|
||||
const T &back() const;
|
||||
|
||||
/*!
|
||||
* Returns a reference to the last item in the list.
|
||||
*/
|
||||
T &back();
|
||||
|
||||
/*!
|
||||
* Auto delete the members of the list when the last reference to the list
|
||||
* passes out of scope. This will have no effect on lists which do not
|
||||
* contain a pointer type.
|
||||
*
|
||||
* \note This relies on partial template instantiation -- most modern C++
|
||||
* compilers should now support this.
|
||||
*/
|
||||
void setAutoDelete(bool autoDelete);
|
||||
|
||||
/*!
|
||||
* Returns a reference to item \a i in the list.
|
||||
*
|
||||
* \warning This method is slow. Use iterators to loop through the list.
|
||||
*/
|
||||
T &operator[](uint i);
|
||||
|
||||
/*!
|
||||
* Returns a const reference to item \a i in the list.
|
||||
*
|
||||
* \warning This method is slow. Use iterators to loop through the list.
|
||||
*/
|
||||
const T &operator[](uint i) const;
|
||||
|
||||
/*!
|
||||
* Make a shallow, implicitly shared, copy of \a l. Because this is
|
||||
* implicitly shared, this method is lightweight and suitable for
|
||||
* pass-by-value usage.
|
||||
*/
|
||||
List<T> &operator=(const List<T> &l);
|
||||
|
||||
/*!
|
||||
* Compares this list with \a l and returns true if all of the elements are
|
||||
* the same.
|
||||
*/
|
||||
bool operator==(const List<T> &l) const;
|
||||
|
||||
protected:
|
||||
/*
|
||||
* If this List is being shared via implicit sharing, do a deep copy of the
|
||||
* data and separate from the shared members. This should be called by all
|
||||
* non-const subclass members.
|
||||
*/
|
||||
void detach();
|
||||
|
||||
private:
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
template <class TP> class ListPrivate;
|
||||
ListPrivate<T> *d;
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// Since GCC doesn't support the "export" keyword, we have to include the
|
||||
// implementation.
|
||||
|
||||
#include "tlist.tcc"
|
||||
|
||||
#endif
|
294
toolkit/tlist.tcc
Normal file
294
toolkit/tlist.tcc
Normal file
@ -0,0 +1,294 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
* USA *
|
||||
***************************************************************************/
|
||||
|
||||
#include <tdebug.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// The functionality of List<T>::setAutoDelete() is implemented here partial
|
||||
// template specialization. This is implemented in such a way that calling
|
||||
// setAutoDelete() on non-pointer types will simply have no effect.
|
||||
|
||||
// A base for the generic and specialized private class types. New
|
||||
// non-templatized members should be added here.
|
||||
|
||||
class ListPrivateBase : public RefCounter
|
||||
{
|
||||
public:
|
||||
ListPrivateBase() : autoDelete(false) {}
|
||||
bool autoDelete;
|
||||
};
|
||||
|
||||
// A generic implementation
|
||||
|
||||
template <class T>
|
||||
template <class TP> class List<T>::ListPrivate : public ListPrivateBase
|
||||
{
|
||||
public:
|
||||
ListPrivate() : ListPrivateBase() {}
|
||||
ListPrivate(const std::list<TP> &l) : ListPrivateBase(), list(l) {}
|
||||
void clear() {
|
||||
list.clear();
|
||||
}
|
||||
std::list<TP> list;
|
||||
};
|
||||
|
||||
// A partial specialization for all pointer types that implements the
|
||||
// setAutoDelete() functionality.
|
||||
|
||||
template <class T>
|
||||
template <class TP> class List<T>::ListPrivate<TP *> : public ListPrivateBase
|
||||
{
|
||||
public:
|
||||
ListPrivate() : ListPrivateBase() {}
|
||||
ListPrivate(const std::list<TP *> &l) : ListPrivateBase(), list(l) {}
|
||||
~ListPrivate() {
|
||||
clear();
|
||||
}
|
||||
void clear() {
|
||||
if(autoDelete) {
|
||||
typename std::list<TP *>::const_iterator it = list.begin();
|
||||
for(; it != list.end(); ++it)
|
||||
delete *it;
|
||||
}
|
||||
list.clear();
|
||||
}
|
||||
std::list<TP *> list;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <class T>
|
||||
List<T>::List()
|
||||
{
|
||||
d = new ListPrivate<T>;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
List<T>::List(const List<T> &l) : d(l.d)
|
||||
{
|
||||
d->ref();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
List<T>::~List()
|
||||
{
|
||||
if(d->deref())
|
||||
delete d;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename List<T>::Iterator List<T>::begin()
|
||||
{
|
||||
detach();
|
||||
return d->list.begin();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename List<T>::ConstIterator List<T>::begin() const
|
||||
{
|
||||
return d->list.begin();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename List<T>::Iterator List<T>::end()
|
||||
{
|
||||
detach();
|
||||
return d->list.end();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename List<T>::ConstIterator List<T>::end() const
|
||||
{
|
||||
return d->list.end();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void List<T>::insert(Iterator it, const T &item)
|
||||
{
|
||||
detach();
|
||||
d->list.insert(it, item);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void List<T>::sortedInsert(const T &value, bool unique)
|
||||
{
|
||||
detach();
|
||||
Iterator it = begin();
|
||||
while(*it < value && it != end())
|
||||
++it;
|
||||
if(unique && it != end() && *it == value)
|
||||
return;
|
||||
insert(it, value);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void List<T>::append(const T &item)
|
||||
{
|
||||
detach();
|
||||
d->list.push_back(item);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void List<T>::append(const List<T> &l)
|
||||
{
|
||||
detach();
|
||||
d->list.insert(d->list.end(), l.begin(), l.end());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void List<T>::clear()
|
||||
{
|
||||
detach();
|
||||
d->clear();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
TagLib::uint List<T>::size() const
|
||||
{
|
||||
return d->list.size();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool List<T>::isEmpty() const
|
||||
{
|
||||
return d->list.empty();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename List<T>::Iterator List<T>::find(const T &value)
|
||||
{
|
||||
return std::find(d->list.begin(), d->list.end(), value);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename List<T>::ConstIterator List<T>::find(const T &value) const
|
||||
{
|
||||
return std::find(d->list.begin(), d->list.end(), value);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool List<T>::contains(const T &value) const
|
||||
{
|
||||
return std::find(d->list.begin(), d->list.end(), value) != d->list.end();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void List<T>::erase(Iterator it)
|
||||
{
|
||||
d->list.erase(it);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
const T &List<T>::front() const
|
||||
{
|
||||
return d->list.front();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T &List<T>::front()
|
||||
{
|
||||
detach();
|
||||
return d->list.front();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
const T &List<T>::back() const
|
||||
{
|
||||
return d->list.back();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void List<T>::setAutoDelete(bool autoDelete)
|
||||
{
|
||||
d->autoDelete = autoDelete;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T &List<T>::back()
|
||||
{
|
||||
detach();
|
||||
return d->list.back();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T &List<T>::operator[](uint i)
|
||||
{
|
||||
Iterator it = d->list.begin();
|
||||
|
||||
for(uint j = 0; j < i; j++)
|
||||
++it;
|
||||
|
||||
return *it;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
const T &List<T>::operator[](uint i) const
|
||||
{
|
||||
ConstIterator it = d->list.begin();
|
||||
|
||||
for(uint j = 0; j < i; j++)
|
||||
++it;
|
||||
|
||||
return *it;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
List<T> &List<T>::operator=(const List<T> &l)
|
||||
{
|
||||
if(&l == this)
|
||||
return *this;
|
||||
|
||||
if(d->deref())
|
||||
delete d;
|
||||
d = l.d;
|
||||
d->ref();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool List<T>::operator==(const List<T> &l) const
|
||||
{
|
||||
return d->list == l.d->list;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <class T>
|
||||
void List<T>::detach()
|
||||
{
|
||||
if(d->count() > 1) {
|
||||
d->deref();
|
||||
d = new ListPrivate<T>(d->list);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace TagLib
|
162
toolkit/tmap.h
Normal file
162
toolkit/tmap.h
Normal file
@ -0,0 +1,162 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2003 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
* USA *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_MAP_H
|
||||
#define TAGLIB_MAP_H
|
||||
|
||||
#include "taglib.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
//! A generic, implicitly shared map.
|
||||
|
||||
/*!
|
||||
* This implements a standard map container that associates a key with a value
|
||||
* and has fast key-based lookups. This map is also implicitly shared making
|
||||
* it suitable for pass-by-value usage.
|
||||
*/
|
||||
|
||||
template <class Key, class T> class Map
|
||||
{
|
||||
public:
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
typedef typename std::map<Key, T>::iterator Iterator;
|
||||
typedef typename std::map<Key, T>::const_iterator ConstIterator;
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* Constructs an empty Map.
|
||||
*/
|
||||
Map();
|
||||
|
||||
/*!
|
||||
* Make a shallow, implicitly shared, copy of \a m. Because this is
|
||||
* implicitly shared, this method is lightweight and suitable for
|
||||
* pass-by-value usage.
|
||||
*/
|
||||
Map(const Map<Key, T> &m);
|
||||
|
||||
/*!
|
||||
* Destroys this instance of the Map.
|
||||
*/
|
||||
virtual ~Map();
|
||||
|
||||
/*!
|
||||
* Returns an STL style iterator to the beginning of the map. See
|
||||
* std::map::iterator for the semantics.
|
||||
*/
|
||||
Iterator begin();
|
||||
|
||||
/*!
|
||||
* Returns an STL style iterator to the beginning of the map. See
|
||||
* std::map::const_iterator for the semantics.
|
||||
*/
|
||||
ConstIterator begin() const;
|
||||
|
||||
/*!
|
||||
* Returns an STL style iterator to the end of the map. See
|
||||
* std::map::iterator for the semantics.
|
||||
*/
|
||||
Iterator end();
|
||||
|
||||
/*!
|
||||
* Returns an STL style iterator to the end of the map. See
|
||||
* std::map::const_iterator for the semantics.
|
||||
*/
|
||||
ConstIterator end() const;
|
||||
|
||||
/*!
|
||||
* Inserts \a value under \a key in the map. If a value for \a key already
|
||||
* exists it will be overwritten.
|
||||
*/
|
||||
void insert(const Key &key, const T &value);
|
||||
|
||||
/*!
|
||||
* Removes all of the elements from elements from the map. This however
|
||||
* will not delete pointers if the mapped type is a pointer type.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/*!
|
||||
* The number of elements in the map.
|
||||
*
|
||||
* \see isEmpty()
|
||||
*/
|
||||
uint size() const;
|
||||
|
||||
/*!
|
||||
* Returns true if the map is empty.
|
||||
*
|
||||
* \see size()
|
||||
*/
|
||||
bool isEmpty() const;
|
||||
|
||||
/*!
|
||||
* Returns true if the map contains an instance of \a key.
|
||||
*/
|
||||
bool contains(const Key &key) const;
|
||||
|
||||
/*!
|
||||
* Returns a reference to the value associated with \a key.
|
||||
*
|
||||
* \note This has undefined behavior if the key is not present in the map.
|
||||
*/
|
||||
const T &operator[](const Key &key) const;
|
||||
|
||||
/*!
|
||||
* Returns a reference to the value associated with \a key.
|
||||
*
|
||||
* \note This has undefined behavior if the key is not present in the map.
|
||||
*/
|
||||
T &operator[](const Key &key);
|
||||
|
||||
/*!
|
||||
* Make a shallow, implicitly shared, copy of \a m. Because this is
|
||||
* implicitly shared, this method is lightweight and suitable for
|
||||
* pass-by-value usage.
|
||||
*/
|
||||
Map<Key, T> &operator=(const Map<Key, T> &m);
|
||||
|
||||
protected:
|
||||
/*
|
||||
* If this List is being shared via implicit sharing, do a deep copy of the
|
||||
* data and separate from the shared members. This should be called by all
|
||||
* non-const subclass members.
|
||||
*/
|
||||
void detach();
|
||||
|
||||
private:
|
||||
#ifndef DO_NOT_DOCUMENT
|
||||
template <class KeyP, class TP> class MapPrivate;
|
||||
MapPrivate<Key, T> *d;
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// Since GCC doesn't support the "export" keyword, we have to include the
|
||||
// implementation.
|
||||
|
||||
#include "tmap.tcc"
|
||||
|
||||
#endif
|
154
toolkit/tmap.tcc
Normal file
154
toolkit/tmap.tcc
Normal file
@ -0,0 +1,154 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
* USA *
|
||||
***************************************************************************/
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <class Key, class T>
|
||||
template <class KeyP, class TP> class Map<Key, T>::MapPrivate : public RefCounter
|
||||
{
|
||||
public:
|
||||
MapPrivate() : RefCounter() {}
|
||||
MapPrivate(const std::map<KeyP, TP> &m) : RefCounter(), map(m) {}
|
||||
|
||||
std::map<KeyP, TP> map;
|
||||
};
|
||||
|
||||
template <class Key, class T>
|
||||
Map<Key, T>::Map()
|
||||
{
|
||||
d = new MapPrivate<Key, T>;
|
||||
}
|
||||
|
||||
template <class Key, class T>
|
||||
Map<Key, T>::Map(const Map<Key, T> &m) : d(m.d)
|
||||
{
|
||||
d->ref();
|
||||
}
|
||||
|
||||
template <class Key, class T>
|
||||
Map<Key, T>::~Map()
|
||||
{
|
||||
if(d->deref())
|
||||
delete(d);
|
||||
}
|
||||
|
||||
template <class Key, class T>
|
||||
typename Map<Key, T>::Iterator Map<Key, T>::begin()
|
||||
{
|
||||
detach();
|
||||
return d->map.begin();
|
||||
}
|
||||
|
||||
template <class Key, class T>
|
||||
typename Map<Key, T>::ConstIterator Map<Key, T>::begin() const
|
||||
{
|
||||
return d->map.begin();
|
||||
}
|
||||
|
||||
template <class Key, class T>
|
||||
typename Map<Key, T>::Iterator Map<Key, T>::end()
|
||||
{
|
||||
detach();
|
||||
return d->map.end();
|
||||
}
|
||||
|
||||
template <class Key, class T>
|
||||
typename Map<Key, T>::ConstIterator Map<Key, T>::end() const
|
||||
{
|
||||
return d->map.end();
|
||||
}
|
||||
|
||||
template <class Key, class T>
|
||||
void Map<Key, T>::insert(const Key &key, const T &value)
|
||||
{
|
||||
detach();
|
||||
std::pair<Key, T> item(key, value);
|
||||
d->map.insert(item);
|
||||
}
|
||||
|
||||
template <class Key, class T>
|
||||
void Map<Key, T>::clear()
|
||||
{
|
||||
detach();
|
||||
d->map.clear();
|
||||
}
|
||||
|
||||
template <class Key, class T>
|
||||
bool Map<Key, T>::isEmpty() const
|
||||
{
|
||||
return d->map.empty();
|
||||
}
|
||||
|
||||
template <class Key, class T>
|
||||
bool Map<Key, T>::contains(const Key &key) const
|
||||
{
|
||||
return d->map.find(key) != d->map.end();
|
||||
}
|
||||
|
||||
template <class Key, class T>
|
||||
TagLib::uint Map<Key, T>::size() const
|
||||
{
|
||||
return d->map.size();
|
||||
}
|
||||
|
||||
template <class Key, class T>
|
||||
const T &Map<Key, T>::operator[](const Key &key) const
|
||||
{
|
||||
return d->map[key];
|
||||
}
|
||||
|
||||
template <class Key, class T>
|
||||
T &Map<Key, T>::operator[](const Key &key)
|
||||
{
|
||||
return d->map[key];
|
||||
}
|
||||
|
||||
template <class Key, class T>
|
||||
Map<Key, T> &Map<Key, T>::operator=(const Map<Key, T> &m)
|
||||
{
|
||||
if(&m == this)
|
||||
return *this;
|
||||
|
||||
if(d->deref())
|
||||
delete(d);
|
||||
d = m.d;
|
||||
d->ref();
|
||||
return *this;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <class Key, class T>
|
||||
void Map<Key, T>::detach()
|
||||
{
|
||||
if(d->count() > 1) {
|
||||
d->deref();
|
||||
d = new MapPrivate<Key, T>(d->map);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace TagLib
|
652
toolkit/tstring.cpp
Normal file
652
toolkit/tstring.cpp
Normal file
@ -0,0 +1,652 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002, 2003 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
* USA *
|
||||
***************************************************************************/
|
||||
|
||||
#include "tstring.h"
|
||||
#include "unicode.h"
|
||||
#include "tdebug.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
inline unsigned short byteSwap(unsigned short x)
|
||||
{
|
||||
return ((x) >> 8) & 0xff | ((x) & 0xff) << 8;
|
||||
}
|
||||
|
||||
inline unsigned short combine(unsigned char c1, unsigned char c2)
|
||||
{
|
||||
return (c1 << 8) | c2;
|
||||
}
|
||||
}
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class String::StringPrivate : public RefCounter
|
||||
{
|
||||
public:
|
||||
StringPrivate(const wstring &s) :
|
||||
RefCounter(),
|
||||
data(s),
|
||||
CString(0) {}
|
||||
|
||||
StringPrivate() :
|
||||
RefCounter(),
|
||||
CString(0) {}
|
||||
|
||||
~StringPrivate() {
|
||||
delete [] CString;
|
||||
}
|
||||
|
||||
wstring data;
|
||||
|
||||
/*!
|
||||
* This is only used to hold the a pointer to the most recent value of
|
||||
* toCString.
|
||||
*/
|
||||
char *CString;
|
||||
};
|
||||
|
||||
String String::null;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
String::String()
|
||||
{
|
||||
d = new StringPrivate;
|
||||
}
|
||||
|
||||
String::String(const String &s) : d(s.d)
|
||||
{
|
||||
d->ref();
|
||||
}
|
||||
|
||||
String::String(const std::string &s, Type t)
|
||||
{
|
||||
d = new StringPrivate;
|
||||
|
||||
if(t == UTF16 || t == UTF16BE) {
|
||||
debug("String::String() -- A std::string should not contain UTF16.");
|
||||
return;
|
||||
}
|
||||
|
||||
for(std::string::const_iterator it = s.begin(); it != s.end(); it++)
|
||||
d->data += uchar(*it);
|
||||
|
||||
prepare(t);
|
||||
}
|
||||
|
||||
String::String(const wstring &s, Type t)
|
||||
{
|
||||
d = new StringPrivate(s);
|
||||
prepare(t);
|
||||
}
|
||||
|
||||
String::String(const wchar_t *s, Type t)
|
||||
{
|
||||
d = new StringPrivate(s);
|
||||
prepare(t);
|
||||
}
|
||||
|
||||
String::String(const char *s, Type t)
|
||||
{
|
||||
d = new StringPrivate;
|
||||
|
||||
if(t == UTF16 || t == UTF16BE) {
|
||||
debug("String::String() -- A const char * should not contain UTF16.");
|
||||
return;
|
||||
}
|
||||
|
||||
for(int i = 0; s[i] != 0; i++)
|
||||
d->data += uchar(s[i]);
|
||||
|
||||
prepare(t);
|
||||
}
|
||||
|
||||
String::String(wchar_t c, Type t)
|
||||
{
|
||||
d = new StringPrivate;
|
||||
d->data += c;
|
||||
prepare(t);
|
||||
}
|
||||
|
||||
String::String(char c, Type t)
|
||||
{
|
||||
d = new StringPrivate;
|
||||
|
||||
if(t == UTF16 || t == UTF16BE) {
|
||||
debug("String::String() -- A std::string should not contain UTF16.");
|
||||
return;
|
||||
}
|
||||
|
||||
d->data += uchar(c);
|
||||
prepare(t);
|
||||
}
|
||||
|
||||
String::String(const ByteVector &v, Type t)
|
||||
{
|
||||
d = new StringPrivate;
|
||||
|
||||
if(t == Latin1 || t == UTF8) {
|
||||
for(uint i = 0; i < v.size() && v[i]; i++)
|
||||
d->data += uchar(v[i]);
|
||||
}
|
||||
else {
|
||||
for(uint i = 0; i + 1 < v.size() && combine(v[i], v[i + 1]); i += 2)
|
||||
d->data += combine(v[i], v[i + 1]);
|
||||
}
|
||||
prepare(t);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
String::~String()
|
||||
{
|
||||
if(d->deref())
|
||||
delete d;
|
||||
}
|
||||
|
||||
std::string String::to8Bit(bool unicode) const
|
||||
{
|
||||
std::string s;
|
||||
s.resize(d->data.size());
|
||||
|
||||
if(!unicode) {
|
||||
std::string::iterator targetIt = s.begin();
|
||||
for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) {
|
||||
*targetIt = char(*it);
|
||||
++targetIt;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
const int outputBufferSize = d->data.size() * 3 + 1;
|
||||
|
||||
Unicode::UTF16 *sourceBuffer = new Unicode::UTF16[d->data.size() + 1];
|
||||
Unicode::UTF8 *targetBuffer = new Unicode::UTF8[outputBufferSize];
|
||||
|
||||
for(unsigned int i = 0; i < d->data.size(); i++)
|
||||
sourceBuffer[i] = Unicode::UTF16(d->data[i]);
|
||||
|
||||
const Unicode::UTF16 *source = sourceBuffer;
|
||||
Unicode::UTF8 *target = targetBuffer;
|
||||
|
||||
Unicode::ConversionResult result =
|
||||
Unicode::ConvertUTF16toUTF8(&source, sourceBuffer + d->data.size(),
|
||||
&target, targetBuffer + outputBufferSize,
|
||||
Unicode::lenientConversion);
|
||||
|
||||
if(result != Unicode::conversionOK)
|
||||
debug("String::to8Bit() - Unicode conversion error.");
|
||||
|
||||
int newSize = target - targetBuffer;
|
||||
s.resize(newSize);
|
||||
targetBuffer[newSize] = 0;
|
||||
|
||||
s = (char *) targetBuffer;
|
||||
|
||||
delete [] sourceBuffer;
|
||||
delete [] targetBuffer;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
const char *String::toCString(bool unicode) const
|
||||
{
|
||||
delete [] d->CString;
|
||||
|
||||
std::string buffer = to8Bit(unicode);
|
||||
d->CString = new char[buffer.size() + 1];
|
||||
strcpy(d->CString, buffer.c_str());
|
||||
|
||||
return d->CString;
|
||||
}
|
||||
|
||||
int String::find(const String &s, int offset) const
|
||||
{
|
||||
wstring::size_type position = d->data.find(s.d->data, offset);
|
||||
|
||||
if(position != wstring::npos)
|
||||
return position;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
String String::substr(uint position, uint n) const
|
||||
{
|
||||
if(n > position + d->data.size())
|
||||
n = d->data.size() - position;
|
||||
|
||||
String s;
|
||||
s.d->data = d->data.substr(position, n);
|
||||
return s;
|
||||
}
|
||||
|
||||
String &String::append(const String &s)
|
||||
{
|
||||
detach();
|
||||
d->data += s.d->data;
|
||||
return *this;
|
||||
}
|
||||
|
||||
String String::upper() const
|
||||
{
|
||||
String s;
|
||||
|
||||
static int shift = 'A' - 'a';
|
||||
|
||||
for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); ++it) {
|
||||
if(*it >= 'a' && *it <= 'z')
|
||||
s.d->data.push_back(*it + shift);
|
||||
else
|
||||
s.d->data.push_back(*it);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
TagLib::uint String::size() const
|
||||
{
|
||||
return d->data.size();
|
||||
}
|
||||
|
||||
bool String::isEmpty() const
|
||||
{
|
||||
return d->data.size() == 0;
|
||||
}
|
||||
|
||||
bool String::isNull() const
|
||||
{
|
||||
return d == null.d;
|
||||
}
|
||||
|
||||
ByteVector String::data(Type t) const
|
||||
{
|
||||
ByteVector v;
|
||||
|
||||
switch(t) {
|
||||
|
||||
case Latin1:
|
||||
{
|
||||
for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++)
|
||||
v.append(char(*it));
|
||||
break;
|
||||
}
|
||||
case UTF8:
|
||||
{
|
||||
std::string s = to8Bit(true);
|
||||
v.setData(s.c_str(), s.length());
|
||||
break;
|
||||
}
|
||||
case UTF16:
|
||||
{
|
||||
// Assume that if we're doing UTF16 and not UTF16BE that we want little
|
||||
// endian encoding. (Byte Order Mark)
|
||||
|
||||
v.append(char(0xff));
|
||||
v.append(char(0xfe));
|
||||
|
||||
for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) {
|
||||
|
||||
char c1 = *it & 0xff;
|
||||
char c2 = *it >> 8;
|
||||
|
||||
v.append(c1);
|
||||
v.append(c2);
|
||||
}
|
||||
}
|
||||
case UTF16BE:
|
||||
{
|
||||
for(wstring::const_iterator it = d->data.begin(); it != d->data.end(); it++) {
|
||||
|
||||
char c1 = *it >> 8;
|
||||
char c2 = *it & 0xff;
|
||||
|
||||
v.append(c2);
|
||||
v.append(c1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
int String::toInt() const
|
||||
{
|
||||
int value = 0;
|
||||
|
||||
bool negative = d->data[0] == '-';
|
||||
uint i = negative ? 1 : 0;
|
||||
|
||||
for(; i < d->data.size() && d->data[i] >= '0' && d->data[i] <= '9'; i++)
|
||||
value = value * 10 + (d->data[i] - '0');
|
||||
|
||||
if(negative)
|
||||
value = value * -1;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
String String::stripWhiteSpace() const
|
||||
{
|
||||
wstring::const_iterator begin = d->data.begin();
|
||||
wstring::const_iterator end = d->data.end();
|
||||
|
||||
while(*begin == '\t' || *begin == '\n' || *begin == '\f' ||
|
||||
*begin == '\r' || *begin == ' ' && begin != end)
|
||||
{
|
||||
++begin;
|
||||
}
|
||||
|
||||
if(begin == end)
|
||||
return null;
|
||||
|
||||
// There must be at least one non-whitespace charater here for us to have
|
||||
// gotten this far, so we should be safe not doing bounds checking.
|
||||
|
||||
do {
|
||||
--end;
|
||||
} while(*end == '\t' || *end == '\n' ||
|
||||
*end == '\f' || *end == '\r' || *end == ' ');
|
||||
|
||||
return String(wstring(begin, end + 1));
|
||||
}
|
||||
|
||||
String String::number(int n) // static
|
||||
{
|
||||
if(n == 0)
|
||||
return String("0");
|
||||
|
||||
String charStack;
|
||||
|
||||
bool negative = n < 0;
|
||||
|
||||
if(negative)
|
||||
n = n * -1;
|
||||
|
||||
while(n > 0) {
|
||||
int remainder = n % 10;
|
||||
charStack += char(remainder + '0');
|
||||
n = (n - remainder) / 10;
|
||||
}
|
||||
|
||||
String s;
|
||||
|
||||
if(negative)
|
||||
s += '-';
|
||||
|
||||
for(int i = charStack.d->data.size() - 1; i >= 0; i--)
|
||||
s += charStack.d->data[i];
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
bool String::operator==(const String &s) const
|
||||
{
|
||||
return d == s.d || d->data == s.d->data;
|
||||
}
|
||||
|
||||
String &String::operator+=(const String &s)
|
||||
{
|
||||
detach();
|
||||
|
||||
d->data += s.d->data;
|
||||
return *this;
|
||||
}
|
||||
|
||||
String &String::operator+=(const wchar_t *s)
|
||||
{
|
||||
detach();
|
||||
|
||||
d->data += s;
|
||||
return *this;
|
||||
}
|
||||
|
||||
String &String::operator+=(const char *s)
|
||||
{
|
||||
detach();
|
||||
|
||||
for(int i = 0; s[i] != 0; i++)
|
||||
d->data += uchar(s[i]);
|
||||
return *this;
|
||||
}
|
||||
|
||||
String &String::operator+=(wchar_t c)
|
||||
{
|
||||
detach();
|
||||
|
||||
d->data += c;
|
||||
return *this;
|
||||
}
|
||||
|
||||
String &String::operator+=(char c)
|
||||
{
|
||||
d->data += uchar(c);
|
||||
return *this;
|
||||
}
|
||||
|
||||
String &String::operator=(const String &s)
|
||||
{
|
||||
if(&s == this)
|
||||
return *this;
|
||||
|
||||
if(d->deref())
|
||||
delete d;
|
||||
d = s.d;
|
||||
d->ref();
|
||||
return *this;
|
||||
}
|
||||
|
||||
String &String::operator=(const std::string &s)
|
||||
{
|
||||
if(d->deref())
|
||||
delete d;
|
||||
|
||||
d = new StringPrivate;
|
||||
|
||||
d->data.resize(s.size());
|
||||
|
||||
wstring::iterator targetIt = d->data.begin();
|
||||
for(std::string::const_iterator it = s.begin(); it != s.end(); it++) {
|
||||
*targetIt = uchar(*it);
|
||||
++targetIt;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
String &String::operator=(const wstring &s)
|
||||
{
|
||||
if(d->deref())
|
||||
delete d;
|
||||
d = new StringPrivate(s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
String &String::operator=(const wchar_t *s)
|
||||
{
|
||||
if(d->deref())
|
||||
delete d;
|
||||
d = new StringPrivate(s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
String &String::operator=(char c)
|
||||
{
|
||||
if(d->deref())
|
||||
delete d;
|
||||
d = new StringPrivate;
|
||||
d->data += uchar(c);
|
||||
return *this;
|
||||
}
|
||||
|
||||
String &String::operator=(wchar_t c)
|
||||
{
|
||||
if(d->deref())
|
||||
delete d;
|
||||
d = new StringPrivate;
|
||||
d->data += c;
|
||||
return *this;
|
||||
}
|
||||
|
||||
String &String::operator=(const char *s)
|
||||
{
|
||||
if(d->deref())
|
||||
delete d;
|
||||
|
||||
d = new StringPrivate;
|
||||
|
||||
for(int i = 0; s[i] != 0; i++)
|
||||
d->data += uchar(s[i]);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
String &String::operator=(const ByteVector &v)
|
||||
{
|
||||
if(d->deref())
|
||||
delete d;
|
||||
|
||||
d = new StringPrivate;
|
||||
d->data.resize(v.size());
|
||||
wstring::iterator targetIt = d->data.begin();
|
||||
|
||||
uint i = 0;
|
||||
for(; i < v.size() && v[i]; i++) {
|
||||
*targetIt = uchar(v[i]);
|
||||
++targetIt;
|
||||
}
|
||||
|
||||
// If we hit a null in the ByteVector, shrink the string again.
|
||||
|
||||
d->data.resize(i);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool String::operator<(const String &s) const
|
||||
{
|
||||
return d->data < s.d->data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// protected members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void String::detach()
|
||||
{
|
||||
if(d->count() > 1) {
|
||||
d->deref();
|
||||
d = new StringPrivate(d->data);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// private members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void String::prepare(Type t)
|
||||
{
|
||||
switch(t) {
|
||||
case UTF16:
|
||||
{
|
||||
if(d->data.size() > 1) {
|
||||
bool swap = d->data[0] != 0xfeff;
|
||||
d->data.erase(d->data.begin(), d->data.begin() + 1);
|
||||
if(swap) {
|
||||
for(uint i = 0; i < d->data.size(); i++)
|
||||
d->data[i] = byteSwap((unsigned short)d->data[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
debug("String::prepare() - Invalid UTF16 string.");
|
||||
d->data.erase(d->data.begin(), d->data.end());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case UTF8:
|
||||
{
|
||||
int bufferSize = d->data.size() + 1;
|
||||
Unicode::UTF8 *sourceBuffer = new Unicode::UTF8[bufferSize];
|
||||
Unicode::UTF16 *targetBuffer = new Unicode::UTF16[bufferSize];
|
||||
|
||||
unsigned int i = 0;
|
||||
for(; i < d->data.size(); i++)
|
||||
sourceBuffer[i] = Unicode::UTF8(d->data[i]);
|
||||
sourceBuffer[i] = 0;
|
||||
|
||||
const Unicode::UTF8 *source = sourceBuffer;
|
||||
Unicode::UTF16 *target = targetBuffer;
|
||||
|
||||
Unicode::ConversionResult result =
|
||||
Unicode::ConvertUTF8toUTF16(&source, sourceBuffer + bufferSize,
|
||||
&target, targetBuffer + bufferSize,
|
||||
Unicode::lenientConversion);
|
||||
|
||||
if(result != Unicode::conversionOK)
|
||||
debug("String::prepare() - Unicode conversion error.");
|
||||
|
||||
|
||||
int newSize = target - targetBuffer - 1;
|
||||
d->data.resize(newSize);
|
||||
|
||||
for(int i = 0; i < newSize; i++)
|
||||
d->data[i] = targetBuffer[i];
|
||||
|
||||
delete [] sourceBuffer;
|
||||
delete [] targetBuffer;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// related functions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const TagLib::String operator+(const TagLib::String &s1, const TagLib::String &s2)
|
||||
{
|
||||
String s(s1);
|
||||
s.append(s2);
|
||||
return s;
|
||||
}
|
||||
|
||||
const TagLib::String operator+(const char *s1, const TagLib::String &s2)
|
||||
{
|
||||
String s(s1);
|
||||
s.append(s2);
|
||||
return s;
|
||||
}
|
||||
|
||||
const TagLib::String operator+(const TagLib::String &s1, const char *s2)
|
||||
{
|
||||
String s(s1);
|
||||
s.append(s2);
|
||||
return s;
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &s, const String &str)
|
||||
{
|
||||
s << str.to8Bit();
|
||||
return s;
|
||||
}
|
372
toolkit/tstring.h
Normal file
372
toolkit/tstring.h
Normal file
@ -0,0 +1,372 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002, 2003 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
* USA *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_STRING_H
|
||||
#define TAGLIB_STRING_H
|
||||
|
||||
#include "taglib.h"
|
||||
#include "tbytevector.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
/*!
|
||||
* Converts a TagLib::String to a QString without a requirement to link to Qt.
|
||||
*/
|
||||
#define QStringToTString(s) TagLib::String(s.utf8().data(), TagLib::String::UTF8)
|
||||
|
||||
/*!
|
||||
* Converts a TagLib::String to a QString without a requirement to link to Qt.
|
||||
*/
|
||||
#define TStringToQString(s) QString::fromUtf8(s.toCString(true))
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
//! A \e wide string class suitable for unicode.
|
||||
|
||||
/*!
|
||||
* This is an implicitly shared \e wide string. For storage it uses
|
||||
* TagLib::wstring, but as this is an <i>implementation detail</i> this of
|
||||
* course could change. Strings are stored internally as UTF-16BE. (Without
|
||||
* the BOM (Byte Order Mark)
|
||||
*
|
||||
* The use of implicit sharing means that copying a string is cheap, the only
|
||||
* \e cost comes into play when the copy is modified. Prior to that the string
|
||||
* just has a pointer to the data of the \e parent String. This also makes
|
||||
* this class suitable as a function return type.
|
||||
*
|
||||
* In addition to adding implicit sharing, this class keeps track of four
|
||||
* possible encodings, which are the four supported by the ID3v2 standard.
|
||||
*/
|
||||
|
||||
class String
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* The four types of string encodings supported by the ID3v2 specification.
|
||||
* ID3v1 is assumed to be Latin1 and Ogg Vorbis comments use UTF8.
|
||||
*/
|
||||
enum Type {
|
||||
/*!
|
||||
* IS08859-1, or <i>Latin1</i> encoding. 8 bit characters.
|
||||
*/
|
||||
Latin1 = 0,
|
||||
/*!
|
||||
* UTF16 with a <i>byte order mark</i>. 16 bit characters.
|
||||
*/
|
||||
UTF16 = 1,
|
||||
/*!
|
||||
* UTF16 <i>big endian</i>. 16 bit characters. This is the encoding used
|
||||
* internally by TagLib.
|
||||
*/
|
||||
UTF16BE = 2,
|
||||
/*!
|
||||
* UTF8 encoding. Characters are usually 8 bits but can be up to 32.
|
||||
*/
|
||||
UTF8 = 3
|
||||
};
|
||||
|
||||
/*!
|
||||
* Constructs an empty String.
|
||||
*/
|
||||
String();
|
||||
|
||||
/*!
|
||||
* Make a shallow, implicitly shared, copy of \a s. Because this is
|
||||
* implicitly shared, this method is lightweight and suitable for
|
||||
* pass-by-value usage.
|
||||
*/
|
||||
String(const String &s);
|
||||
|
||||
/*!
|
||||
* Makes a deep copy of the data in \a s.
|
||||
*
|
||||
* \note This should only be used with the 8-bit codecs Latin1 and UTF8, when
|
||||
* used with other codecs it will simply print a warning and exit.
|
||||
*/
|
||||
String(const std::string &s, Type t = Latin1);
|
||||
|
||||
/*!
|
||||
* Makes a deep copy of the data in \a s.
|
||||
*/
|
||||
String(const wstring &s, Type t = UTF16BE);
|
||||
|
||||
/*!
|
||||
* Makes a deep copy of the data in \a s.
|
||||
*/
|
||||
String(const wchar_t *s, Type t = UTF16BE);
|
||||
|
||||
/*!
|
||||
* Makes a deep copy of the data in \a c.
|
||||
*
|
||||
* \note This should only be used with the 8-bit codecs Latin1 and UTF8, when
|
||||
* used with other codecs it will simply print a warning and exit.
|
||||
*/
|
||||
String(char c, Type t = Latin1);
|
||||
|
||||
/*!
|
||||
* Makes a deep copy of the data in \a c.
|
||||
*/
|
||||
String(wchar_t c, Type t = Latin1);
|
||||
|
||||
|
||||
/*!
|
||||
* Makes a deep copy of the data in \a s.
|
||||
*
|
||||
* \note This should only be used with the 8-bit codecs Latin1 and UTF8, when
|
||||
* used with other codecs it will simply print a warning and exit.
|
||||
*/
|
||||
String(const char *s, Type t = Latin1);
|
||||
|
||||
/*!
|
||||
* Makes a deep copy of the data in \a s.
|
||||
*
|
||||
* \note This should only be used with the 8-bit codecs Latin1 and UTF8, when
|
||||
* used with other codecs it will simply print a warning and exit.
|
||||
*/
|
||||
String(const ByteVector &v, Type t = Latin1);
|
||||
|
||||
/*!
|
||||
* Destroys this String instance.
|
||||
*/
|
||||
virtual ~String();
|
||||
|
||||
/*!
|
||||
* If \a unicode if false (the default) this will return a \e Latin1 encoded
|
||||
* std::string. If it is true the returned std::wstring will be UTF-8
|
||||
* encoded.
|
||||
*/
|
||||
std::string to8Bit(bool unicode = false) const;
|
||||
|
||||
/*!
|
||||
* Creates and returns a C-String based on the data. This string is still
|
||||
* owned by the String (class) and as such should not be deleted by the user.
|
||||
*
|
||||
* If \a unicode if false (the default) this string will be encoded in
|
||||
* \e Latin1. If it is true the returned C-String will be UTF-8 encoded.
|
||||
*
|
||||
* This string remains valid until the String instance is destroyed or
|
||||
* another export method is called.
|
||||
*
|
||||
* \warning This however has the side effect that this C-String will remain
|
||||
* in memory <b>in addition to</b> other memory that is consumed by the
|
||||
* String instance. So, this method should not be used on large strings or
|
||||
* where memory is critical.
|
||||
*/
|
||||
const char *toCString(bool unicode = false) const;
|
||||
|
||||
/*!
|
||||
* Finds the first occurance of pattern \a s in this string starting from
|
||||
* \a offset. If the pattern is not found, -1 is returned.
|
||||
*/
|
||||
int find(const String &s, int offset = 0) const;
|
||||
|
||||
/*!
|
||||
* Extract a substring from this string starting at \a position and
|
||||
* continuing for \a n characters.
|
||||
*/
|
||||
String substr(uint position, uint n = 0xffffffff) const;
|
||||
|
||||
/*!
|
||||
* Append \a s to the current string and return a reference to the current
|
||||
* string.
|
||||
*/
|
||||
String &append(const String &s);
|
||||
|
||||
/*!
|
||||
* Returns an upper case version of the string.
|
||||
*
|
||||
* \warning This only works for the characters in US-ASCII, i.e. A-Z.
|
||||
*/
|
||||
String upper() const;
|
||||
|
||||
/*!
|
||||
* Returns the size of the string.
|
||||
*/
|
||||
uint size() const;
|
||||
|
||||
/*!
|
||||
* Returns true if the string is empty.
|
||||
*
|
||||
* \see isNull()
|
||||
*/
|
||||
bool isEmpty() const;
|
||||
|
||||
/*!
|
||||
* Returns true if this string is null -- i.e. it is a copy of the
|
||||
* String::null string.
|
||||
*
|
||||
* \note A string can be empty and not null.
|
||||
* \see isEmpty()
|
||||
*/
|
||||
bool isNull() const;
|
||||
|
||||
/*!
|
||||
* Returns a ByteVector containing the string's data. If \a t is Latin1 or
|
||||
* UTF8, this will return a vector of 8 bit characters, otherwise it will use
|
||||
* 16 bit characters.
|
||||
*/
|
||||
ByteVector data(Type t) const;
|
||||
|
||||
/*!
|
||||
* Convert the string to an integer.
|
||||
*/
|
||||
int toInt() const;
|
||||
|
||||
/*!
|
||||
* Returns a string with the leading and trailing whitespace stripped.
|
||||
*/
|
||||
String stripWhiteSpace() const;
|
||||
|
||||
/*!
|
||||
* Converts the base-10 integer \a n to a string.
|
||||
*/
|
||||
static String number(int n);
|
||||
|
||||
/*!
|
||||
* Compares each character of the String with each character of \a s and
|
||||
* returns true if the strings match.
|
||||
*/
|
||||
bool operator==(const String &s) const;
|
||||
|
||||
/*!
|
||||
* Appends \a s to the end of the String.
|
||||
*/
|
||||
String &operator+=(const String &s);
|
||||
|
||||
/*!
|
||||
* Appends \a s to the end of the String.
|
||||
*/
|
||||
String &operator+=(const wchar_t* s);
|
||||
|
||||
/*!
|
||||
* Appends \a s to the end of the String.
|
||||
*/
|
||||
String &operator+=(const char* s);
|
||||
|
||||
/*!
|
||||
* Appends \a s to the end of the String.
|
||||
*/
|
||||
String &operator+=(wchar_t c);
|
||||
|
||||
/*!
|
||||
* Appends \a c to the end of the String.
|
||||
*/
|
||||
String &operator+=(char c);
|
||||
|
||||
/*!
|
||||
* Performs a shallow, implicitly shared, copy of \a s, overwriting the
|
||||
* String's current data.
|
||||
*/
|
||||
String &operator=(const String &s);
|
||||
|
||||
/*!
|
||||
* Performs a deep copy of the data in \a s.
|
||||
*/
|
||||
String &operator=(const std::string &s);
|
||||
|
||||
/*!
|
||||
* Performs a deep copy of the data in \a s.
|
||||
*/
|
||||
String &operator=(const wstring &s);
|
||||
|
||||
/*!
|
||||
* Performs a deep copy of the data in \a s.
|
||||
*/
|
||||
String &operator=(const wchar_t *s);
|
||||
|
||||
/*!
|
||||
* Performs a deep copy of the data in \a s.
|
||||
*/
|
||||
String &operator=(char c);
|
||||
|
||||
/*!
|
||||
* Performs a deep copy of the data in \a s.
|
||||
*/
|
||||
String &operator=(wchar_t c);
|
||||
|
||||
/*!
|
||||
* Performs a deep copy of the data in \a s.
|
||||
*/
|
||||
String &operator=(const char *s);
|
||||
|
||||
/*!
|
||||
* Performs a deep copy of the data in \a v.
|
||||
*/
|
||||
String &operator=(const ByteVector &v);
|
||||
|
||||
/*!
|
||||
* To be able to use this class in a Map, this operator needed to be
|
||||
* implemented. Returns true if \a s is less than this string in a bytewise
|
||||
* comparison.
|
||||
*/
|
||||
bool operator<(const String &s) const;
|
||||
|
||||
/*!
|
||||
* A null string provided for convenience.
|
||||
*/
|
||||
static String null;
|
||||
|
||||
protected:
|
||||
/*
|
||||
* If this String is being shared via implicit sharing, do a deep copy of the
|
||||
* data and separate from the shared members. This should be called by all
|
||||
* non-const subclass members.
|
||||
*/
|
||||
void detach();
|
||||
|
||||
private:
|
||||
/*!
|
||||
* This checks to see if the string is in \e UTF-16 (with BOM) or \e UTF-8
|
||||
* format and if so converts it to \e UTF-16BE for internal use. \e Latin1
|
||||
* does not require conversion since it is a subset of \e UTF-16BE and
|
||||
* \e UTF16-BE requires no conversion since it is used internally.
|
||||
*/
|
||||
void prepare(Type t);
|
||||
|
||||
class StringPrivate;
|
||||
StringPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
* \relates TagLib::String
|
||||
*/
|
||||
const TagLib::String operator+(const TagLib::String &s1, const TagLib::String &s2);
|
||||
|
||||
/*!
|
||||
* \relates TagLib::String
|
||||
*/
|
||||
const TagLib::String operator+(const char *s1, const TagLib::String &s2);
|
||||
|
||||
/*!
|
||||
* \relates TagLib::String
|
||||
*/
|
||||
const TagLib::String operator+(const TagLib::String &s1, const char *s2);
|
||||
|
||||
|
||||
/*!
|
||||
* \relates TagLib::String
|
||||
* Send the string to an output stream.
|
||||
*/
|
||||
std::ostream &operator<<(std::ostream &s, const TagLib::String &str);
|
||||
|
||||
#endif
|
98
toolkit/tstringlist.cpp
Normal file
98
toolkit/tstringlist.cpp
Normal file
@ -0,0 +1,98 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002, 2003 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
* USA *
|
||||
***************************************************************************/
|
||||
|
||||
#include "tstringlist.h"
|
||||
|
||||
using namespace TagLib;
|
||||
|
||||
class StringListPrivate
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// static members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
StringList StringList::split(const String &s, const String &pattern)
|
||||
{
|
||||
StringList l;
|
||||
|
||||
int previousOffset = 0;
|
||||
for(int offset = s.find(pattern); offset != -1; offset = s.find(pattern, offset + 1)) {
|
||||
l.append(s.substr(previousOffset, offset - previousOffset));
|
||||
previousOffset = offset + 1;
|
||||
}
|
||||
|
||||
l.append(s.substr(previousOffset, s.size() - previousOffset));
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// public members
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
StringList::StringList() : List<String>()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
StringList::StringList(const StringList &l) : List<String>(l)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
StringList::StringList(const String &s) : List<String>()
|
||||
{
|
||||
append(s);
|
||||
}
|
||||
|
||||
StringList::~StringList()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
String StringList::toString(const String &separator) const
|
||||
{
|
||||
String s;
|
||||
|
||||
ConstIterator it = begin();
|
||||
|
||||
while(it != end()) {
|
||||
s += *it;
|
||||
it++;
|
||||
if(it != end())
|
||||
s += separator;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// related functions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::ostream &operator<<(std::ostream &s, const StringList &l)
|
||||
{
|
||||
s << l.toString();
|
||||
return s;
|
||||
}
|
89
toolkit/tstringlist.h
Normal file
89
toolkit/tstringlist.h
Normal file
@ -0,0 +1,89 @@
|
||||
/***************************************************************************
|
||||
copyright : (C) 2002, 2003 by Scott Wheeler
|
||||
email : wheeler@kde.org
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* This library is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License version *
|
||||
* 2.1 as published by the Free Software Foundation. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, but *
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
* Lesser General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Lesser General Public *
|
||||
* License along with this library; if not, write to the Free Software *
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
* USA *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef TAGLIB_STRINGLIST_H
|
||||
#define TAGLIB_STRINGLIST_H
|
||||
|
||||
#include "tstring.h"
|
||||
#include "tlist.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace TagLib {
|
||||
|
||||
//! A list of strings
|
||||
|
||||
/*!
|
||||
* This is a spcialization of the List class with some members convention for
|
||||
* string operations.
|
||||
*/
|
||||
|
||||
class StringList : public List<String>
|
||||
{
|
||||
public:
|
||||
|
||||
/*!
|
||||
* Constructs an empty StringList.
|
||||
*/
|
||||
StringList();
|
||||
|
||||
/*!
|
||||
* Make a shallow, implicitly shared, copy of \a l. Because this is
|
||||
* implicitly shared, this method is lightweight and suitable for
|
||||
* pass-by-value usage.
|
||||
*/
|
||||
StringList(const StringList &l);
|
||||
|
||||
/*!
|
||||
* Constructs a StringList with \a s as a member.
|
||||
*/
|
||||
StringList(const String &s);
|
||||
|
||||
/*!
|
||||
* Destroys this StringList instance.
|
||||
*/
|
||||
virtual ~StringList();
|
||||
|
||||
/*!
|
||||
* Concatenate the list of strings into one string separated by \a separator.
|
||||
*/
|
||||
String toString(const String &separator = " ") const;
|
||||
|
||||
/*!
|
||||
* Splits the String \a s into several strings at \a pattern. This will not include
|
||||
* the pattern in the returned strings.
|
||||
*/
|
||||
static StringList split(const String &s, const String &pattern);
|
||||
|
||||
private:
|
||||
class StringListPrivate;
|
||||
StringListPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
* \related TagLib::StringList
|
||||
* Send the StringList to an output stream.
|
||||
*/
|
||||
std::ostream &operator<<(std::ostream &s, const TagLib::StringList &l);
|
||||
|
||||
#endif
|
303
toolkit/unicode.cpp
Normal file
303
toolkit/unicode.cpp
Normal file
@ -0,0 +1,303 @@
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* THIS FILE IS INCLUDED IN TAGLIB, BUT IS NOT COPYRIGHTED BY THE TAGLIB *
|
||||
* AUTHORS, NOT PART OF THE TAGLIB API AND COULD GO AWAY AT ANY POINT IN TIME. *
|
||||
* AS SUCH IT SHOULD BE CONSIERED FOR INTERNAL USE ONLY. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
/*
|
||||
* Copyright 2001 Unicode, Inc.
|
||||
*
|
||||
* Disclaimer
|
||||
*
|
||||
* This source code is provided as is by Unicode, Inc. No claims are
|
||||
* made as to fitness for any particular purpose. No warranties of any
|
||||
* kind are expressed or implied. The recipient agrees to determine
|
||||
* applicability of information provided. If this file has been
|
||||
* purchased on magnetic or optical media from Unicode, Inc., the
|
||||
* sole remedy for any claim will be exchange of defective media
|
||||
* within 90 days of receipt.
|
||||
*
|
||||
* Limitations on Rights to Redistribute This Code
|
||||
*
|
||||
* Unicode, Inc. hereby grants the right to freely use the information
|
||||
* supplied in this file in the creation of products supporting the
|
||||
* Unicode Standard, and to make copies of this file in any form
|
||||
* for internal or external distribution as long as this notice
|
||||
* remains attached.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file has been modified by Scott Wheeler <wheeler@kde.org> to remove
|
||||
* the UTF32 conversion functions and to place the appropriate functions
|
||||
* in their own C++ namespace.
|
||||
*/
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
|
||||
Conversions between UTF32, UTF-16, and UTF-8. Source code file.
|
||||
Author: Mark E. Davis, 1994.
|
||||
Rev History: Rick McGowan, fixes & updates May 2001.
|
||||
Sept 2001: fixed const & error conditions per
|
||||
mods suggested by S. Parent & A. Lillich.
|
||||
|
||||
See the header file "ConvertUTF.h" for complete documentation.
|
||||
|
||||
------------------------------------------------------------------------ */
|
||||
|
||||
|
||||
#include "unicode.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#define UNI_SUR_HIGH_START (UTF32)0xD800
|
||||
#define UNI_SUR_HIGH_END (UTF32)0xDBFF
|
||||
#define UNI_SUR_LOW_START (UTF32)0xDC00
|
||||
#define UNI_SUR_LOW_END (UTF32)0xDFFF
|
||||
#define false 0
|
||||
#define true 1
|
||||
|
||||
namespace Unicode {
|
||||
|
||||
static const int halfShift = 10; /* used for shifting by 10 bits */
|
||||
|
||||
static const UTF32 halfBase = 0x0010000UL;
|
||||
static const UTF32 halfMask = 0x3FFUL;
|
||||
|
||||
/*
|
||||
* Index into the table below with the first byte of a UTF-8 sequence to
|
||||
* get the number of trailing bytes that are supposed to follow it.
|
||||
*/
|
||||
static const char trailingBytesForUTF8[256] = {
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
|
||||
};
|
||||
|
||||
/*
|
||||
* Magic values subtracted from a buffer value during UTF8 conversion.
|
||||
* This table contains as many values as there might be trailing bytes
|
||||
* in a UTF-8 sequence.
|
||||
*/
|
||||
static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
|
||||
0x03C82080UL, 0xFA082080UL, 0x82082080UL };
|
||||
|
||||
/*
|
||||
* Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
|
||||
* into the first byte, depending on how many bytes follow. There are
|
||||
* as many entries in this table as there are UTF-8 sequence types.
|
||||
* (I.e., one byte sequence, two byte... six byte sequence.)
|
||||
*/
|
||||
static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* The interface converts a whole buffer to avoid function-call overhead.
|
||||
* Constants have been gathered. Loops & conditionals have been removed as
|
||||
* much as possible for efficiency, in favor of drop-through switches.
|
||||
* (See "Note A" at the bottom of the file for equivalent code.)
|
||||
* If your compiler supports it, the "isLegalUTF8" call can be turned
|
||||
* into an inline function.
|
||||
*/
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
ConversionResult ConvertUTF16toUTF8 (
|
||||
const UTF16** sourceStart, const UTF16* sourceEnd,
|
||||
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF16* source = *sourceStart;
|
||||
UTF8* target = *targetStart;
|
||||
while (source < sourceEnd) {
|
||||
UTF32 ch;
|
||||
unsigned short bytesToWrite = 0;
|
||||
const UTF32 byteMask = 0xBF;
|
||||
const UTF32 byteMark = 0x80;
|
||||
const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
|
||||
ch = *source++;
|
||||
/* If we have a surrogate pair, convert to UTF32 first. */
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END && source < sourceEnd) {
|
||||
UTF32 ch2 = *source;
|
||||
if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
|
||||
ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
|
||||
+ (ch2 - UNI_SUR_LOW_START) + halfBase;
|
||||
++source;
|
||||
} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
} else if ((flags == strictConversion) && (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END)) {
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
/* Figure out how many bytes the result will require */
|
||||
if (ch < (UTF32)0x80) { bytesToWrite = 1;
|
||||
} else if (ch < (UTF32)0x800) { bytesToWrite = 2;
|
||||
} else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
|
||||
} else if (ch < (UTF32)0x200000) { bytesToWrite = 4;
|
||||
} else { bytesToWrite = 2;
|
||||
ch = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
// printf("bytes to write = %i\n", bytesToWrite);
|
||||
target += bytesToWrite;
|
||||
if (target > targetEnd) {
|
||||
source = oldSource; /* Back up source pointer! */
|
||||
target -= bytesToWrite; result = targetExhausted; break;
|
||||
}
|
||||
switch (bytesToWrite) { /* note: everything falls through. */
|
||||
case 4: *--target = (ch | byteMark) & byteMask; ch >>= 6;
|
||||
case 3: *--target = (ch | byteMark) & byteMask; ch >>= 6;
|
||||
case 2: *--target = (ch | byteMark) & byteMask; ch >>= 6;
|
||||
case 1: *--target = ch | firstByteMark[bytesToWrite];
|
||||
}
|
||||
target += bytesToWrite;
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Utility routine to tell whether a sequence of bytes is legal UTF-8.
|
||||
* This must be called with the length pre-determined by the first byte.
|
||||
* If not calling this from ConvertUTF8to*, then the length can be set by:
|
||||
* length = trailingBytesForUTF8[*source]+1;
|
||||
* and the sequence is illegal right away if there aren't that many bytes
|
||||
* available.
|
||||
* If presented with a length > 4, this returns false. The Unicode
|
||||
* definition of UTF-8 goes up to 4-byte sequences.
|
||||
*/
|
||||
|
||||
static Boolean isLegalUTF8(const UTF8 *source, int length) {
|
||||
UTF8 a;
|
||||
const UTF8 *srcptr = source+length;
|
||||
switch (length) {
|
||||
default: return false;
|
||||
/* Everything else falls through when "true"... */
|
||||
case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
|
||||
case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
|
||||
case 2: if ((a = (*--srcptr)) > 0xBF) return false;
|
||||
switch (*source) {
|
||||
/* no fall-through in this inner switch */
|
||||
case 0xE0: if (a < 0xA0) return false; break;
|
||||
case 0xF0: if (a < 0x90) return false; break;
|
||||
case 0xF4: if (a > 0x8F) return false; break;
|
||||
default: if (a < 0x80) return false;
|
||||
}
|
||||
case 1: if (*source >= 0x80 && *source < 0xC2) return false;
|
||||
if (*source > 0xF4) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Exported function to return whether a UTF-8 sequence is legal or not.
|
||||
* This is not used here; it's just exported.
|
||||
*/
|
||||
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
|
||||
int length = trailingBytesForUTF8[*source]+1;
|
||||
if (source+length > sourceEnd) {
|
||||
return false;
|
||||
}
|
||||
return isLegalUTF8(source, length);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
ConversionResult ConvertUTF8toUTF16 (
|
||||
const UTF8** sourceStart, const UTF8* sourceEnd,
|
||||
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF8* source = *sourceStart;
|
||||
UTF16* target = *targetStart;
|
||||
while (source < sourceEnd) {
|
||||
UTF32 ch = 0;
|
||||
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
|
||||
if (source + extraBytesToRead >= sourceEnd) {
|
||||
result = sourceExhausted; break;
|
||||
}
|
||||
/* Do this check whether lenient or strict */
|
||||
if (! isLegalUTF8(source, extraBytesToRead+1)) {
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* The cases all fall through. See "Note A" below.
|
||||
*/
|
||||
switch (extraBytesToRead) {
|
||||
case 3: ch += *source++; ch <<= 6;
|
||||
case 2: ch += *source++; ch <<= 6;
|
||||
case 1: ch += *source++; ch <<= 6;
|
||||
case 0: ch += *source++;
|
||||
}
|
||||
ch -= offsetsFromUTF8[extraBytesToRead];
|
||||
|
||||
if (target >= targetEnd) {
|
||||
source -= (extraBytesToRead+1); /* Back up source pointer! */
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
|
||||
if ((flags == strictConversion) && (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END)) {
|
||||
source -= (extraBytesToRead+1); /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
} else {
|
||||
*target++ = ch; /* normal case */
|
||||
}
|
||||
} else if (ch > UNI_MAX_UTF16) {
|
||||
if (flags == strictConversion) {
|
||||
result = sourceIllegal;
|
||||
source -= (extraBytesToRead+1); /* return to the start */
|
||||
break; /* Bail out; shouldn't continue */
|
||||
} else {
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
} else {
|
||||
/* target is a character in range 0xFFFF - 0x10FFFF. */
|
||||
if (target + 1 >= targetEnd) {
|
||||
source -= (extraBytesToRead+1); /* Back up source pointer! */
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
ch -= halfBase;
|
||||
*target++ = (ch >> halfShift) + UNI_SUR_HIGH_START;
|
||||
*target++ = (ch & halfMask) + UNI_SUR_LOW_START;
|
||||
}
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
|
||||
Note A.
|
||||
The fall-through switches in UTF-8 reading code save a
|
||||
temp variable, some decrements & conditionals. The switches
|
||||
are equivalent to the following loop:
|
||||
{
|
||||
int tmpBytesToRead = extraBytesToRead+1;
|
||||
do {
|
||||
ch += *source++;
|
||||
--tmpBytesToRead;
|
||||
if (tmpBytesToRead) ch <<= 6;
|
||||
} while (tmpBytesToRead > 0);
|
||||
}
|
||||
In UTF-8 writing code, the switches on "bytesToWrite" are
|
||||
similarly unrolled loops.
|
||||
|
||||
--------------------------------------------------------------------- */
|
||||
|
||||
|
149
toolkit/unicode.h
Normal file
149
toolkit/unicode.h
Normal file
@ -0,0 +1,149 @@
|
||||
#ifndef TAGLIB_UNICODE_H
|
||||
#define TAGLIB_UNICODE_H
|
||||
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* THIS FILE IS INCLUDED IN TAGLIB, BUT IS NOT COPYRIGHTED BY THE TAGLIB *
|
||||
* AUTHORS, NOT PART OF THE TAGLIB API AND COULD GO AWAY AT ANY POINT IN TIME. *
|
||||
* AS SUCH IT SHOULD BE CONSIERED FOR INTERNAL USE ONLY. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef DO_NOT_DOCUMENT // tell Doxygen not to document this header
|
||||
|
||||
/*
|
||||
* Copyright 2001 Unicode, Inc.
|
||||
*
|
||||
* Disclaimer
|
||||
*
|
||||
* This source code is provided as is by Unicode, Inc. No claims are
|
||||
* made as to fitness for any particular purpose. No warranties of any
|
||||
* kind are expressed or implied. The recipient agrees to determine
|
||||
* applicability of information provided. If this file has been
|
||||
* purchased on magnetic or optical media from Unicode, Inc., the
|
||||
* sole remedy for any claim will be exchange of defective media
|
||||
* within 90 days of receipt.
|
||||
*
|
||||
* Limitations on Rights to Redistribute This Code
|
||||
*
|
||||
* Unicode, Inc. hereby grants the right to freely use the information
|
||||
* supplied in this file in the creation of products supporting the
|
||||
* Unicode Standard, and to make copies of this file in any form
|
||||
* for internal or external distribution as long as this notice
|
||||
* remains attached.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file has been modified by Scott Wheeler <wheeler@kde.org> to remove
|
||||
* the UTF32 conversion functions and to place the appropriate functions
|
||||
* in their own C++ namespace.
|
||||
*/
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
|
||||
Conversions between UTF32, UTF-16, and UTF-8. Header file.
|
||||
|
||||
Several funtions are included here, forming a complete set of
|
||||
conversions between the three formats. UTF-7 is not included
|
||||
here, but is handled in a separate source file.
|
||||
|
||||
Each of these routines takes pointers to input buffers and output
|
||||
buffers. The input buffers are const.
|
||||
|
||||
Each routine converts the text between *sourceStart and sourceEnd,
|
||||
putting the result into the buffer between *targetStart and
|
||||
targetEnd. Note: the end pointers are *after* the last item: e.g.
|
||||
*(sourceEnd - 1) is the last item.
|
||||
|
||||
The return result indicates whether the conversion was successful,
|
||||
and if not, whether the problem was in the source or target buffers.
|
||||
(Only the first encountered problem is indicated.)
|
||||
|
||||
After the conversion, *sourceStart and *targetStart are both
|
||||
updated to point to the end of last text successfully converted in
|
||||
the respective buffers.
|
||||
|
||||
Input parameters:
|
||||
sourceStart - pointer to a pointer to the source buffer.
|
||||
The contents of this are modified on return so that
|
||||
it points at the next thing to be converted.
|
||||
targetStart - similarly, pointer to pointer to the target buffer.
|
||||
sourceEnd, targetEnd - respectively pointers to the ends of the
|
||||
two buffers, for overflow checking only.
|
||||
|
||||
These conversion functions take a ConversionFlags argument. When this
|
||||
flag is set to strict, both irregular sequences and isolated surrogates
|
||||
will cause an error. When the flag is set to lenient, both irregular
|
||||
sequences and isolated surrogates are converted.
|
||||
|
||||
Whether the flag is strict or lenient, all illegal sequences will cause
|
||||
an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>,
|
||||
or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code
|
||||
must check for illegal sequences.
|
||||
|
||||
When the flag is set to lenient, characters over 0x10FFFF are converted
|
||||
to the replacement character; otherwise (when the flag is set to strict)
|
||||
they constitute an error.
|
||||
|
||||
Output parameters:
|
||||
The value "sourceIllegal" is returned from some routines if the input
|
||||
sequence is malformed. When "sourceIllegal" is returned, the source
|
||||
value will point to the illegal value that caused the problem. E.g.,
|
||||
in UTF-8 when a sequence is malformed, it points to the start of the
|
||||
malformed sequence.
|
||||
|
||||
Author: Mark E. Davis, 1994.
|
||||
Rev History: Rick McGowan, fixes & updates May 2001.
|
||||
Fixes & updates, Sept 2001.
|
||||
|
||||
------------------------------------------------------------------------ */
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
The following 4 definitions are compiler-specific.
|
||||
The C standard does not guarantee that wchar_t has at least
|
||||
16 bits, so wchar_t is no less portable than unsigned short!
|
||||
All should be unsigned values to avoid sign extension during
|
||||
bit mask & shift operations.
|
||||
------------------------------------------------------------------------ */
|
||||
|
||||
/* Some fundamental constants */
|
||||
#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
|
||||
#define UNI_MAX_BMP (UTF32)0x0000FFFF
|
||||
#define UNI_MAX_UTF16 (UTF32)0x0010FFFF
|
||||
#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF
|
||||
|
||||
namespace Unicode {
|
||||
|
||||
typedef unsigned long UTF32; /* at least 32 bits */
|
||||
typedef unsigned short UTF16; /* at least 16 bits */
|
||||
typedef unsigned char UTF8; /* typically 8 bits */
|
||||
typedef unsigned char Boolean; /* 0 or 1 */
|
||||
|
||||
typedef enum {
|
||||
conversionOK = 0, /* conversion successful */
|
||||
sourceExhausted = 1, /* partial character in source, but hit end */
|
||||
targetExhausted = 2, /* insuff. room in target for conversion */
|
||||
sourceIllegal = 3 /* source sequence is illegal/malformed */
|
||||
} ConversionResult;
|
||||
|
||||
typedef enum {
|
||||
strictConversion = 0,
|
||||
lenientConversion
|
||||
} ConversionFlags;
|
||||
|
||||
ConversionResult ConvertUTF8toUTF16 (
|
||||
const UTF8** sourceStart, const UTF8* sourceEnd,
|
||||
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
|
||||
|
||||
ConversionResult ConvertUTF16toUTF8 (
|
||||
const UTF16** sourceStart, const UTF16* sourceEnd,
|
||||
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
|
||||
|
||||
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
|
||||
|
||||
} // namespace Unicode
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
#endif
|
||||
#endif
|
Reference in New Issue
Block a user