diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/replicant/nsid3v2/frame_utils.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/replicant/nsid3v2/frame_utils.cpp')
-rw-r--r-- | Src/replicant/nsid3v2/frame_utils.cpp | 265 |
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; +} |