aboutsummaryrefslogtreecommitdiff
path: root/Src/id3v2/id3_field_string_unicode.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/id3v2/id3_field_string_unicode.cpp')
-rw-r--r--Src/id3v2/id3_field_string_unicode.cpp338
1 files changed, 338 insertions, 0 deletions
diff --git a/Src/id3v2/id3_field_string_unicode.cpp b/Src/id3v2/id3_field_string_unicode.cpp
new file mode 100644
index 00000000..4e84943d
--- /dev/null
+++ b/Src/id3v2/id3_field_string_unicode.cpp
@@ -0,0 +1,338 @@
+// The authors have released ID3Lib as Public Domain (PD) and claim no copyright,
+// patent or other intellectual property protection in this work. This means that
+// it may be modified, redistributed and used in commercial and non-commercial
+// software and hardware without restrictions. ID3Lib is distributed on an "AS IS"
+// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+//
+// The ID3Lib authors encourage improvements and optimisations to be sent to the
+// ID3Lib coordinator, currently Dirk Mahoney (dirk@id3.org). Approved
+// submissions may be altered, and will be included and released under these terms.
+//
+// Mon Nov 23 18:34:01 1998
+
+// improved/optimized/whatever 10/30/00 JF
+// improved/optimized/whatEVER jan-08-2006 benski
+
+#include <wchar.h>
+#include <string.h>
+#include <stdlib.h>
+#include "id3_field.h"
+#include <windows.h>
+#include "../Plugins/Input/in_mp3/config.h" // TODO: cut
+#include "id3_misc_support.h"
+
+// this function is another way of using Set()
+#if 0
+ID3_Field &ID3_Field::operator=(wchar_t *string)
+{
+ Set(string);
+
+ return *this;
+}
+#endif
+
+
+// this is Set()
+
+void ID3_Field::SetUnicode(const wchar_t *string)
+{
+ luint bytesUsed = lstrlenW(string);
+
+ // we can simply increment the
+ // bytesUsed count here because
+ // we just pilfer the NULL which is
+ // present in the string which was
+ // passed to us
+ if (flags & ID3FF_NULL)
+ bytesUsed++;
+
+ // doubling the bytesUsed because
+ // Unicode is twice the size of ASCII
+ bytesUsed *= sizeof (wchar_t);
+
+ Set ((uchar *) string, bytesUsed);
+
+ type = ID3FTY_UNICODESTRING;
+ hasChanged = true;
+}
+
+
+void ID3_Field::AddUnicode(const wchar_t *string)
+{
+ if (!data)
+ SetUnicode(string);
+ else
+ {
+ wchar_t *temp;
+ luint newLen;
+ lsint nullOffset = 0;
+
+ // if there is a NULL in this string, set this offset
+ // so that we ignore it in string size calculations
+ if (flags & ID3FF_NULL)
+ nullOffset = -1;
+
+ // +1 is for the NULL at the end and the
+ // other +1 is for the list divider
+ newLen = 1 + (size / sizeof (wchar_t)) + lstrlenW(string) + 1 + nullOffset;
+
+ // I use the value 1 as a divider because then I
+ // can change it to either a '/' or a NULL at render
+ // time. This allows easy use of these functions
+ // for text lists or in the IPLS frame
+
+ if (temp = (wchar_t*)calloc(newLen, sizeof(wchar_t)))
+ {
+ lstrcpyW(temp, (wchar_t *) data);
+ temp[(size / sizeof (wchar_t)) + nullOffset] = L'\001';
+ lstrcpyW (&temp[(size / sizeof (wchar_t)) + 1 + nullOffset], string);
+
+ SetUnicode(temp);
+
+ free(temp);
+ }
+ else
+ ID3_THROW (ID3E_NoMemory);
+ }
+
+ return;
+}
+
+
+// this is Get()
+
+luint ID3_Field::GetUnicode(wchar_t *buffer, luint maxChars, luint itemNum)
+{
+ luint charsUsed = 0;
+
+ // check to see if there is a string in the frame
+ // to copy before we even try
+ if (data)
+ {
+ lsint nullOffset = 0;
+
+ if (flags & ID3FF_NULL)
+ nullOffset = -1;
+
+ // first we must find which element
+ // is being sought to make sure it
+ // exists before we try to get it
+ if (itemNum <= GetNumTextItems() && itemNum > 0)
+ {
+ wchar_t *source = (wchar_t *) data;
+ luint posn = 0;
+ luint sourceLen = 0;
+ luint curItemNum = 1;
+ luint mx= (size / sizeof (wchar_t)) + nullOffset;
+
+ // now we find that element and set the souvre pointer
+ while (posn<mx && curItemNum < itemNum)
+ {
+ while (posn<mx && *source != L'\001' && *source != L'\0')
+ {
+ source++;
+ posn++;
+ }
+
+ source++;
+ posn++;
+ curItemNum++;
+ }
+
+ if(posn>=mx) return 0;
+
+ // now that we are positioned at the first character
+ // of the string we want, find the end of it
+ while (posn<mx && source[sourceLen] != L'\001' && source[sourceLen] != L'\0')
+ {
+ sourceLen++;
+ posn++;
+ }
+
+ if (maxChars) // JF
+ {
+ // we subtract 1 here so we have
+ // room for the NULL terminator
+ //maxChars--; // CT
+
+ if (buffer)
+ {
+ luint actualChars = MIN (maxChars-1, sourceLen);
+
+ wcsncpy (buffer, source, actualChars);
+ buffer[actualChars] = L'\0';
+ charsUsed = actualChars;
+ }
+ else
+ ID3_THROW (ID3E_NoBuffer);
+ }
+ }
+ }
+
+ return charsUsed;
+}
+
+
+luint ID3_Field::GetNumTextItems (void)
+{
+ luint numItems = 0;
+
+ if (data)
+ {
+ luint posn = 0;
+
+ numItems++;
+
+ while (posn < size)
+ if (data[posn++] == L'\001')
+ numItems++;
+ }
+
+ return numItems;
+}
+
+
+luint ID3_Field::ParseUnicodeString (uchar *buffer, luint posn, luint buffSize)
+{
+ luint bytesUsed = 0;
+ wchar_t *temp = NULL;
+
+ if (fixedLength != -1)
+ bytesUsed = fixedLength;
+ else
+ {
+ if (flags & ID3FF_NULL)
+ while ((posn + bytesUsed) < buffSize &&
+ ! (buffer[posn + bytesUsed] == 0 && buffer[posn + bytesUsed + 1] == 0))
+ bytesUsed += 2;
+ else
+ bytesUsed = buffSize - posn;
+ }
+
+ if (bytesUsed > 0x8ffff)
+ {
+ hasChanged = false;
+ return 0;
+ }
+
+ if (bytesUsed)
+ {
+ if (temp = (wchar_t*)calloc(((bytesUsed / sizeof (wchar_t)) + 1), sizeof(wchar_t)))
+ {
+ luint loc = 0;
+
+ memcpy (temp, &buffer[posn], bytesUsed);
+ temp[bytesUsed / sizeof (wchar_t)] = 0;
+
+ // if there is a BOM, skip past it and check to see if we
+ // need to swap the byte order around
+ if (temp[0] == 0xFEFF || temp[0] == 0xFFFE)
+ {
+ loc++;
+
+ // if we need to swap the byte order
+ if (temp[0] != 0xFEFF)
+ {
+ int mylen=(int) lstrlenW(temp);
+ for (int i = loc; i < mylen; i++)
+ temp[i] = ((temp[i] >> 8) & 0xFF) | (((temp[i]) & 0xFF) << 8);
+ }
+ }
+
+ SetUnicode(&temp[loc]);
+
+ free(temp);
+ }
+ else
+ ID3_THROW (ID3E_NoMemory);
+ }
+
+ if (flags & ID3FF_NULL)
+ bytesUsed += 2;
+
+ hasChanged = false;
+
+ return bytesUsed;
+}
+
+
+luint ID3_Field::RenderUnicodeString(uchar *buffer)
+{
+ luint bytesUsed = 0;
+
+ bytesUsed = BinSize();
+
+ if (data && size && bytesUsed >= sizeof (wchar_t))
+ {
+ wchar_t *ourString = (wchar_t *) &buffer[sizeof(wchar_t)];
+
+ // we render at sizeof (wchar_t) bytes into the buffer
+ // because we make room for the Unicode BOM
+ memcpy (&buffer[sizeof (wchar_t)], (uchar *) data, bytesUsed - sizeof (wchar_t));
+
+ // now we convert the internal dividers to what they
+ // are supposed to be
+ size_t numChars = bytesUsed / sizeof (wchar_t);
+ for (size_t i = 0; i != numChars-1; i++)
+ if (ourString[i] == 1)
+ {
+ wchar_t sub = L'/';
+
+ if (flags & ID3FF_NULLDIVIDE)
+ sub = L'\0';
+
+ ourString[i] = sub;
+ }
+ }
+
+ if (bytesUsed)
+ {
+ // render the BOM
+ wchar_t *BOM = (wchar_t *) buffer;
+ BOM[0] = 0xFEFF;
+ }
+
+ if (bytesUsed == 2 && (flags & ID3FF_NULL))
+ buffer[0] = buffer[1] = 0;
+
+ hasChanged = false;
+
+ return bytesUsed;
+}
+
+luint ID3_Field::RenderUTF8String(uchar *buffer)
+{
+ luint bytesUsed = 0;
+
+ buffer[0] = 0;
+ bytesUsed = BinSize();
+
+ if (data && size)
+ {
+ luint i;
+
+ ID3_UnicodeToUTF8( (char*)buffer, (const wchar_t *) data, bytesUsed, bytesUsed);
+
+ for (i = 0;i < bytesUsed; i++)
+ {
+ if (buffer[i] == 1)
+ {
+ char sub = '/';
+
+ if (flags & ID3FF_NULLDIVIDE)
+ sub = '\0';
+
+ buffer[i] = sub;
+ }
+ }
+ }
+
+ if (bytesUsed == 1 && flags & ID3FF_NULL)
+ buffer[0] = 0;
+
+ hasChanged = false;
+
+ return bytesUsed;
+}
+
+