20#include "id3dependencies/ByteStream/include/byteStream.h"
21#include "id3dependencies/ByteStream/include/byteInt.h"
22#include "id3dependencies/ByteStream/include/byteUnicode.h"
24static void internal_copyNBits(
const unsigned char *src,
unsigned char *dest,
int startBit,
int nBits) {
25 int byteIndex = startBit / CHAR_BIT;
26 int bitIndex = startBit % CHAR_BIT;
27 int remainingBits = nBits;
33 while (remainingBits > 0) {
34 unsigned char mask = 0xFF >> (CHAR_BIT - remainingBits);
35 unsigned char shiftedMask = mask << bitIndex;
38 dest[byteIndex] &= ~shiftedMask;
41 dest[byteIndex] |= (src[byteIndex] & shiftedMask) >> bitIndex;
44 remainingBits -= (CHAR_BIT - bitIndex);
74 if (in == NULL || inl == 0) {
75 *extendedTagHeader = NULL;
79 ByteStream *stream = byteStreamCreate(in, inl);
82 *extendedTagHeader = NULL;
90 bool tagRestrictions =
false;
91 uint8_t restrictions = 0;
96 unsigned char crcBytes[5] = {0, 0, 0, 0, 0};
98 bool hasRestrictions =
false;
99 ByteStream *innerStream = NULL;
106 hSize = byteStreamReturnInt(stream);
108 *extendedTagHeader = NULL;
109 byteStreamDestroy(stream);
113 if (hSize > (stream->bufferSize - stream->cursor)) {
114 offset = hSize - (stream->bufferSize - stream->cursor);
118 innerStream = byteStreamCreate(byteStreamCursor(stream), hSize - offset);
122 flags = (int8_t) byteStreamReadBit(innerStream, 7);
130 if (!(byteStreamSeek(innerStream, 2, SEEK_CUR))) {
135 padding = byteStreamReturnInt(innerStream);
145 crc = byteStreamReturnInt(innerStream);
156 if (!(byteStreamSeek(innerStream, 1, SEEK_CUR))) {
161 if (byteStreamReadBit(innerStream, 6)) {
165 if (byteStreamReadBit(innerStream, 5)) {
169 if (byteStreamReadBit(innerStream, 4)) {
170 hasRestrictions =
true;
173 if (!(byteStreamSeek(innerStream, 1, SEEK_CUR))) {
179 if (!(byteStreamRead(innerStream, (uint8_t *) crcBytes, 5))) {
183 crc = byteSyncintDecode(btoi(crcBytes, 5));
187 if (hasRestrictions) {
188 for (uint8_t k = 8; k > 0; k--) {
189 int bit = byteStreamReadBit(innerStream, k - 1);
195 restrictions = setBit(restrictions, k - 1, (
bool) bit);
198 tagRestrictions =
true;
200 if (!(byteStreamSeek(innerStream, 1, SEEK_CUR))) {
209 byteStreamDestroy(innerStream);
210 *extendedTagHeader = NULL;
215 byteStreamDestroy(stream);
217 walk = innerStream->cursor + 4;
219 if (innerStream != NULL) {
220 byteStreamDestroy(innerStream);
251 if (in == NULL || inl == 0) {
256 ByteStream *stream = byteStreamCreate(in, inl);
273 uint32_t idAsInt = 0;
282 idAsInt = (idAsInt << 8) |
id[i];
293 if (!(byteStreamRead(stream, &major, 1))) {
297 if (!(byteStreamRead(stream, &minor, 1))) {
302 if (!(byteStreamRead(stream, &flags, 1))) {
307 hSize = byteStreamReturnSyncInt(stream);
315 walk = stream->cursor;
318 byteStreamDestroy(stream);
352 uint32_t *frameSize) {
353 if (in == NULL || inl == 0) {
359 ByteStream *stream = byteStreamCreate(in, inl);
369 bool tagAlter =
false;
370 bool fileAlter =
false;
371 bool readOnly =
false;
373 uint32_t decompressionSize = 0;
374 uint8_t encryptionSymbol = 0;
375 uint8_t groupSymbol = 0;
388 byteStreamDestroy(stream);
395 byteStreamDestroy(stream);
409 byteStreamDestroy(stream);
413 tSize = byteStreamReturnU32(stream);
417 byteStreamDestroy(stream);
424 byteStreamDestroy(stream);
428 if (readBit(flagBytes[0], 7)) {
432 if (readBit(flagBytes[0], 6)) {
436 if (readBit(flagBytes[0], 5)) {
440 if (readBit(flagBytes[1], 7)) {
441 decompressionSize = byteStreamReturnInt(stream);
442 if (!decompressionSize) {
447 if (readBit(flagBytes[1], 6)) {
448 if (!(byteStreamRead(stream, &encryptionSymbol, 1))) {
453 if (readBit(flagBytes[1], 5)) {
454 if (!(byteStreamRead(stream, &groupSymbol, 1))) {
465 byteStreamDestroy(stream);
469 tSize = byteStreamReturnSyncInt(stream);
473 byteStreamDestroy(stream);
480 byteStreamDestroy(stream);
484 if (readBit(flagBytes[0], 6)) {
488 if (readBit(flagBytes[0], 5)) {
492 if (readBit(flagBytes[0], 4)) {
496 if (readBit(flagBytes[1], 6)) {
497 if (!byteStreamRead(stream, &groupSymbol, 1)) {
502 if (readBit(flagBytes[1], 2)) {
503 if (!byteStreamRead(stream, &encryptionSymbol, 1)) {
508 if (readBit(flagBytes[1], 1)) {
512 if (readBit(flagBytes[1], 3) || encryptionSymbol || readBit(flagBytes[1], 0)) {
513 decompressionSize = byteStreamReturnSyncInt(stream);
522 byteStreamDestroy(stream);
527 encryptionSymbol, groupSymbol);
529 walk = stream->cursor;
530 byteStreamDestroy(stream);
566 if (in == NULL || inl == 0) {
571 ByteStream *stream = byteStreamCreate(in, inl);
573 if (!stream || !context) {
580 List *entries = NULL;
585 size_t currIterations = 0;
586 size_t concurrentBitCount = 0;
587 uint32_t expectedHeaderSize = 0;
588 uint32_t expectedContentSize = 0;
589 ByteStream *innerStream = NULL;
591 ListIter iterStorage;
592 void *contextData = NULL;
595 &expectedContentSize);
596 walk += expectedHeaderSize;
597 if (!expectedHeaderSize) {
598 if (header != NULL) {
602 byteStreamDestroy(stream);
606 if (header == NULL || !expectedContentSize) {
608 if (header != NULL) {
612 byteStreamDestroy(stream);
613 return expectedHeaderSize;
616 byteStreamSeek(stream, expectedHeaderSize, SEEK_CUR);
618 innerStream = byteStreamCreate(byteStreamCursor(stream), expectedContentSize);
627 uint8_t *data = NULL;
639 if (dataSize > expectedContentSize) {
640 dataSize = expectedContentSize;
643 data = malloc(dataSize);
645 if (!byteStreamRead(innerStream, data, dataSize)) {
646 memset(data, 0, dataSize);
652 walk += innerStream->cursor;
654 byteStreamDestroy(innerStream);
655 byteStreamDestroy(stream);
659 iter = listCreateIterator(context);
661 while ((contextData = listIteratorNext(&iter)) != NULL) {
667 uint8_t *data = NULL;
672 uint8_t encoding = 0;
673 ListIter contentContextIter = listCreateIterator(context);
674 ListIter contentEntryIter = listCreateIterator(entries);
677 while ((tmp = listIteratorNext(&contentContextIter)) != NULL) {
689 while ((tmp = listIteratorNext(&contentEntryIter)) != NULL) {
690 if (poscc == posce) {
698 case BYTE_ISO_8859_1:
701 data = byteStreamReturnUtf8(innerStream, &dataSize);
703 if (data == NULL && dataSize == 0) {
704 byteStreamSeek(innerStream, 1, SEEK_CUR);
705 data = calloc(
sizeof(
unsigned char), 1);
712 data = byteStreamReturnUtf16(innerStream, &dataSize);
714 if (data == NULL && dataSize == 0) {
715 byteStreamSeek(innerStream, 2, SEEK_CUR);
716 data = calloc(
sizeof(
unsigned char), 2);
725 if (dataSize > cc->
max) {
726 uint8_t *reallocPtr = realloc(data, cc->
max);
727 if (reallocPtr == NULL) {
730 byteStreamDestroy(innerStream);
731 byteStreamDestroy(stream);
738 }
else if (cc->
min > dataSize) {
739 uint8_t *reallocPtr = realloc(data, cc->
min);
740 if (reallocPtr == NULL) {
743 byteStreamDestroy(innerStream);
744 byteStreamDestroy(stream);
750 memset(data + dataSize, 0, cc->
min - dataSize);
757 expectedContentSize = ((expectedContentSize < dataSize) ? 0 : expectedContentSize - dataSize);
762 uint8_t *data = NULL;
765 data = byteStreamReturnLatin1(innerStream, &dataSize);
767 if (dataSize > cc->
max) {
769 uint8_t *reallocPtr = realloc(data, dataSize);
770 if (reallocPtr == NULL) {
773 byteStreamDestroy(innerStream);
774 byteStreamDestroy(stream);
780 }
else if (cc->
min > dataSize) {
781 uint8_t *reallocPtr = realloc(data, cc->
min);
782 if (reallocPtr == NULL) {
785 byteStreamDestroy(innerStream);
786 byteStreamDestroy(stream);
792 memset(data + dataSize, 0, cc->
min - dataSize);
799 expectedContentSize = ((expectedContentSize < dataSize) ? 0 : expectedContentSize - dataSize);
807 uint8_t *data = NULL;
817 if (dataSize > expectedContentSize) {
818 dataSize = expectedContentSize;
821 data = calloc(
sizeof(uint8_t), dataSize);
823 if (!byteStreamRead(innerStream, data, dataSize)) {
824 memset(data, 0, dataSize);
830 expectedContentSize = ((expectedContentSize < dataSize) ? 0 : expectedContentSize - dataSize);
834 uint8_t *data = NULL;
846 dataSize = (nBits + (CHAR_BIT - 1)) / CHAR_BIT;
848 data = malloc(dataSize);
849 memset(data, 0, dataSize);
850 internal_copyNBits(byteStreamCursor(innerStream), data, (
int) concurrentBitCount, (
int) nBits);
852 if (iter.current->data != NULL) {
854 isBitContext = nextContext->
type;
857 concurrentBitCount += nBits;
860 if (concurrentBitCount / CHAR_BIT) {
861 byteStreamSeek(innerStream, concurrentBitCount / CHAR_BIT, SEEK_CUR);
862 expectedContentSize = ((expectedContentSize < dataSize) ? 0 : expectedContentSize - dataSize);
865 concurrentBitCount = 0;
873 if (!currIterations) {
876 iter = listCreateIterator(context);
878 for (
size_t i = 0; i < cc->
min; i++) {
879 listIteratorNext(&iter);
883 if (currIterations != cc->
max && currIterations != 0) {
884 iter = listCreateIterator(context);
886 for (
size_t i = 0; i < cc->
min; i++) {
887 listIteratorNext(&iter);
892 if (currIterations >= cc->
max) {
895 for (
size_t i = 0; i < currIterations; i++) {
896 listIteratorNext(&iter);
906 uint8_t *data = NULL;
912 ListIter contentContextIter = listCreateIterator(context);
913 ListIter contentEntryIter = listCreateIterator(entries);
916 while ((tmp = listIteratorNext(&contentContextIter)) != NULL) {
928 while ((tmp = listIteratorNext(&contentEntryIter)) != NULL) {
929 if (poscc == posce) {
937 if (dataSize > expectedContentSize) {
938 dataSize = expectedContentSize;
941 data = malloc(dataSize);
942 memset(data, 0, dataSize);
943 byteStreamRead(innerStream, data, dataSize);
948 expectedContentSize = ((expectedContentSize < dataSize) ? 0 : expectedContentSize - dataSize);
954 byteStreamSeek(innerStream, 0, SEEK_END);
958 if (expectedContentSize == 0 || byteStreamGetCh(innerStream) == EOF) {
965 walk += innerStream->bufferSize;
968 byteStreamDestroy(innerStream);
969 byteStreamDestroy(stream);
1002 if (in == NULL || inl == 0) {
1006 ByteStream *stream = byteStreamCreate(in, inl);
1014 uint32_t tagSize = 0;
1018 List *frames = NULL;
1019 HashTable *pairs = NULL;
1027 byteStreamDestroy(stream);
1038 read =
id3v2ParseTagHeader(byteStreamCursor(stream), stream->bufferSize - stream->cursor, &header, &tagSize);
1040 if (read == 0 || header == NULL || tagSize == 0) {
1044 if (!byteStreamSeek(stream, read, SEEK_CUR)) {
1049 byteStreamResize(stream, tagSize + read);
1052 size_t readCount = 0;
1053 tagSize = tagSize / 2;
1054 while (readCount < tagSize) {
1055 byteStreamSeek(stream, 1, SEEK_CUR);
1056 if (!byteStreamDeleteCh(stream)) {
1063 byteStreamSeek(stream, 10, SEEK_SET);
1072 if (read == 0 || ext == NULL) {
1076 tagSize = ((tagSize < read) ? 0 : tagSize - read);
1077 byteStreamSeek(stream, read, SEEK_CUR);
1084 List *context = NULL;
1104 context = hashTableRetrieve(pairs, (
char *) frameId);
1107 if (context == NULL) {
1108 context = hashTableRetrieve(userPairs, (
char *) frameId);
1112 if (context == NULL) {
1113 if (frameId[0] ==
'T') {
1114 context = hashTableRetrieve(pairs,
"T");
1117 if (frameId[0] ==
'W') {
1118 context = hashTableRetrieve(pairs,
"W");
1123 if (context == NULL) {
1124 context = hashTableRetrieve(pairs,
"?");
1127 read =
id3v2ParseFrame(byteStreamCursor(stream), stream->bufferSize - stream->cursor, context,
1130 if (read == 0 || frame == NULL) {
1135 listInsertBack(frames, frame);
1136 tagSize = ((tagSize < read) ? 0 : tagSize - read);
1137 byteStreamSeek(stream, read, SEEK_CUR);
1140 if (pairs != NULL) {
1141 hashTableFree(pairs);
1149 byteStreamDestroy(stream);
1153 byteStreamDestroy(stream);
Function definitions for ID3v2 frame context definitions and parsing configuration.
unsigned long id3v2djb2(const char *str)
Computes a DJB2 hash value for a null-terminated string.
HashTable * id3v2CreateDefaultIdentifierContextPairings(unsigned int version)
Creates a default mapping of frame identifiers to their corresponding parse contexts for all ID3v2 ve...
List * id3v2CreateGenericFrameContext(void)
Creates a context definition list for generic frames with unknown or unrecognized structure.
Function definitions for ID3v2 frame lifecycle, traversal, serialization, and content management.
int id3v2CompareFrame(const void *first, const void *second)
Performs deep comparison of two ID3v2 frame structures.
void * id3v2CopyContentEntry(const void *toBeCopied)
Creates a deep copy of a content entry.
Id3v2FrameHeader * id3v2CreateFrameHeader(uint8_t id[ID3V2_FRAME_ID_MAX_SIZE], bool tagAlter, bool fileAlter, bool readOnly, bool unsync, uint32_t decompressionSize, uint8_t encryptionSymbol, uint8_t groupSymbol)
Creates an ID3v2 frame header structure with specified flags and metadata.
Id3v2Frame * id3v2CreateFrame(Id3v2FrameHeader *header, List *context, List *entries)
Creates an ID3v2 frame structure from provided components.
void * id3v2CopyFrame(const void *toBeCopied)
Creates a deep copy of an ID3v2 frame structure.
Id3v2ContentEntry * id3v2CreateContentEntry(void *entry, size_t size)
Creates a content entry structure with a deep copy of the provided data.
char * id3v2PrintContentEntry(const void *toBePrinted)
Generates a string representation of a content entry for debugging.
void id3v2DeleteContentEntry(void *toBeDeleted)
Frees all memory allocated for a content entry structure.
int id3v2CompareContentEntry(const void *first, const void *second)
Compares two content entries byte-by-byte and returns the difference.
void id3v2DestroyFrameHeader(Id3v2FrameHeader **toDelete)
Frees all memory allocated for a frame header and nullifies the pointer.
char * id3v2PrintFrame(const void *toBePrinted)
Generates a string representation of a frame for debugging.
void id3v2DeleteFrame(void *toBeDeleted)
Frees all memory allocated for an ID3v2 frame structure.
uint32_t id3v2ParseTagHeader(uint8_t *in, size_t inl, Id3v2TagHeader **tagHeader, uint32_t *tagSize)
Parses an ID3v2 tag header from a byte buffer (excluding extended header).
uint32_t id3v2ParseExtendedTagHeader(uint8_t *in, size_t inl, uint8_t version, Id3v2ExtendedTagHeader **extendedTagHeader)
Parses an ID3v2 extended tag header from a byte buffer.
uint32_t id3v2ParseFrame(uint8_t *in, size_t inl, List *context, uint8_t version, Id3v2Frame **frame)
Parses an ID3v2 frame (header + content) from a byte buffer using context-driven interpretation.
uint32_t id3v2ParseFrameHeader(uint8_t *in, size_t inl, uint8_t version, Id3v2FrameHeader **frameHeader, uint32_t *frameSize)
Parses an ID3v2 frame header from a byte buffer.
Id3v2Tag * id3v2ParseTagFromBuffer(uint8_t *in, size_t inl, HashTable *userPairs)
Parses a complete ID3v2 tag from a byte buffer, including header, optional extended header,...
Definitions for binary parsing of ID3v2 tags, headers, frames, and complete tag structures from byte ...
Function definitions of ID3v2 tag header and tag structure creation, manipulation,...
Id3v2Tag * id3v2CreateTag(Id3v2TagHeader *header, List *frames)
Creates and allocates an ID3v2 tag structure.
Id3v2ExtendedTagHeader * id3v2CreateExtendedTagHeader(uint32_t padding, uint32_t crc, bool update, bool tagRestrictions, uint8_t restrictions)
Creates and allocates an ID3v2 extended tag header structure.
int id3v2ReadUnsynchronisationIndicator(Id3v2TagHeader *header)
Reads the unsynchronisation flag from a tag header.
Id3v2TagHeader * id3v2CreateTagHeader(uint8_t majorVersion, uint8_t minorVersion, uint8_t flags, Id3v2ExtendedTagHeader *extendedHeader)
Creates and allocates an ID3v2 tag header structure.
int id3v2ReadExtendedHeaderIndicator(Id3v2TagHeader *header)
Reads the extended header flag from an ID3v2.3/ID3v2.4 tag header.
#define ID3V2_TAG_VERSION_3
ID3v2.3 major version number (3)
struct _Id3v2ContentEntry Id3v2ContentEntry
Parsed data field from an ID3v2 frame.
struct _Id3v2ContentContext Id3v2ContentContext
Parsing instructions for a single field within an ID3v2 frame.
struct _Id3v2Tag Id3v2Tag
Complete ID3v2 tag structure containing header and metadata frames.
#define ID3V2_FRAME_ID_MAX_SIZE
Maximum size in bytes for a frame ID field (4 bytes).
#define ID3V2_TAG_VERSION_2
ID3v2.2 major version number (2)
@ noEncoding_context
Raw character data with no encoding or null terminator.
@ iter_context
Iterator for repeating context sequences.
@ numeric_context
Integer values of 8, 16, 32, or 64 bits.
@ encodedString_context
Text string with encoding determined by prior context with the key 'encoding'.
@ latin1Encoding_context
Latin-1 (ISO-8859-1) null-terminated string.
@ adjustment_context
Dynamic upper bound adjustment based on prior context with key 'adjustment'.
@ binary_context
Binary data block with no terminator.
@ bit_context
Bit-level field (1-8 bits).
@ precision_context
Floating-point values (float or double).
@ unknown_context
Error/invalid context state (-1).
struct _Id3v2ExtendedTagHeader Id3v2ExtendedTagHeader
Optional ID3v2 extended header containing supplementary tag metadata.
enum _Id3v2ContextType Id3v2ContextType
Context types for parsing and writing ID3v2 frame content fields.
struct _Id3v2Frame Id3v2Frame
Complete ID3v2 frame structure with header, parsing contexts, and data.
#define ID3V2_FRAME_FLAG_SIZE
Size in bytes of a frame header's flag section (2 bytes).
#define ID3V2_TAG_ID_SIZE
Size in bytes of the ID3v2 tag identifier "ID3" or "3DI" (3 bytes)
#define ID3V2_TAG_VERSION_4
ID3v2.4 major version number (4)
struct _Id3v2FrameHeader Id3v2FrameHeader
ID3v2 frame header containing identification and processing flags.
#define ID3V2_TAG_ID_MAGIC_NUMBER_H
Hexadecimal magic number for ID3v2 header tag identifier "ID3" (0x494433)
struct _Id3v2TagHeader Id3v2TagHeader
ID3v2 tag header containing version and parsing information.
size_t min
Minimum size in bytes (or bits for bit_context, or start index for iter_context).
size_t max
Maximum size in bytes (or bits for bit_context, or iteration count for iter_context).
Id3v2ContextType type
Context type determining parsing behavior (string, binary, numeric, etc.)