aboutsummaryrefslogtreecommitdiff
path: root/src/utils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/utils.cpp')
-rw-r--r--src/utils.cpp540
1 files changed, 540 insertions, 0 deletions
diff --git a/src/utils.cpp b/src/utils.cpp
new file mode 100644
index 0000000..09f2c8d
--- /dev/null
+++ b/src/utils.cpp
@@ -0,0 +1,540 @@
+/*$off*/
+// $Id: utils.cpp,v 1.26 2002/07/02 22:04:36 t1mpy Exp $
+
+// id3lib: a C++ library for creating and manipulating id3v1/v2 tags
+// Copyright 1999, 2000 Scott Thomas Haug
+
+// This library is free software; you can redistribute it and/or modify it
+// under the terms of the GNU Library General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or (at your
+// option) any later version.
+//
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+// License for more details.
+//
+// You should have received a copy of the GNU Library 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.
+
+// The id3lib authors encourage improvements and optimisations to be sent to
+// the id3lib coordinator. Please see the README file for details on where to
+// send such submissions. See the AUTHORS file for a list of people who have
+// contributed to id3lib. See the ChangeLog file for a list of changes to
+// id3lib. These files are distributed with id3lib at
+// http://download.sourceforge.net/id3lib/
+/*$on*/
+#include <ctype.h>
+#include <errno.h>
+#include "id3/utils.h" // has <config.h> "id3/id3lib_streams.h" "id3/globals.h" "id3/id3lib_strings.h"
+
+#if (defined(__GNUC__) && __GNUC__ == 2)
+#define NOCREATE ios::nocreate
+#else
+#define NOCREATE ((std::ios_base::openmode) 0)
+#endif
+#ifdef WIN32
+#include <windows.h>
+#else
+#define min(a, b) (a < b ? a : b)
+#endif
+using namespace dami;
+
+// ESL: The original code is complicated, but maybe supports a wider range of platforms? The changes hereafter
+// leverage Unicode utilities and known shortcuts between encodings.
+#include "../unicode.org/ConvertUTF.c"
+
+/* =====================================================================================================================
+ ======================================================================================================================= */
+inline bool _legalTagChar(int c)
+{
+ // NULL, TAB, CR, LF and anything higher or equal to space is legal
+ return !c || (c >= 0x20) || (c == 0x09) || (c == 0x0a) || (c == 0x0d);
+}
+
+/* =====================================================================================================================
+ ======================================================================================================================= */
+String Utf8FromLatin1String(const char *input, size_t src_sz)
+{
+ String convertedString("");
+
+ // check the input
+ const unsigned char *src_buf = (const unsigned char *) input;
+ if(!src_buf || !src_sz) {
+ return convertedString;
+ }
+
+ // Allocate buffer and perform conversion. Since input is Latin1 it never expands to more than 2 octets
+ size_t dest_sz = src_sz * 2;
+ unsigned char *dest_buf = new unsigned char[dest_sz + 2];
+ unsigned char *dest_ptr = dest_buf;
+
+ int c = (int) *((const unsigned char *) src_buf);
+
+ while(c && src_sz--) {
+ if(c >= 128) {
+ *dest_ptr++ = (char) (((c & 0x7c0) >> 6) | 0xc0);
+ *dest_ptr++ = (char) ((c & 0x3f) | 0x80);
+ }
+ else if(!_legalTagChar(c)) {
+ *dest_ptr++ = '?';
+ }
+ else {
+ *dest_ptr++ = (char) c;
+ }
+
+ c = (int) *((const unsigned char *)++src_buf);
+ }
+
+ size_t length = dest_ptr - dest_buf;
+ if(length) {
+ dest_buf[length] = dest_buf[length + 1] = '\0';
+ convertedString = String((const char *) dest_buf);
+ }
+
+ delete[] dest_buf;
+ return convertedString;
+}
+
+/* =====================================================================================================================
+ ======================================================================================================================= */
+String Utf8FromUtf16String(const unicode_t *input, size_t src_sz)
+{
+ String convertedString("");
+
+ // check the input
+ const UTF16 *src_buf = (const UTF16 *) input;
+ if(!src_buf || !src_sz || ((src_sz % 2) != 0)) {
+ return convertedString;
+ }
+
+ // allocate buffer and perform conversion. At most each UCS2 expands to 3 octets in UTF8, but since this is
+ // physical length in octet alreay
+ size_t dest_sz = (size_t) (((float) src_sz) * 1.5) + 1;
+ unsigned char *dest_buf = new unsigned char[dest_sz + 2];
+ unsigned char *dest_ptr = dest_buf;
+ ConversionResult result = ConvertUTF16toUTF8((const UTF16 **) &src_buf, ((const UTF16 *) src_buf) + (src_sz / sizeof(UTF16)), (UTF8 **) &dest_ptr,
+ ((UTF8 *) dest_buf) + dest_sz, strictConversion);
+
+ // On success set the string in _data
+ if(result == conversionOK) {
+ size_t length = dest_ptr - dest_buf; // physical length
+ dest_buf[length] = dest_buf[length + 1] = '\0';
+ convertedString = String((const char *) dest_buf);
+ }
+
+ delete[] dest_buf;
+ return convertedString;
+}
+
+/* =====================================================================================================================
+ ======================================================================================================================= */
+String Latin1FromUtf8String(const char *input, size_t src_sz)
+{
+ String convertedString("");
+
+ // check the input
+ const unsigned char *src_buf = (const unsigned char *) input;
+ if(!src_buf || !src_sz) {
+ return convertedString;
+ }
+
+ // allocate buffer. The latin1 string will not be larger than the UTF-8 one
+ unsigned char *dest_buf = new unsigned char[src_sz + 2];
+ unsigned char *dest_ptr = dest_buf;
+
+ // perform conversion
+ int c = (int) *src_buf;
+ while(c && src_sz--) {
+ if(c >= 128) {
+ int c2 = (int) * ++src_buf;
+ if(!c2) {
+ break; // We reached the end of string
+ }
+
+ // conversion rule: 110yyyyy(C2-DF) 10zzzzzz(80-BF);
+ // However we really only care about 2 of the 'y'
+ *dest_ptr++ = (unsigned char) (((c & 0x3) << 6) + (c2 & 0x3F));
+
+ // Decrement counter since we consumed one more character
+ src_sz--;
+ }
+ else if(!_legalTagChar(c)) {
+ *dest_ptr++ = (unsigned char) '?';
+ }
+ else {
+ *dest_ptr++ = (unsigned char) c;
+ }
+
+ c = (int) * ++src_buf;
+ }
+
+ size_t length = dest_ptr - dest_buf;
+ dest_buf[length] = dest_buf[length + 1] = '\0';
+ convertedString = String((const char *) dest_buf);
+
+ delete[] dest_buf;
+ return convertedString;
+}
+
+/* =====================================================================================================================
+ ======================================================================================================================= */
+String Latin1FromUtf16String(const unicode_t *input, size_t src_sz)
+{
+ String convertedString("");
+
+ // check the input
+ const UTF16 *src_buf = (const UTF16 *) input;
+ if(!src_buf || !src_sz || ((src_sz % 2) != 0)) {
+ return convertedString;
+ }
+
+ // Each UCS2 character hanles one Latin1 character. But takes half the physical space
+ size_t dest_sz = src_sz / sizeof(UTF16);
+ size_t length = src_sz / sizeof(UTF16);
+ unsigned char *dest_buf = new unsigned char[dest_sz + 2];
+ unsigned char *dest_ptr = dest_buf;
+ while(dest_sz--) {
+ unsigned char c = (unsigned char) (0x00FF & (*src_buf++));
+ if(!_legalTagChar(c)) {
+ *dest_ptr++ = '?';
+ }
+ else {
+ *dest_ptr++ = c;
+ }
+ }
+
+ dest_buf[length] = dest_buf[length + 1] = '\0';
+ convertedString = String((const char *) dest_buf);
+
+ delete[] dest_buf;
+ return convertedString;
+}
+
+/* =====================================================================================================================
+ ======================================================================================================================= */
+String Utf16FromLatin1String(const char *input, size_t src_sz)
+{
+ String convertedString("");
+
+ // check the input
+ const unsigned char *src_buf = (const unsigned char *) input;
+ if(!src_buf || !src_sz) {
+ return convertedString;
+ }
+
+ // allocate the buffer
+ size_t length = src_sz * sizeof(UTF16);
+ unsigned char *dest_buf = new unsigned char[length + 2];
+ UTF16 *dest_ptr = (UTF16 *) dest_buf;
+ while(src_sz--) {
+ if(!_legalTagChar(*src_buf)) {
+ *dest_ptr++ = (UTF16) '?';
+ src_buf++;
+ }
+ else {
+ *dest_ptr++ = (UTF16) * src_buf++;
+ }
+ }
+
+ dest_buf[length] = dest_buf[length + 1] = '\0';
+ convertedString = String((const char *) dest_buf, length + 2);
+
+ delete[] dest_buf;
+ return convertedString;
+}
+
+/* =====================================================================================================================
+ ======================================================================================================================= */
+String Utf16FromUtf8String(const char *input, size_t src_sz)
+{
+ String convertedString("");
+
+ // check the input
+ const unsigned char *src_buf = (const unsigned char *) input;
+ if(!src_buf || !src_sz) {
+ return convertedString;
+ }
+
+ // allocate buffer and perform conversion
+ size_t dest_sz = src_sz;
+ unsigned char *dest_buf = new unsigned char[(dest_sz + 1) * sizeof(UTF16)];
+ unsigned char *dest_ptr = dest_buf;
+ ConversionResult result = ConvertUTF8toUTF16((const UTF8 **) &src_buf, (const UTF8 *) (src_buf + src_sz), (UTF16 **) &dest_ptr,
+ ((UTF16 *) dest_buf) + dest_sz, strictConversion);
+
+ // On success set the string in _data
+ if(result == conversionOK) {
+ size_t length = dest_ptr - dest_buf; // physical length
+ dest_buf[length] = dest_buf[length + 1] = '\0';
+ convertedString = String((const char *) dest_buf, length + 2);
+ }
+
+ delete[] dest_buf;
+ return convertedString;
+}
+
+/* =====================================================================================================================
+ ======================================================================================================================= */
+size_t dami::renderNumber(uchar *buffer, uint32 val, size_t size)
+{
+ uint32 num = val;
+ for(size_t i = 0; i < size; i++) {
+ buffer[size - i - 1] = (uchar) (num & MASK8);
+ num >>= 8;
+ }
+
+ return size;
+}
+
+/* =====================================================================================================================
+ ======================================================================================================================= */
+String dami::renderNumber(uint32 val, size_t size)
+{
+ String str(size, '\0');
+ uint32 num = val;
+ for(size_t i = 0; i < size; i++) {
+ str[size - i - 1] = (uchar) (num & MASK8);
+ num >>= 8;
+ }
+
+ return str;
+}
+
+// =====================================================================================================================
+// this should be convert( const String&, ...) to be changed soon...
+// =====================================================================================================================
+String dami::convert(String data, ID3_TextEnc sourceEnc, ID3_TextEnc targetEnc)
+{
+ if((sourceEnc == targetEnc) || (data.size() == 0)) {
+ return String(data);
+ }
+
+ switch(sourceEnc) {
+ case ID3TE_ISO8859_1:
+ {
+ size_t len = data.length();
+ if(targetEnc == ID3TE_UTF8) {
+ return Utf8FromLatin1String(data.c_str(), len);
+ }
+ else if(targetEnc == ID3TE_UTF16) {
+ return Utf16FromLatin1String(data.c_str(), len);
+ }
+ }
+
+ break;
+
+ case ID3TE_UTF8:
+ {
+ size_t len = data.length();
+ if(targetEnc == ID3TE_ISO8859_1) {
+ return Latin1FromUtf8String(data.c_str(), len);
+ }
+ else if(targetEnc == ID3TE_UTF16) {
+ return Utf16FromUtf8String(data.c_str(), len);
+ }
+ }
+
+ break;
+
+ case ID3TE_UTF16:
+ {
+ size_t len = ucslen((const unicode_t *) data.c_str()) * sizeof(unicode_t);
+ if(targetEnc == ID3TE_ISO8859_1) {
+ return Latin1FromUtf16String((unicode_t *) data.c_str(), len);
+ }
+ else if(targetEnc == ID3TE_UTF8) {
+ return Utf8FromUtf16String((unicode_t *) data.c_str(), len);
+ }
+ }
+
+ break;
+ }
+
+ return "";
+}
+
+/* =====================================================================================================================
+ ======================================================================================================================= */
+size_t dami::ucslen(const unicode_t *unicode)
+{
+ if(NULL != unicode) {
+ for(size_t size = 0; true; size++) {
+ if(NULL_UNICODE == unicode[size]) {
+ return size;
+ }
+ }
+ }
+
+ return 0;
+}
+
+namespace
+{
+
+ /* =================================================================================================================
+ =================================================================================================================== */
+ bool exists(String name)
+ {
+ ifstream file(name.c_str(), NOCREATE);
+ return file.is_open() != 0;
+ }
+};
+
+/* =====================================================================================================================
+ ======================================================================================================================= */
+ID3_Err dami::createFile(String name, fstream &file)
+{
+ if(file.is_open()) {
+ file.close();
+ }
+
+ file.open(name.c_str(), ios::in | ios::out | ios::binary | ios::trunc);
+ if(!file) {
+ return ID3E_ReadOnly;
+ }
+
+ return ID3E_NoError;
+}
+
+/* =====================================================================================================================
+ ======================================================================================================================= */
+size_t dami::getFileSize(fstream &file)
+{
+ size_t size = 0;
+ if(file.is_open()) {
+ streamoff curpos = file.tellg();
+ file.seekg(0, ios::end);
+ size = file.tellg();
+ file.seekg(curpos);
+ }
+
+ return size;
+}
+
+/* =====================================================================================================================
+ ======================================================================================================================= */
+size_t dami::getFileSize(ifstream &file)
+{
+ size_t size = 0;
+ if(file.is_open()) {
+ streamoff curpos = file.tellg();
+ file.seekg(0, ios::end);
+ size = file.tellg();
+ file.seekg(curpos);
+ }
+
+ return size;
+}
+
+/* =====================================================================================================================
+ ======================================================================================================================= */
+size_t dami::getFileSize(ofstream &file)
+{
+ size_t size = 0;
+ if(file.is_open()) {
+ streamoff curpos = file.tellp();
+ file.seekp(0, ios::end);
+ size = file.tellp();
+ file.seekp(curpos);
+ }
+
+ return size;
+}
+
+/* =====================================================================================================================
+ ======================================================================================================================= */
+ID3_Err dami::openWritableFile(String name, fstream &file)
+{
+ if(!exists(name)) {
+ return ID3E_NoFile;
+ }
+
+ if(file.is_open()) {
+ file.close();
+ }
+
+ file.open(name.c_str(), ios::in | ios::out | ios::binary | NOCREATE);
+ if(!file) {
+ return ID3E_ReadOnly;
+ }
+
+ return ID3E_NoError;
+}
+
+/* =====================================================================================================================
+ ======================================================================================================================= */
+ID3_Err dami::openWritableFile(String name, ofstream &file)
+{
+ if(!exists(name)) {
+ return ID3E_NoFile;
+ }
+
+ if(file.is_open()) {
+ file.close();
+ }
+
+ file.open(name.c_str(), ios::in | ios::out | ios::binary | NOCREATE);
+ if(!file) {
+ return ID3E_ReadOnly;
+ }
+
+ return ID3E_NoError;
+}
+
+/* =====================================================================================================================
+ ======================================================================================================================= */
+ID3_Err dami::openReadableFile(String name, fstream &file)
+{
+ if(file.is_open()) {
+ file.close();
+ }
+
+ file.open(name.c_str(), ios::in | ios::binary | NOCREATE);
+ if(!file) {
+ return ID3E_NoFile;
+ }
+
+ return ID3E_NoError;
+}
+
+#ifdef WIN32
+ID3_Err dami:: openReadableFile(std::wstring name, ifstream &file)
+#else
+ID3_Err dami::openReadableFile(String name, ifstream &file)
+#endif
+{
+ if(file.is_open()) {
+ file.close();
+ }
+
+ file.open(name.c_str(), ios::in | ios::binary | NOCREATE);
+
+ if(!file) {
+ return ID3E_NoFile;
+ }
+
+ return ID3E_NoError;
+}
+
+// =====================================================================================================================
+// wow, did we really had to implement string by ourself (ralf)
+// =====================================================================================================================
+String dami::toString(uint32 val)
+{
+ if(val == 0) {
+ return "0";
+ }
+
+ String text;
+ while(val > 0) {
+ String tmp;
+ char ch = (val % 10) + '0';
+ tmp += ch;
+ text = tmp + text;
+ val /= 10;
+ }
+
+ return text;
+}