diff options
Diffstat (limited to 'src/utils.cpp')
-rw-r--r-- | src/utils.cpp | 540 |
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; +} |