15#include "id3dependencies/ByteStream/include/byteStream.h"
16#include "id3dependencies/ByteStream/include/byteUnicode.h"
17#include "id3dependencies/ByteStream/include/byteInt.h"
32 ByteStream *stream = NULL;
35 if (filename == NULL) {
39 stream = byteStreamFromFile(filename);
45 byteStreamDestroy(stream);
64 if (toCopy->
header == NULL) {
90 if (tag1 == NULL || tag2 == NULL) {
174 if (
id == NULL || tag == NULL) {
192 if (memcmp(
id, f->
header->
id, i) == 0) {
217 if (remove != NULL) {
237 if (
id == NULL ||
string == NULL || tag == NULL || encoding > BYTE_UTF8) {
241 if (strlen(
string) == 0) {
248 uint8_t *usableString = NULL;
260 listInsertBack(f->
entries, (
void *) entry);
263 convi = byteConvertTextFormat((
unsigned char *)
string, BYTE_UTF8, strlen(
string), &usableString, encoding,
267 if (convi ==
true && outLen == 0) {
268 usableString = (uint8_t *) strdup(
string);
270 if (usableString == NULL) {
275 outLen = strlen(
string);
276 }
else if (convi ==
false || outLen == 0 || usableString == NULL) {
282 bytePrependBOM(encoding, &usableString, &outLen);
284 if (encoding == BYTE_UTF16BE || encoding == BYTE_UTF16LE) {
287 uint8_t *reallocPtr = realloc(usableString, outLen + BYTE_PADDING);
288 if (reallocPtr == NULL) {
293 usableString = reallocPtr;
294 memset(usableString + outLen, 0, BYTE_PADDING);
299 listInsertBack(f->
entries, (
void *) entry);
302 listInsertBack(tag->
frames, (
void *) f);
321 if (tag->
header == NULL) {
339 ListIter entries = {0};
340 ListIter context = {0};
355 context = listCreateIterator(frame->
contexts);
357 for (
int i = 0; i < 2; i++) {
358 cc = listIteratorNext(&context);
660 ListIter entries = {0};
661 ListIter context = {0};
693 context = listCreateIterator(frame->
contexts);
695 for (
int i = 0; i < 4; i++) {
696 cc = listIteratorNext(&context);
729 ListIter entries = {0};
730 ListIter context = {0};
762 context = listCreateIterator(frame->
contexts);
764 for (
int i = 0; i < 4; i++) {
765 cc = listIteratorNext(&context);
805 ListIter frames = listCreateIterator(tag->
frames);
806 uint8_t usableType = ((type > 0x14) ? 0x00 : type);
808 while ((f = listIteratorNext(&frames)) != NULL) {
837 if (
id == NULL ||
string == NULL || tag == NULL) {
842 if (strlen(
string) == 0) {
848 ListIter context = {0};
849 ListIter entries = {0};
851 uint8_t encoding = 0;
852 uint8_t *usableString = NULL;
866 if (memcmp(
id, f->
header->
id, i) == 0) {
880 context = listCreateIterator(f->
contexts);
882 for (
int j = 0; j < 2; j++) {
883 cc = listIteratorNext(&context);
895 convi = byteConvertTextFormat((
unsigned char *)
string, BYTE_UTF8, strlen(
string), &usableString, encoding,
898 if (!convi && outLen == 0 && usableString == NULL) {
903 if (convi && outLen == 0) {
904 usableString = (uint8_t *) strdup(
string);
905 outLen = strlen(
string);
908 bytePrependBOM(encoding, &usableString, &outLen);
911 if (encoding == BYTE_UTF16BE || encoding == BYTE_UTF16LE) {
914 uint8_t *reallocPtr = realloc(usableString, outLen + BYTE_PADDING);
915 if (reallocPtr == NULL) {
919 usableString = reallocPtr;
920 memset(usableString + outLen, 0, BYTE_PADDING);
923 if (
id3v2WriteFrameEntry(f, &entries, byteStrlen(encoding, usableString), (
void *) usableString)) {
930 if (usableString != NULL) {
948 if (title == NULL || tag == NULL) {
974 if (artist == NULL || tag == NULL) {
1000 if (albumArtist == NULL || tag == NULL) {
1026 if (album == NULL || tag == NULL) {
1052 if (year == NULL || tag == NULL) {
1078 if (genre == NULL || tag == NULL) {
1104 if (track == NULL || tag == NULL) {
1130 if (disc == NULL || tag == NULL) {
1156 if (composer == NULL || tag == NULL) {
1174static int internal_id3v2CreateLyricFrameUTF16LE(
const uint8_t v,
const char *lyrics,
Id3v2Tag *tag) {
1177 if (lyrics == NULL) {
1182 if (strlen(lyrics) == 0) {
1187 ListIter entries = {0};
1188 uint8_t encoding = BYTE_UTF16LE;
1189 uint8_t *usableString = NULL;
1237 convi = byteConvertTextFormat((
unsigned char *) lyrics, BYTE_UTF8, strlen(lyrics), &usableString, BYTE_UTF16LE,
1240 if (convi ==
false || outLen == 0 || usableString == NULL) {
1246 bytePrependBOM(encoding, &usableString, &outLen);
1250 uint8_t *reallocPtr = realloc(usableString, outLen + BYTE_PADDING);
1251 if (reallocPtr == NULL) {
1256 usableString = reallocPtr;
1258 memset(usableString + outLen, 0, BYTE_PADDING);
1272 listInsertBack(tag->
frames, (
void *) f);
1291 if (lyrics == NULL || tag == NULL) {
1296 if (strlen(lyrics) == 0) {
1302 ListIter context = {0};
1303 ListIter entries = {0};
1305 uint8_t encoding = 0;
1306 uint8_t *usableString = NULL;
1315 memcpy(
id,
"ULT", i);
1320 memcpy(
id,
"USLT", i);
1327 if (memcmp(
id, f->
header->
id, i) == 0) {
1333 return internal_id3v2CreateLyricFrameUTF16LE(tag->
header->
majorVersion, lyrics, tag);
1341 context = listCreateIterator(f->
contexts);
1343 for (
int j = 0; j < 4; j++) {
1344 cc = listIteratorNext(&context);
1358 convi = byteConvertTextFormat((
unsigned char *) lyrics, BYTE_UTF8, strlen(lyrics), &usableString, encoding,
1361 if (!convi && outLen == 0 && usableString == NULL) {
1366 if (convi && outLen == 0) {
1367 usableString = (uint8_t *) strdup(lyrics);
1368 outLen = strlen(lyrics);
1371 bytePrependBOM(encoding, &usableString, &outLen);
1374 if (encoding == BYTE_UTF16BE || encoding == BYTE_UTF16LE) {
1377 uint8_t *reallocPtr = realloc(usableString, outLen + BYTE_PADDING);
1378 if (reallocPtr == NULL) {
1382 usableString = reallocPtr;
1383 memset(usableString + outLen, 0, BYTE_PADDING);
1389 if (
id3v2WriteFrameEntry(f, &entries, byteStrlen(encoding, usableString), (
void *) usableString)) {
1396 if (usableString != NULL) {
1408static int internal_id3v2CreateCommentFrameUTF16LE(uint8_t v,
const char lang[3],
const char *desc,
const char *comment,
1412 if (lang == NULL || desc == NULL || comment == NULL) {
1417 if (strlen(lang) != 3 || strlen(comment) == 0) {
1424 uint8_t *usableString = NULL;
1425 uint8_t encoding = BYTE_UTF16LE;
1448 listInsertBack(f->
entries, (
void *) ce);
1451 listInsertBack(f->
entries, (
void *) ce);
1454 if (strlen(desc) != 0) {
1455 convi = byteConvertTextFormat((
unsigned char *) desc, BYTE_UTF8, strlen(desc), &usableString, encoding,
1458 if (!convi && outLen == 0 && usableString == NULL) {
1464 if (convi && outLen == 0) {
1465 usableString = (uint8_t *) strdup(desc);
1466 outLen = strlen(desc);
1469 bytePrependBOM(encoding, &usableString, &outLen);
1472 if (encoding == BYTE_UTF16BE || encoding == BYTE_UTF16LE) {
1475 uint8_t *reallocPtr = realloc(usableString, outLen + BYTE_PADDING);
1476 if (reallocPtr == NULL) {
1481 usableString = reallocPtr;
1483 memset(usableString + outLen, 0, BYTE_PADDING);
1487 listInsertBack(f->
entries, (
void *) ce);
1490 usableString = NULL;
1494 listInsertBack(f->
entries, (
void *) ce);
1497 convi = byteConvertTextFormat((
unsigned char *) comment, BYTE_UTF8, strlen(comment), &usableString, encoding,
1500 if (!convi && outLen == 0 && usableString == NULL) {
1508 if (convi && outLen == 0) {
1509 usableString = (uint8_t *) strdup(comment);
1510 outLen = strlen(comment);
1513 bytePrependBOM(encoding, &usableString, &outLen);
1516 if (encoding == BYTE_UTF16BE || encoding == BYTE_UTF16LE) {
1519 uint8_t *reallocPtr = realloc(usableString, outLen + BYTE_PADDING);
1520 if (reallocPtr == NULL) {
1527 usableString = reallocPtr;
1528 memset(usableString + outLen, 0, BYTE_PADDING);
1533 listInsertBack(f->
entries, (
void *) ce);
1536 listInsertBack(tag->
frames, (
void *) f);
1554 if (comment == NULL || tag == NULL) {
1559 if (strlen(comment) == 0) {
1565 ListIter context = {0};
1566 ListIter entries = {0};
1568 uint8_t encoding = 0;
1569 uint8_t *usableString = NULL;
1579 memcpy(
id,
"COM", i);
1584 memcpy(
id,
"COMM", i);
1591 if (memcmp(
id, f->
header->
id, i) == 0) {
1597 return internal_id3v2CreateCommentFrameUTF16LE(tag->
header->
majorVersion,
"zxx",
"", comment, tag);
1606 context = listCreateIterator(f->
contexts);
1608 for (
int j = 0; j < 4; j++) {
1609 cc = listIteratorNext(&context);
1623 convi = byteConvertTextFormat((
unsigned char *) comment, BYTE_UTF8, strlen(comment), &usableString, encoding,
1626 if (!convi && outLen == 0 && usableString == NULL) {
1631 if (convi && outLen == 0) {
1632 usableString = (uint8_t *) strdup(comment);
1633 outLen = strlen(comment);
1636 bytePrependBOM(encoding, &usableString, &outLen);
1639 if (encoding == BYTE_UTF16BE || encoding == BYTE_UTF16LE) {
1642 uint8_t *reallocPtr = realloc(usableString, outLen + BYTE_PADDING);
1643 if (reallocPtr == NULL) {
1647 usableString = reallocPtr;
1648 memset(usableString + outLen, 0, BYTE_PADDING);
1654 if (
id3v2WriteFrameEntry(f, &entries, byteStrlen(encoding, usableString), (
void *) usableString)) {
1661 if (usableString != NULL) {
1671static int internal_id3v2CreatePictureFrameUTF16LEtype0(uint8_t v, uint8_t *image,
size_t imageSize,
const char *kind,
1675 if (image == NULL || imageSize == 0 || kind == NULL || tag == NULL) {
1680 if (strlen(kind) == 0) {
1685 ListIter entries = {0};
1686 uint8_t encoding = BYTE_UTF16LE;
1718 kindLen = strlen(kind);
1733 mime = calloc(
sizeof(
char), strlen(
"image/") + strlen(kind) + 1);
1735 memcpy(mime,
"image/", strlen(
"image/"));
1738 memcpy(mime + strlen(
"image/"), kind, strlen(kind));
1776 listInsertBack(tag->
frames, (
void *) f);
1795 if (image == NULL || imageSize == 0 || kind == NULL || tag == NULL) {
1799 if (strlen(kind) == 0) {
1805 ListIter context = {0};
1806 ListIter entries = {0};
1808 uint8_t usableType = ((type > 0x14) ? 0x00 : type);
1817 memcpy(
id,
"PIC", i);
1822 memcpy(
id,
"APIC", i);
1831 if (memcmp(
id, f->
header->
id, i) == 0) {
1837 return internal_id3v2CreatePictureFrameUTF16LEtype0(tag->
header->
majorVersion, image, imageSize, kind, tag);
1845 context = listCreateIterator(f->
contexts);
1847 for (
int j = 0; j < 4; j++) {
1848 cc = listIteratorNext(&context);
1880 kindLen = (int) strlen(kind);
1895 mime = calloc(
sizeof(
char), strlen(
"image/") + strlen(kind) + 1);
1897 memcpy(mime,
"image/", strlen(
"image/"));
1900 memcpy(mime + strlen(
"image/"), kind, strlen(kind));
1933 if (filename == NULL || kind == NULL || tag == NULL) {
1937 if (strlen(filename) == 0 || strlen(kind) == 0) {
1942 uint8_t *data = NULL;
1946 f = fopen(filename,
"rb");
1952 (void) fseek(f, 0, SEEK_END);
1954 (void) fseek(f, 0, SEEK_SET);
1956 data = calloc(
sizeof(uint8_t), size);
1958 if (fread(data,
sizeof(uint8_t), size, f) != size) {
1995 ByteStream *stream = NULL;
1996 ByteStream *headerStream = NULL;
1997 ByteStream *frameStream = NULL;
1998 ByteStream *footerStream = NULL;
2002 uint32_t padding = 0;
2003 uint8_t *sizeBytes = NULL;
2004 uint8_t *headerOut = NULL;
2005 uint8_t *out = NULL;
2006 size_t headerOutl = 0;
2010 ByteStream *tmp = NULL;
2011 size_t frameOutl = 0;
2012 uint8_t *frameOut = NULL;
2016 if (frameOut == NULL && frameOutl == 0) {
2020 tmp = byteStreamCreate(frameOut, frameOutl);
2027 if (frameStream == NULL) {
2028 frameStream = byteStreamCreate(byteStreamCursor(tmp), tmp->bufferSize);
2029 byteStreamSeek(frameStream, 0, SEEK_END);
2031 byteStreamResize(frameStream, frameStream->bufferSize + tmp->bufferSize);
2032 byteStreamWrite(frameStream, tmp->buffer, tmp->bufferSize);
2034 byteStreamDestroy(tmp);
2038 if (frameStream == NULL) {
2043 byteStreamRewind(frameStream);
2047 ByteStream *tmp = NULL;
2049 tmp = byteStreamCreate(NULL, frameStream->bufferSize * 2);
2051 for (
size_t i = 0; i < frameStream->bufferSize; i++) {
2052 byteStreamWrite(tmp, byteStreamCursor(frameStream), 1);
2054 byteStreamSeek(tmp, 1, SEEK_CUR);
2055 byteStreamSeek(frameStream, 1, SEEK_CUR);
2058 byteStreamDestroy(frameStream);
2060 fsize = frameStream->bufferSize;
2061 byteStreamRewind(frameStream);
2063 fsize = frameStream->bufferSize;
2069 if (headerOut == NULL && headerOutl == 0) {
2070 byteStreamDestroy(frameStream);
2075 headerStream = byteStreamCreate(headerOut, headerOutl);
2080 ByteStream *tmp = NULL;
2084 size = (headerStream->bufferSize - 10) * 2;
2086 tmp = byteStreamCreate(NULL, 10 + size);
2089 byteStreamWrite(tmp, byteStreamCursor(headerStream), 10);
2090 byteStreamSeek(headerStream, 10, SEEK_SET);
2092 for (uint32_t i = 0; i < size; i++) {
2093 byteStreamWrite(tmp, byteStreamCursor(headerStream), 1);
2095 byteStreamSeek(tmp, 1, SEEK_CUR);
2096 byteStreamSeek(headerStream, 1, SEEK_CUR);
2099 byteStreamDestroy(headerStream);
2103 fsize += ((headerStream->bufferSize > 10) ? headerStream->bufferSize - 10 : 0);
2106 byteStreamRewind(headerStream);
2110 footerStream = byteStreamCreate(byteStreamCursor(headerStream), 10);
2112 byteStreamRewind(footerStream);
2121 sizeBytes = u32tob(byteSyncintEncode(fsize));
2122 byteStreamSeek(headerStream, 6, SEEK_SET);
2123 byteStreamWrite(headerStream, sizeBytes, 4);
2124 byteStreamRewind(headerStream);
2126 if (footerStream != NULL) {
2127 byteStreamSeek(footerStream, 6, SEEK_SET);
2128 byteStreamWrite(footerStream, sizeBytes, 4);
2129 byteStreamRewind(footerStream);
2135 stream = byteStreamCreate(
2136 NULL, frameStream->bufferSize + headerStream->bufferSize + ((footerStream != NULL)
2137 ? footerStream->bufferSize
2139 byteStreamWrite(stream, byteStreamCursor(headerStream), headerStream->bufferSize);
2140 byteStreamWrite(stream, byteStreamCursor(frameStream), frameStream->bufferSize);
2141 byteStreamSeek(stream, padding, SEEK_CUR);
2142 if (footerStream != NULL) {
2143 byteStreamWrite(stream, byteStreamCursor(footerStream), footerStream->bufferSize);
2144 byteStreamDestroy(footerStream);
2147 byteStreamDestroy(headerStream);
2148 byteStreamDestroy(frameStream);
2149 byteStreamRewind(stream);
2151 out = calloc(stream->bufferSize,
sizeof(uint8_t));
2152 *outl = stream->bufferSize;
2153 byteStreamRead(stream, out, stream->bufferSize);
2154 byteStreamDestroy(stream);
2186 char *headerJson = NULL;
2187 char **contentJson = NULL;
2188 char *concatenatedString = NULL;
2189 size_t contentJsonSize = 0;
2190 size_t memCount = 3;
2193 json = calloc(memCount,
sizeof(
char));
2194 memcpy(json,
"{}\0", memCount);
2199 json = calloc(memCount,
sizeof(
char));
2200 memcpy(json,
"{}\0", memCount);
2205 json = calloc(memCount,
sizeof(
char));
2206 memcpy(json,
"{}\0", memCount);
2217 size_t jsonSize = 0;
2220 jsonSize = strlen(tmp);
2223 if (contentJson == NULL) {
2226 contentJson = (
char **) calloc(contentJsonSize,
sizeof(
char *));
2227 contentJson[contentJsonSize - 1] = calloc(jsonSize + 1,
sizeof(
char));
2231 char **reallocPtr = realloc(contentJson, (contentJsonSize) *
sizeof(
char *));
2232 if (reallocPtr == NULL) {
2233 for (
size_t i = 0; i < contentJsonSize - 1; i++) {
2234 free(contentJson[i]);
2236 free((
void *) contentJson);
2242 contentJson = reallocPtr;
2243 contentJson[contentJsonSize - 1] = calloc(jsonSize + 1,
sizeof(
char));
2246 memcpy(contentJson[contentJsonSize - 1], tmp, jsonSize);
2255 if (contentJson != NULL) {
2256 size_t concatenatedStringLength = 0;
2257 for (
size_t i = 0; i < contentJsonSize; i++) {
2258 concatenatedStringLength += strlen(contentJson[i]) + 1;
2261 concatenatedString = calloc(concatenatedStringLength + 1,
sizeof(
char));
2264 for (
size_t i = 0; i < contentJsonSize; i++) {
2266 concatenatedString[offset++] =
',';
2269 const size_t currentLen = strlen(contentJson[i]);
2270 memcpy(concatenatedString + offset, contentJson[i], currentLen);
2271 offset += currentLen;
2273 concatenatedString[offset] =
'\0';
2276 memCount += snprintf(NULL, 0,
2277 "{\"header\":%s,\"content\":[%s]}",
2279 concatenatedString);
2280 json = calloc(memCount + 1,
sizeof(
char));
2281 (void) snprintf(json, memCount,
2282 "{\"header\":%s,\"content\":[%s]}",
2284 concatenatedString);
2289 if (concatenatedString != NULL) {
2290 free(concatenatedString);
2293 if (contentJson != NULL) {
2294 for (
size_t i = 0; i < contentJsonSize; i++) {
2295 free(contentJson[i]);
2297 free((
void *) contentJson);
2318 if (filePath == NULL || tag == NULL) {
2323 uint8_t *out = NULL;
2325 ByteStream *stream = NULL;
2329 if (out == NULL && outl == 0) {
2333 stream = byteStreamCreate(out, outl);
2336 fp = fopen(filePath,
"r+b");
2341 fp = fopen(filePath,
"wb");
2344 byteStreamDestroy(stream);
2348 if ((fwrite(byteStreamCursor(stream), 1, stream->bufferSize, fp)) == 0) {
2349 byteStreamDestroy(stream);
2357 bool hasTag =
false;
2360 uint8_t *tmp = NULL;
2361 uint8_t *upperTmp = NULL;
2362 size_t upperBytes = 0;
2363 uint32_t oldTagSize = 0;
2366 while (hasTag ==
false && feof(fp) == 0) {
2368 upperBytes += bytesRead;
2388 }
else if (hasTag ==
true) {
2392 (void) fseek(fp, 3, SEEK_CUR);
2394 (void) fread(tmp, 1, 4, fp);
2395 oldTagSize = byteSyncintDecode(btou32(tmp, 4));
2407 (void) fseek(fp, 0, SEEK_END);
2408 fileSize = ftell(fp);
2409 (void) fseek(fp, 0, SEEK_SET);
2412 tmp = malloc(fileSize);
2413 if (fread(tmp, 1, fileSize, fp) != fileSize) {
2416 byteStreamDestroy(stream);
2420 (void) fseek(fp, 0, SEEK_SET);
2424 if (fwrite(byteStreamCursor(stream), 1, stream->bufferSize, fp) != stream->bufferSize) {
2427 byteStreamDestroy(stream);
2432 if (fwrite(tmp, 1, fileSize, fp) != fileSize) {
2435 byteStreamDestroy(stream);
2441 uint32_t offset = 10;
2454 if (upperBytes > 0) {
2455 upperTmp = calloc(
sizeof(uint8_t), upperBytes);
2457 if (fread(upperTmp,
sizeof(
char), upperBytes, fp) != upperBytes) {
2461 byteStreamDestroy(stream);
2466 (void) fseek(fp, 0, SEEK_SET);
2470 if (fwrite(byteStreamCursor(stream), 1, stream->bufferSize, fp) != stream->bufferSize) {
2473 byteStreamDestroy(stream);
2478 fileSize = fileSize - ((long) (oldTagSize + offset)) - (
long) upperBytes;
2480 if (fwrite(tmp + upperBytes + oldTagSize + offset, 1, fileSize, fp)) {
2483 byteStreamDestroy(stream);
2492 byteStreamDestroy(stream);
int id3v2WriteLyrics(const char *lyrics, Id3v2Tag *tag)
Writes lyrics to the appropriate unsynchronized lyrics frame in a tag.
char * id3v2ReadAlbum(Id3v2Tag *tag)
Extracts the album name from an ID3v2 tag.
uint8_t * id3v2TagSerialize(Id3v2Tag *tag, size_t *outl)
Serializes an ID3v2 tag structure to its binary representation.
int id3v2WriteGenre(const char *genre, Id3v2Tag *tag)
Writes the genre/content type to an ID3v2 tag.
bool id3v2CompareTag(Id3v2Tag *tag1, Id3v2Tag *tag2)
Performs deep structural comparison of two ID3v2 tags for equality.
int id3v2WritePictureFromFile(const char *filename, const char *kind, uint8_t type, Id3v2Tag *tag)
Reads a picture from a file and writes it to the appropriate attached picture frame in a tag.
char * id3v2ReadGenre(Id3v2Tag *tag)
Extracts the genre/content type from an ID3v2 tag.
int id3v2WriteTagToFile(const char *filePath, Id3v2Tag *tag)
Writes an ID3v2 tag to a file, creating, prepending, or replacing as needed.
int id3v2WriteYear(const char *year, Id3v2Tag *tag)
Writes the year to an ID3v2 tag.
char * id3v2ReadTrack(Id3v2Tag *tag)
Extracts the track number/position from an ID3v2 tag.
char * id3v2ReadYear(Id3v2Tag *tag)
Extracts the year from an ID3v2 tag.
char * id3v2ReadTitle(Id3v2Tag *tag)
Extracts the title/song name from an ID3v2 tag.
char * id3v2ReadAlbumArtist(Id3v2Tag *tag)
Extracts the album artist/band/orchestra from an ID3v2 tag.
int id3v2WritePicture(uint8_t *image, size_t imageSize, const char *kind, uint8_t type, Id3v2Tag *tag)
Writes a picture to the appropriate attached picture frame in a tag.
char * id3v2ReadComment(Id3v2Tag *tag)
Extracts the comment text from an ID3v2 tag.
uint8_t * id3v2ReadPicture(uint8_t type, const Id3v2Tag *tag, size_t *dataSize)
Extracts picture/artwork data of a specific type from an ID3v2 tag.
char * id3v2ReadTextFrameContent(const char id[ID3V2_FRAME_ID_MAX_SIZE], Id3v2Tag *tag)
Extracts the text content from a text frame with the specified ID.
int id3v2WriteTextFrameContent(const char id[ID3V2_FRAME_ID_MAX_SIZE], const char *string, Id3v2Tag *tag)
Writes UTF-8 text content to a text frame, creating it if necessary.
char * id3v2ReadComposer(Id3v2Tag *tag)
Extracts the composer from an ID3v2 tag.
int id3v2ReadTagVersion(const Id3v2Tag *tag)
Retrieves the major version number from an ID3v2 tag.
int id3v2WriteAlbumArtist(const char *albumArtist, Id3v2Tag *tag)
Writes the album artist/band/orchestra to an ID3v2 tag.
char * id3v2ReadArtist(Id3v2Tag *tag)
Extracts the lead artist/performer from an ID3v2 tag.
int id3v2InsertTextFrame(const char id[ID3V2_FRAME_ID_MAX_SIZE], const uint8_t encoding, const char *string, Id3v2Tag *tag)
Creates and inserts a new text frame with the specified encoding into a tag.
int id3v2WriteDisc(const char *disc, Id3v2Tag *tag)
Writes a disc number to the appropriate disc number frame in a tag.
char * id3v2ReadDisc(Id3v2Tag *tag)
Extracts the disc number/position from an ID3v2 tag.
int id3v2WriteComposer(const char *composer, Id3v2Tag *tag)
Writes a composer name to the appropriate composer frame in a tag.
Id3v2Tag * id3v2TagFromFile(const char *filename)
Reads and parses an ID3v2 tag from a file.
Id3v2Tag * id3v2CopyTag(const Id3v2Tag *toCopy)
Creates a deep copy of an ID3v2 tag structure.
Id3v2Frame * id3v2ReadFrameByID(const char id[ID3V2_FRAME_ID_MAX_SIZE], Id3v2Tag *tag)
Searches for and returns a copy of the first frame matching the given ID.
int id3v2WriteTitle(const char *title, Id3v2Tag *tag)
Writes the title/song name to an ID3v2 tag.
char * id3v2TagToJSON(Id3v2Tag *tag)
Serializes an ID3v2 tag structure to JSON format.
int id3v2WriteArtist(const char *artist, Id3v2Tag *tag)
Writes the lead artist/performer to an ID3v2 tag.
int id3v2WriteTrack(const char *track, Id3v2Tag *tag)
Writes the track number/position to an ID3v2 tag.
int id3v2WriteAlbum(const char *album, Id3v2Tag *tag)
Writes the album name to an ID3v2 tag.
int id3v2RemoveFrameByID(const char *id, Id3v2Tag *tag)
Locates and removes the first frame matching the given ID from a tag.
char * id3v2ReadLyrics(Id3v2Tag *tag)
Extracts unsynchronised lyrics/text transcription from an ID3v2 tag.
int id3v2WriteComment(const char *comment, Id3v2Tag *tag)
Writes a comment to the appropriate comment frame in a tag.
Declarations of ID3v2 tag operations including reading/writing metadata frames, tag serialization,...
Function definitions for ID3v2 frame context definitions and parsing configuration.
List * id3v2CreateCommentFrameContext(void)
Creates a context definition list for comment frames (COMM).
List * id3v2CreateTextFrameContext(void)
Context list generation.
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.
bool id3v2WriteFrameEntry(Id3v2Frame *frame, ListIter *entries, size_t entrySize, const void *entry)
Writes data to the entry at the iterator's current position, clamping size to context constraints.
uint8_t * id3v2FrameSerialize(Id3v2Frame *frame, uint8_t version, size_t *outl)
Serializes a complete ID3v2 frame to binary format according to the specified version.
void * id3v2CopyContentEntry(const void *toBeCopied)
Creates a deep copy of a content entry.
ListIter id3v2CreateFrameTraverser(Id3v2Tag *tag)
Creates a list iterator for traversing frames in an ID3v2 tag.
char * id3v2FrameToJSON(Id3v2Frame *frame, uint8_t version)
Converts a complete ID3v2 frame structure to its JSON representation.
void * id3v2ReadFrameEntry(ListIter *traverser, size_t *dataSize)
Reads and returns a deep copy of the current entry's data, advancing the iterator.
Id3v2Frame * id3v2CreateEmptyFrame(const char id[ID3V2_FRAME_ID_MAX_SIZE], uint8_t version, HashTable *userPairs)
Creates an empty frame structure with zero-initialized entries based on context lookup.
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.
char * id3v2ReadFrameEntryAsChar(ListIter *traverser, size_t *dataSize)
Reads a frame entry as a UTF-8 encoded string with escaped special characters, advancing the iterator...
Id3v2Frame * id3v2CreateFrame(Id3v2FrameHeader *header, List *context, List *entries)
Creates an ID3v2 frame structure from provided components.
ListIter id3v2CreateFrameEntryTraverser(Id3v2Frame *frame)
Creates a list iterator for traversing content entries within a frame.
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 id3v2DestroyFrame(Id3v2Frame **toDelete)
Frees all memory allocated for an ID3v2 frame structure and nullifies the pointer.
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.
Id3v2Frame * id3v2DetachFrameFromTag(Id3v2Tag *tag, Id3v2Frame *frame)
Removes a frame from a tag's frames list and returns it to the caller.
uint8_t id3v2ReadFrameEntryAsU8(ListIter *traverser)
Reads the first byte of the current entry as an 8-bit unsigned integer, advancing the iterator.
Id3v2Frame * id3v2FrameTraverse(ListIter *traverser)
Advances the iterator and returns the next frame in the list.
Definitions for binary parsing of ID3v2 tags, headers, frames, and complete tag structures from byte ...
Id3v2Tag * id3v2ParseTagFromBuffer(uint8_t *in, size_t inl, HashTable *userPairs)
Parses a complete ID3v2 tag from a byte buffer, including header, optional extended header,...
Function definitions of ID3v2 tag header and tag structure creation, manipulation,...
char * id3v2TagHeaderToJSON(const Id3v2TagHeader *header)
Converts an ID3v2 tag header structure to JSON string representation.
Id3v2Tag * id3v2CreateTag(Id3v2TagHeader *header, List *frames)
Creates and allocates an ID3v2 tag structure.
int id3v2ReadFooterIndicator(Id3v2TagHeader *header)
Reads the footer presence flag from an ID3v2.4 tag header.
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.
uint8_t * id3v2TagHeaderSerialize(Id3v2TagHeader *header, uint32_t uintSize, size_t *outl)
Serializes an ID3v2 tag header into a byte stream.
#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.
@ 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.
@ binary_context
Binary data block with no terminator.
struct _Id3v2Frame Id3v2Frame
Complete ID3v2 frame structure with header, parsing contexts, and data.
#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.
struct _Id3v2TagHeader Id3v2TagHeader
ID3v2 tag header containing version and parsing information.
Id3v2ContextType type
Context type determining parsing behavior (string, binary, numeric, etc.)
Id3v2FrameHeader * header
Frame header containing ID, flags, and processing parameters.
List * contexts
Linked list of Id3v2ContentContext parsing instructions defining frame field structure.
List * entries
Linked list of Id3v2ContentEntry parsed data fields corresponding to contexts.
List * frames
Linked list of Id3v2Frame structures containing all tag metadata.
Id3v2TagHeader * header
Tag header with version, flags, and optional extended header.