id3dev 26.01
An ID3 metadata library
Loading...
Searching...
No Matches
id3v1Parser.c
Go to the documentation of this file.
1
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include "id3v1/id3v1Types.h"
15#include "id3v1/id3v1Parser.h"
16#include "id3dependencies/ByteStream/include/byteStream.h"
17#include "id3dependencies/ByteStream/include/byteInt.h"
18
25bool id3v1HasTag(const uint8_t *buffer) {
26 return (memcmp(buffer, "TAG",ID3V1_TAG_ID_SIZE) == 0) ? true : false;
27}
28
41Id3v1Tag *id3v1CreateTag(uint8_t *title, uint8_t *artist, uint8_t *albumTitle, int year, int track, uint8_t *comment,
42 Genre genre) {
43 Id3v1Tag *tag = malloc(sizeof(Id3v1Tag));
44
45 //inits all members
46 memset(tag, 0, sizeof(Id3v1Tag));
47
48 //set values
49 if (title != NULL) {
50 memcpy(tag->title, title,
51 ((strlen((char *) title) >= ID3V1_FIELD_SIZE) ? ID3V1_FIELD_SIZE : strlen((char *) title)));
52 }
53
54 if (artist != NULL) {
55 memcpy(tag->artist, artist,
56 ((strlen((char *) artist) >= ID3V1_FIELD_SIZE) ? ID3V1_FIELD_SIZE : strlen((char *) artist)));
57 }
58
59 if (albumTitle != NULL) {
60 memcpy(tag->albumTitle, albumTitle, ((strlen((char *) albumTitle) >= ID3V1_FIELD_SIZE)
62 : strlen((char *) albumTitle)));
63 }
64
65 if (comment != NULL) {
66 memcpy(tag->comment, comment,
67 ((strlen((char *) comment) >= ID3V1_FIELD_SIZE) ? ID3V1_FIELD_SIZE : strlen((char *) comment)));
68 }
69
70 tag->year = year;
71 tag->track = track;
72 tag->genre = genre;
73
74 return tag;
75}
76
83 if (tag == NULL) {
84 return;
85 }
86
87 memset(tag->albumTitle, 0, ID3V1_FIELD_SIZE);
88 memset(tag->artist, 0, ID3V1_FIELD_SIZE);
89 memset(tag->comment, 0, ID3V1_FIELD_SIZE);
90 memset(tag->title, 0, ID3V1_FIELD_SIZE);
91
92 tag->genre = OTHER_GENRE;
93 tag->track = 0;
94 tag->year = 0;
95}
96
102void id3v1DestroyTag(Id3v1Tag **toDelete) {
103 //error address free
104 if (*toDelete) {
105 free(*toDelete);
106 *toDelete = NULL;
107 toDelete = NULL;
108 }
109}
110
119Id3v1Tag *id3v1TagFromBuffer(uint8_t *buffer) {
120 //lots of error checking because I cannot 100% know what im given
121
122 int trackno = 0;
123 int nYear = 0;
124 uint8_t holdTitle[ID3V1_FIELD_SIZE + 1] = {0};
125 uint8_t holdArtist[ID3V1_FIELD_SIZE + 1] = {0};
126 uint8_t holdAlbum[ID3V1_FIELD_SIZE + 1] = {0};
127 uint8_t holdComment[ID3V1_FIELD_SIZE + 1] = {0};
128 uint8_t year[ID3V1_YEAR_SIZE + 1]; //must be +1. without it holdTitle gets overwritten somehow
129 Genre genre = OTHER_GENRE;
130 ByteStream *stream = NULL;
131
132 stream = byteStreamCreate((unsigned char *) buffer, ID3V1_MAX_SIZE);
133
134 //check for tag
135 if (!id3v1HasTag(byteStreamCursor(stream))) {
136 byteStreamDestroy(stream);
137 return NULL;
138 }
139
140 if (!byteStreamSeek(stream, ID3V1_TAG_ID_SIZE, SEEK_SET)) {
141 byteStreamDestroy(stream);
142 return id3v1CreateTag(NULL, NULL, NULL, 0, 0, NULL, OTHER_GENRE);
143 }
144 //get song title and set index for next tag
145 memset(holdTitle, 0, ID3V1_FIELD_SIZE);
146 if (!byteStreamRead(stream, holdTitle, ID3V1_FIELD_SIZE)) {
147 byteStreamDestroy(stream);
148 return id3v1CreateTag(NULL, NULL, NULL, 0, 0, NULL, OTHER_GENRE);
149 }
150
151 //get artist and set index for next tag
152 memset(holdArtist, 0, ID3V1_FIELD_SIZE);
153 if (!byteStreamRead(stream, holdArtist, ID3V1_FIELD_SIZE)) {
154 byteStreamDestroy(stream);
155 return id3v1CreateTag(holdTitle, NULL, NULL, 0, 0, NULL, OTHER_GENRE);
156 }
157 //get album title and set index for next tag
158 memset(holdAlbum, 0, ID3V1_FIELD_SIZE);
159 if (!byteStreamRead(stream, holdAlbum, ID3V1_FIELD_SIZE)) {
160 byteStreamDestroy(stream);
161 return id3v1CreateTag(holdTitle, holdArtist, NULL, 0, 0, NULL, OTHER_GENRE);
162 }
163 //get year and set index for next tag
164 memset(year, 0, ID3V1_YEAR_SIZE);
165 if (!byteStreamRead(stream, year, ID3V1_YEAR_SIZE)) {
166 byteStreamDestroy(stream);
167 return id3v1CreateTag(holdTitle, holdArtist, holdAlbum, 0, 0, NULL, OTHER_GENRE);
168 } else {
169 if (memcmp(year, "\x00\x00\x00\x00\x00",ID3V1_YEAR_SIZE) != 0) {
170 int i = 0;
171 for (i = 0; year[i] == 0 && i < ID3V1_YEAR_SIZE; i++) {
172 }
173 year[ID3V1_YEAR_SIZE] = '\0';
174 nYear = (int) strtol((char *) (year + i), NULL, 10);
175 }
176 }
177
178 //check for a track number, ID3V1.1 has the 28th bit nulled so that the 29th can be a track number
179 if (!byteStreamSeek(stream, ID3V1_FIELD_SIZE - 2, SEEK_CUR)) {
180 byteStreamDestroy(stream);
181 return id3v1CreateTag(holdTitle, holdArtist, holdAlbum, nYear, 0, NULL, OTHER_GENRE);
182 }
183 if (!byteStreamCursor(stream)[0] && byteStreamCursor(stream)[1]) {
184 trackno = 1;
185 }
186
187 //no need to check bytes are confirmed to exist
188 byteStreamSeek(stream, -(ID3V1_FIELD_SIZE - 2), SEEK_CUR);
189
190 //get comment and set index for next tag
191 memset(holdComment, 0, ID3V1_FIELD_SIZE);
192 if (!byteStreamRead(stream, holdComment, ID3V1_FIELD_SIZE - trackno)) {
193 byteStreamDestroy(stream);
194 return id3v1CreateTag(holdTitle, holdArtist, holdAlbum, nYear, 0, NULL, 0);
195 }
196
197
198 //read and set track number + move index
199 if (trackno) {
200 trackno = byteStreamGetCh(stream);
201 if (trackno == EOF) {
202 byteStreamDestroy(stream);
203 return id3v1CreateTag(holdTitle, holdArtist, holdAlbum, nYear, 0, holdAlbum, 0);
204 }
205
206 if (!byteStreamSeek(stream, 1, SEEK_CUR)) {
207 byteStreamDestroy(stream);
208 return id3v1CreateTag(holdTitle, holdArtist, holdAlbum, nYear, trackno, holdComment, 0);
209 }
210 } else {
211 trackno = 0;
212 }
213
214 //read genre or last byte
215 genre = byteStreamGetCh(stream);
216 if (genre == EOF) {
217 byteStreamDestroy(stream);
218 return id3v1CreateTag(holdTitle, holdArtist, holdAlbum, nYear, trackno, holdComment, 0);
219 }
220
221 byteStreamDestroy(stream);
222 return id3v1CreateTag(holdTitle, holdArtist, holdAlbum, nYear, trackno, holdComment, genre);
223}
void id3v1DestroyTag(Id3v1Tag **toDelete)
Frees an Id3v1Tag and nullifies the pointer.
void id3v1ClearTag(Id3v1Tag *tag)
Resets all tag fields to their default empty state.
Definition id3v1Parser.c:82
Id3v1Tag * id3v1TagFromBuffer(uint8_t *buffer)
Parses an ID3V1_MAX_SIZE buffer into an Id3v1Tag structure.
bool id3v1HasTag(const uint8_t *buffer)
Checks if a buffer contains a valid ID3v1 tag identifier.
Definition id3v1Parser.c:25
Id3v1Tag * id3v1CreateTag(uint8_t *title, uint8_t *artist, uint8_t *albumTitle, int year, int track, uint8_t *comment, Genre genre)
Creates and allocates a new Id3v1Tag structure.
Definition id3v1Parser.c:41
Definitions for ID3v1 tag structure, constants, and genre enumeration.
#define ID3V1_YEAR_SIZE
Size in bytes of the year field in ID3v1 tags (4 bytes)
Definition id3v1Types.h:25
#define ID3V1_MAX_SIZE
Total size in bytes of a complete ID3v1/ID3v1.1 tag on disk (128 bytes)
Definition id3v1Types.h:31
#define ID3V1_FIELD_SIZE
Size in bytes of text fields (title, artist, album, comment) in ID3v1 tags (30 bytes)
Definition id3v1Types.h:28
@ OTHER_GENRE
Other Music Genres not Defined.
Definition id3v1Types.h:68
#define ID3V1_TAG_ID_SIZE
Size in bytes of the ID3v1 tag identifier "TAG" (3 bytes)
Definition id3v1Types.h:22
enum _Genre Genre
ID3v1 genre enumeration with Winamp extensions (genres 0-191).
struct _Id3v1Tag Id3v1Tag
ID3v1/ID3v1.1 tag structure containing all metadata fields.
int track
Track number (0 if not present, ID3v1.1 only)
Definition id3v1Types.h:451
Genre genre
Genre value (0-191, maps to Genre enum)
Definition id3v1Types.h:457
uint8_t artist[ID3V1_FIELD_SIZE]
Artist name (ID3V1_FIELD_SIZE bytes, null-padded)
Definition id3v1Types.h:442
uint8_t comment[ID3V1_FIELD_SIZE]
Comment text (ID3V1_FIELD_SIZE bytes, null-padded; ID3V1_FIELD_SIZE - 2 bytes if track number present...
Definition id3v1Types.h:454
uint8_t title[ID3V1_FIELD_SIZE]
Song title (ID3V1_FIELD_SIZE bytes, null-padded)
Definition id3v1Types.h:439
int year
Release year (4-digit integer)
Definition id3v1Types.h:448
uint8_t albumTitle[ID3V1_FIELD_SIZE]
Album title (ID3V1_FIELD_SIZE bytes, null-padded)
Definition id3v1Types.h:445