aboutsummaryrefslogtreecommitdiff
path: root/Src/replicant/nsid3v2/frame_utils.cpp
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/replicant/nsid3v2/frame_utils.cpp
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz
Initial community commit
Diffstat (limited to 'Src/replicant/nsid3v2/frame_utils.cpp')
-rw-r--r--Src/replicant/nsid3v2/frame_utils.cpp265
1 files changed, 265 insertions, 0 deletions
diff --git a/Src/replicant/nsid3v2/frame_utils.cpp b/Src/replicant/nsid3v2/frame_utils.cpp
new file mode 100644
index 00000000..6fe88686
--- /dev/null
+++ b/Src/replicant/nsid3v2/frame_utils.cpp
@@ -0,0 +1,265 @@
+#include "frame_utils.h"
+#include "foundation/error.h"
+#include "nsid3v2/nsid3v2.h"
+#if defined(_WIN32) && !defined(strcasecmp)
+#define strcasecmp _stricmp
+#else
+#include <string.h>
+#endif
+
+int ParseDescription(const char *&str, size_t &data_len, size_t &str_cch)
+{
+ str_cch=0;
+ while (data_len && str[str_cch])
+ {
+ data_len--;
+ str_cch++;
+ }
+ if (!data_len)
+ return NErr_Error;
+
+ data_len--;
+ return NErr_Success;
+}
+
+int ParseDescription(const wchar_t *&str, size_t &data_len, size_t &str_cch, uint8_t &str_encoding)
+{
+ str_cch=0;
+ if (data_len > 2 && str[0] == 0xFFFE)
+ {
+ str_encoding=2;
+ str++;
+ str-=3;
+ }
+ else if (data_len > 2 && str[0] == 0xFEFF)
+ {
+ str_encoding=1;
+ str++;
+ data_len-=3;
+ }
+ else
+ {
+ data_len--;
+ }
+
+ while (data_len > 1 && str[str_cch])
+ {
+ data_len-=2;
+ str_cch++;
+ }
+
+ if (!data_len)
+ return NErr_Error;
+
+ data_len-=2;
+ return NErr_Success;
+}
+
+
+static void ParseBOM(bytereader_t reader, uint8_t *encoding, const uint8_t default_encoding)
+{
+ if (bytereader_size(reader) >= 2)
+ {
+ uint16_t bom = bytereader_show_u16_le(reader);
+ if (bom == 0xFFFE)
+ {
+ bytereader_advance(reader, 2);
+ *encoding=2;
+ }
+ else if (bom == 0xFEFF)
+ {
+ bytereader_advance(reader, 2);
+ *encoding=1;
+ }
+ else
+ {
+ *encoding=default_encoding;
+ }
+ }
+ else
+ {
+ *encoding=default_encoding;
+ }
+}
+
+int ParseNullTerminatedString(bytereader_t reader, uint8_t encoding, ParsedString &parsed)
+{
+ switch(encoding)
+ {
+ case 0: // ISO-8859-1
+ if (bytereader_size(reader) == 0)
+ return NErr_Insufficient;
+
+ parsed.encoding = 0;
+ parsed.data = bytereader_pointer(reader);
+ parsed.byte_length = 0;
+ while (bytereader_size(reader) && bytereader_read_u8(reader))
+ parsed.byte_length++;
+
+ return NErr_Success;
+ case 1: // UTF-16
+ if (bytereader_size(reader) < 2)
+ return NErr_Insufficient;
+
+ parsed.byte_length = 0;
+ ParseBOM(reader, &parsed.encoding, 1);
+ parsed.data = bytereader_pointer(reader);
+ while (bytereader_size(reader) && bytereader_read_u16_le(reader))
+ parsed.byte_length+=2;
+
+ return NErr_Success;
+ case 2: // UTF-16BE
+ if (bytereader_size(reader) < 2)
+ return NErr_Insufficient;
+
+ parsed.byte_length = 0;
+ ParseBOM(reader, &parsed.encoding, 2);
+ parsed.data = bytereader_pointer(reader);
+ while (bytereader_size(reader) && bytereader_read_u16_le(reader))
+ parsed.byte_length+=2;
+
+ return NErr_Success;
+ case 3: // UTF-8
+ if (bytereader_size(reader) == 0)
+ return NErr_Insufficient;
+
+ parsed.encoding = 3;
+ parsed.data = bytereader_pointer(reader);
+ parsed.byte_length = 0;
+
+ size_t start = bytereader_size(reader);
+#if 0 // TODO
+ /* check for UTF-8 BOM and skip it */
+ if (bytereader_size(reader) > 3 && bytereader_read_u8(reader) == 0xEF && bytereader_read_u8(reader) == 0xBB && bytereader_read_u8(reader) == 0xBF)
+ {
+ parsed.data = bytereader_pointer(reader);
+ parsed.byte_length = bytereader_size(reader);
+ }
+ else
+ {
+ /* no BOM but skip however far we read into the string */
+ size_t offset = start - bytereader_size(reader);
+ parsed.data = (const uint8_t *)parsed.data + offset;
+ parsed.byte_length -= offset;
+ }
+#endif
+ /* finish it up */
+ while (bytereader_size(reader) && bytereader_read_u8(reader))
+ parsed.byte_length++;
+
+ return NErr_Success;
+ }
+ return NErr_Unknown;
+}
+
+int ParseFrameTerminatedString(bytereader_t reader, uint8_t encoding, ParsedString &parsed)
+{
+ switch(encoding)
+ {
+ case 0: // ISO-8859-1
+ parsed.encoding = 0;
+ parsed.data = bytereader_pointer(reader);
+ parsed.byte_length = bytereader_size(reader);
+ return NErr_Success;
+ case 1: // UTF-16
+ if ((bytereader_size(reader) & 1) == 1)
+ return NErr_Error;
+ ParseBOM(reader, &parsed.encoding, 1);
+ parsed.data = bytereader_pointer(reader);
+ parsed.byte_length = bytereader_size(reader);
+ return NErr_Success;
+ case 2: // UTF-16BE
+ if ((bytereader_size(reader) & 1) == 1)
+ return NErr_Error;
+ ParseBOM(reader, &parsed.encoding, 2);
+ parsed.data = bytereader_pointer(reader);
+ parsed.byte_length = bytereader_size(reader);
+ return NErr_Success;
+ case 3: // UTF-8
+ parsed.encoding = 3;
+ parsed.data = bytereader_pointer(reader);
+ parsed.byte_length = bytereader_size(reader);
+ if (bytereader_size(reader) > 3 && bytereader_read_u8(reader) == 0xEF && bytereader_read_u8(reader) == 0xBB && bytereader_read_u8(reader) == 0xBF)
+ {
+ parsed.data = bytereader_pointer(reader);
+ parsed.byte_length = bytereader_size(reader);
+ }
+ return NErr_Success;
+ }
+ return NErr_Error;
+}
+
+int NXStringCreateFromParsedString(nx_string_t *value, ParsedString &parsed, int text_flags)
+{
+ switch(parsed.encoding)
+ {
+ case 0: // ISO-8859-1
+ if (parsed.byte_length == 0)
+ return NXStringCreateEmpty(value);
+ if (text_flags & NSID3V2_TEXT_SYSTEM)
+ return NXStringCreateWithBytes(value, parsed.data, parsed.byte_length, nx_charset_system);
+ else
+ return NXStringCreateWithBytes(value, parsed.data, parsed.byte_length, nx_charset_latin1);
+ case 1: // UTF-16
+ if (parsed.byte_length < 2)
+ return NXStringCreateEmpty(value);
+ return NXStringCreateWithBytes(value, parsed.data, parsed.byte_length, nx_charset_utf16le);
+ case 2: // UTF-16BE
+ if (parsed.byte_length < 2)
+ return NXStringCreateEmpty(value);
+ return NXStringCreateWithBytes(value, parsed.data, parsed.byte_length, nx_charset_utf16be);
+ case 3: // UTF-8
+ if (parsed.byte_length == 0)
+ return NXStringCreateEmpty(value);
+ return NXStringCreateWithBytes(value, parsed.data, parsed.byte_length, nx_charset_utf8);
+ default:
+ return NErr_Unknown;
+ }
+
+}
+
+bool DescriptionMatches(const ParsedString &parsed, const char *description, int text_flags)
+{
+ // see if our description matches
+ switch(parsed.encoding)
+ {
+ case 0: // ISO-8859-1
+ return !strcasecmp(description, (const char *)parsed.data);
+ case 1:
+ {
+ bytereader_value_t utf16;
+ bytereader_init(&utf16, parsed.data, parsed.byte_length);
+
+ while (*description && bytereader_size(&utf16))
+ {
+ if ((*description++ & ~0x20) != (bytereader_read_u16_le(&utf16) & ~0x20))
+ return false;
+ }
+
+ if (*description == 0 && bytereader_size(&utf16) == 0)
+ return true;
+ else
+ return false;
+ }
+
+ case 2:
+ {
+ bytereader_value_t utf16;
+ bytereader_init(&utf16, parsed.data, parsed.byte_length);
+
+ while (*description && bytereader_size(&utf16))
+ {
+ if ((*description++ & ~0x20) != (bytereader_read_u16_be(&utf16) & ~0x20))
+ return false;
+ }
+ if (*description == 0 && bytereader_size(&utf16) == 0)
+ return true;
+ else
+ return false;
+ }
+ case 3:
+ return !strcasecmp(description, (const char *)parsed.data);
+ }
+
+ return false;
+}