int mp_convert_to_v2(id3_tag *tag) { id3v1_tag *v1; id3_tag *tmp; id3_content* content; if(tag->version == 2) return 0; else if(tag->version == -1) return MP_EVERSION; tmp = mp_alloc_tag_with_version(2); v1 = (id3v1_tag*)tag->tag; content = mp_assemble_text_content(v1->artist, ISO_8859_1); if(v1->artist) mp_set_content(tmp, MP_ARTIST, content); content = mp_assemble_text_content(v1->title, ISO_8859_1); if(v1->title) mp_set_content(tmp, MP_TITLE, content); content = mp_assemble_text_content(v1->album, ISO_8859_1); if(v1->album) mp_set_content(tmp, MP_ALBUM, content); content = mp_assemble_text_content(v1->year, ISO_8859_1); if(v1->year) mp_set_content(tmp, MP_YEAR, content); content = mp_assemble_comment_content(v1->comment, NULL, ISO_8859_1, NULL); if(v1->comment) mp_set_content(tmp, MP_COMMENT, content); if(v1->genre != 0xFF) { char *c = xmallocd(strlen(genre_list[v1->genre]) + 1, "mp_convert_to_v2:c"); strcpy(c, genre_list[v1->genre]); content = mp_assemble_text_content(c, ISO_8859_1); mp_set_content(tmp, MP_GENRE, content); } if(v1->track > 0) { char *trk = (char *)xmallocd(4, "mp_convert_to_v2:trk"); snprintf(trk, 3, "%d", v1->track); trk[3] = 0; content = mp_assemble_text_content(trk, ISO_8859_1); mp_set_content(tmp, MP_TRACK, content); } tag->version = 2; tag->tag = tmp->tag; id3v1_free_tag(v1); xfree(tmp); return 0; }
static int id3v1_del_tag(int fd) { int nlength; unsigned char *c; struct stat fs; if(fstat(fd, &fs)) return 1; if(fs.st_size < 128) return 1; /* Hardly a valid mpeg file.. */ c = (char *)xmallocd(3, "id3v1_del_tag:c"); if(lseek(fd, -128L, SEEK_END) == -1) goto exit_on_error; if(read(fd, c, 3) < 3) goto exit_on_error; if(strncmp(c, "TAG", 3)) goto exit_on_error; xfree(c); nlength = fs.st_size - 128; if(ftruncate(fd, nlength)) return 1; return 0; exit_on_error: xfree(c); return 1; }
static int id3v2_del_tag(int fd, id3v2_tag *t) { unsigned char *c; long tag_len, file_len; FILE *file, *tmp; int read; void *ptr; id3v2_tag *tfound = NULL;; if(!t) { t = id3v2_get_tag(fd); if(!t) return 0; else tfound = t; } ptr = xmallocd(4096, "id3v2_del_tag:ptr"); tag_len = t->header->total_tag_size; file_len = lseek(fd, 0, SEEK_END); if(file_len < 1 || tag_len < 1) goto exit_on_error; /* use os system buffering */ file = fdopen(fd, "r+b"); tmp = tmpfile(); if(!(file && tmp)) goto exit_on_error; fseek(file, tag_len, SEEK_SET); fseek(tmp, 0, SEEK_SET); while(!feof(file)) { read = fread(ptr, 1, 4096, file); if(fwrite(ptr, 1, read, tmp) != read && !feof(file)) goto exit_on_error; } fflush(tmp); fseek(file, 0, SEEK_SET); fseek(tmp, 0, SEEK_SET); while(!feof(tmp)) { read = fread(ptr, 1, 4096, tmp); if(fwrite(ptr, 1, read, file) != read && !feof(tmp)) goto exit_on_error; } fclose(tmp); xfree(ptr); if(tfound) id3v2_free_tag(tfound); return 0; exit_on_error: fclose(tmp); xfree(ptr); if(tfound) id3v2_free_tag(tfound); return 1; }
int mp_set_custom_content_at_pos(id3_tag* tag, char* field, id3_content* new_content, int pos) { id3v2_tag *v2; if(!tag || !field || strlen(field) != 4) return MP_EERROR; if(tag->version == 1) { if(mp_convert_to_v2(tag)) return MP_EERROR; } else if(tag->version == -1) return MP_EVERSION; v2 = (id3v2_tag*)tag->tag; if(!v2->frame_list) { v2->frame_list = XMALLOCD0(id3v2_frame_list, "mp_set_custom_content_at_pos:v2->frame_list"); id3_add_frame(v2->frame_list, field, new_content->data, new_content->length); } else { id3v2_frame *frame; if((frame = id3_lookup_frame(v2->frame_list, field, pos))) { if(new_content) { long len, len_sync; /* make sync safe */ len = new_content->length; len_sync = id3_sync(new_content->data, len); xfree(frame->data); frame->data = xmallocd(new_content->length, "mp_set_custom_content_at_pos:frame->data"); memcpy(frame->data, new_content->data, new_content->length); frame->status_flag = 0; if(len != len_sync) frame->format_flag = 64; else frame->format_flag = 0; frame->data_size = len_sync; } else id3_remove_frame(v2->frame_list, frame); } else if(pos == 0) id3_add_frame(v2->frame_list, field, new_content->data, new_content->length); else return MP_EFNF; } return 0; }
static id3v1_tag* id3v1_get_tag(int fd) { id3v1_tag *tag; char *c; tag = XMALLOCD0(id3v1_tag, "id3v1_get_tag:tag"); c = (char *)xmallocd(3, "id3v1_get_tag:c"); if(lseek(fd, -128L, SEEK_END) == -1) goto exit_on_error; if(read(fd, c, 3) < 3) goto exit_on_error; if(strncmp(c, "TAG", 3) != 0) goto exit_on_error; tag->title = (char *)xmallocd(31, "id3v1_get_tag:tag->title"); if(read(fd, tag->title, 30) < 30) goto exit_on_error; if(tag->title[0] == 0 || id3_is_only_space(tag->title, 30)) { xfree(tag->title); tag->title = NULL; } else tag->title[30] = 0; tag->artist = (char*)xmallocd(31, "id3v1_get_tag:tag->artist"); if(read(fd, tag->artist, 30) < 30) goto exit_on_error; if(tag->artist[0] == 0 || id3_is_only_space(tag->artist, 30)) { xfree(tag->artist); tag->artist = NULL; } else tag->artist[30] = 0; tag->album = (char*)xmallocd(31, "id3v1_get_tag:tag->album"); if(read(fd, tag->album, 30) < 30) goto exit_on_error; if(tag->album[0] == 0 || id3_is_only_space(tag->album, 30)) { xfree(tag->album); tag->album = NULL; } else tag->album[30] = 0; tag->year = (char*)xmallocd(5, "id3v1_get_tag:tag->year"); if(read(fd, tag->year, 4) < 4) goto exit_on_error; if(tag->year[0] == 0 || id3_is_only_space(tag->year, 4)) { xfree(tag->year); tag->year = NULL; } else tag->year[4] = 0; tag->comment = (char*)xmallocd(31, "id3v1_get_tag:tag->comment"); if(read(fd, tag->comment, 30) < 30) goto exit_on_error; tag->comment[30] = 0; if(read(fd, &(tag->genre), 1) < 1) goto exit_on_error; /* Looking for v1.1 track info */ if(tag->comment && tag->comment[28] == 0 && tag->comment[29] != 0) { tag->track = tag->comment[29]; tag->comment[29] = 0; } else { tag->track = 0; } /* Set comment to NULL if not set - this happens at this point because */ /* there maybe a track info anyway */ if(tag->comment[0] == 0 || id3_is_only_space(tag->comment, 28)) { xfree(tag->comment); tag->comment = NULL; } xfree(c); return tag; exit_on_error: xfree(c); id3v1_free_tag(tag); return NULL; }
static int id3v2_add_tag(int fd, id3v2_tag *tag, id3v2_tag *old) { unsigned char *btag, *btag_start; unsigned char flag = 0; int i, j; char *b_tag, *b_tag_start, *d; id3v2_frame_list *frame_list; id3v2_frame *frame; /* at first we are going to write the tags raw data into the btag byte array */ btag = btag_start = xmallocd0(tag->header->total_tag_size, "id3v2_add_tag:btag"); strncpy(btag, "ID3", 3); btag += 3; *btag = (char)tag->header->version_minor; btag += 1; *btag = (char)tag->header->version_revision; btag += 1; flag |= ((tag->header->unsyncronization & 1) << 7); flag |= ((tag->header->has_extended_header & 1) << 6); flag |= ((tag->header->is_experimental & 1) << 5); flag |= ((tag->header->has_footer & 1) << 4); memcpy(btag, &flag, 1); btag += 1; if(old) { i = old->header->total_tag_size - 10; if(old->header->has_footer) i -= 10; } else { i = tag->header->total_tag_size - 10; if(tag->header->has_footer) i -= 10; /* add padding to total size we mean to store on disk */ /* mplib does not use any kind of padding internaly */ i += 1024; } d = id3_sync32(i); btag[0] = d[0]; btag[1] = d[1]; btag[2] = d[2]; btag[3] = d[3]; xfree(d); btag += 4; if(tag->header->has_extended_header) { d = id3_sync32(tag->header->extended_header->size); btag[0] = d[0]; btag[1] = d[1]; btag[2] = d[2]; btag[3] = d[3]; xfree(d); btag += 4; *btag = (char)tag->header->extended_header->no_flag_bytes; btag += 1; flag = ((tag->header->extended_header->is_update & 1) << 6); flag |= ((tag->header->extended_header->crc_data_present & 1) << 5); flag |= ((tag->header->extended_header->restrictions & 1) << 4); memcpy(btag, &flag, 1); btag += 1; if(tag->header->extended_header->is_update) { btag[0] = 0; btag += 1; } if(tag->header->extended_header->crc_data_present) { int length = tag->header->extended_header->crc_data_length ? tag->header->extended_header->crc_data_length : 5; *btag = (char)length; btag += 1; memcpy(btag, tag->header->extended_header->crc_data, length); btag += 1; } if(tag->header->extended_header->restrictions) { int length = tag->header->extended_header->restrictions_data_length ? tag->header->extended_header->restrictions_data_length : 5; *btag = (char)length; btag += 1; memcpy(btag, tag->header->extended_header->restrictions_data, length); btag += 1; } } frame_list = tag->frame_list; while(frame_list) { int j; frame = frame_list->data; strncpy(btag, frame->frame_id, 4); btag += 4; d = id3_sync32(frame->data_size); btag[0] = d[0]; btag[1] = d[1]; btag[2] = d[2]; btag[3] = d[3]; xfree(d); btag += 4; memcpy(btag, &frame->status_flag, 1); btag += 1; memcpy(btag, &frame->format_flag, 1); btag += 1; memcpy(btag, frame->data, frame->data_size); btag += frame->data_size; frame_list = frame_list->next; } /* XXX footer not supported yet */ /* if an old tag was provided it is desired to overwrite it */ /* else this is a brand new tag */ if(old) { FILE *file; void *ptr = xmallocd0(old->header->total_tag_size - tag->header->total_tag_size, "id3v2_add_tag:ptr"); if(!(file = fdopen(fd, "r+b"))) { xfree(ptr); goto exit_on_error; } fseek(file, 0, SEEK_SET); if(fwrite(btag_start, tag->header->total_tag_size, 1, file) < 1) { xfree(ptr); goto exit_on_error; } /* write padding till end of old tag */ if(fwrite(ptr, old->header->total_tag_size - tag->header->total_tag_size, 1, file) < 1) { xfree(ptr); goto exit_on_error; } fflush(file); xfree(ptr); } else { FILE *file, *tmp; int read; void *ptr, *blank; unsigned char *c; ptr = xmallocd(4096, "id3v2_add_tag:ptr"); blank = xmallocd0(1024, "id3v2_add_tag:blank"); file = fdopen(fd, "r+b"); tmp = tmpfile(); if(!(file && tmp)) { fflush(file); fclose(tmp); xfree(ptr); xfree(blank); goto exit_on_error; } fseek(file, 0, SEEK_SET); fseek(tmp, 0, SEEK_SET); /* write tag in tmp file */ fwrite(btag_start, tag->header->total_tag_size, 1, tmp); /* Write 1024b padding */ fwrite(blank, 1024, 1, tmp); /* write rest of file */ while(!feof(file)) { read = fread(ptr, 1, 4096, file); if(fwrite(ptr, 1, read, tmp) != read && !feof(file)) { fflush(file); fclose(tmp); xfree(ptr); xfree(blank); goto exit_on_error; } } fflush(tmp); fseek(file, 0, SEEK_SET); fseek(tmp, 0, SEEK_SET); while(!feof(tmp)) { read = fread(ptr, 1, 4096, tmp); if(fwrite(ptr, 1, read, file) != read && !feof(tmp)) { fflush(file); fclose(tmp); xfree(ptr); xfree(blank); goto exit_on_error; } } fflush(file); fclose(tmp); xfree(ptr); xfree(blank); } xfree(btag_start); return 0; exit_on_error: xfree(btag_start); return MP_EERROR; }
static int id3v1_add_tag(int fd, id3v1_tag *tag) { int i, j; void *blank, *set; char *b_tag, *b_tag_start; blank = xmallocd0(30, "id3v1_add_tag:blank"); set = xmallocd(30, "id3v1_add_tag:set"); memset(set, 0xFF, 30); b_tag = b_tag_start = (char *)xmallocd0(128, "id3v1_add_tag:b_tag"); strncpy(b_tag, "TAG", 3); b_tag += 3; if(tag->title) { j = strlen(tag->title); strncpy(b_tag, tag->title, j); b_tag += j; i = 30 - j; if(i > 0) { strncpy(b_tag, blank, i); b_tag += i; } } else { strncpy(b_tag, blank, 30); b_tag += 30; } if(tag->artist) { j = strlen(tag->artist); strncpy(b_tag, tag->artist, j); b_tag += j; i = 30 - j; if(i > 0) { strncpy(b_tag, blank, i); b_tag += i; } } else { strncpy(b_tag, blank, 30); b_tag += 30; } if(tag->album) { j = strlen(tag->album); strncpy(b_tag, tag->album, j); b_tag += j; i = 30 - j; if(i > 0) { strncpy(b_tag, blank, i); b_tag += i; } } else { strncpy(b_tag, blank, 30); b_tag += 30; } if(tag->year) { j = strlen(tag->year); strncpy(b_tag, tag->year, j); b_tag += j; i = 4 - j; if(i > 0) { strncpy(b_tag, blank, i); b_tag += i; } } else { strncpy(b_tag, blank, 4); b_tag += 4; } if(tag->comment) { int hastrack = 0; j = strlen(tag->comment); if(tag->track > 0) hastrack = 1; if(hastrack && j > 28) { strncpy(b_tag, tag->comment, 28); b_tag += 28; } else { strncpy(b_tag, tag->comment, j); b_tag += j; i = ((tag->track > 0) ? 28 : 30) - j; } if(i > 0) { strncpy(b_tag, blank, i); b_tag += i; } } else { strncpy(b_tag, blank, (tag->track > 0) ? 28 : 30); b_tag += (tag->track > 0) ? 28 : 30; } if(tag->track > 0) { strncpy(b_tag, blank, 1); b_tag += 1; strncpy(b_tag, &(tag->track), 1); b_tag += 1; } if(tag->genre != 0xFF) { strncpy(b_tag, &(tag->genre), 1); b_tag += 1; } else { strncpy(b_tag, set, 1); b_tag += 1; } j = 0; if(lseek(fd, 0L, SEEK_END) != -1) { if(write(fd, b_tag - 128, 128) < 128) j = 1; } else j = 1; xfree(b_tag_start); xfree(blank); xfree(set); return j; }
/* This function is recursivly scaning a directory and all file in it for a match */ void desc_dir(char *dir, unsigned int parent_depth) { DIR *dir_struct = NULL; struct dirent *entry; #ifdef DEBUG assert(dir && parent_depth >= 0); #endif /* Check max depth */ if(MAXDEPTH > 0 && parent_depth > MAXDEPTH) { #ifdef DEBUG printf("DEBUG: Max depth prevents mpfind descending into level %d (trying to scan %s)\n", parent_depth, dir); #endif return; } ++parent_depth; /* Change dir */ if(chdir(dir) == -1) { #ifdef DEBUG puts("DEBUG: Could not change directory"); #endif perror(dir); return; } dir_struct = opendir(dir); if(!dir_struct) perror(dir); /* Looping through every dir-entry and examine file or descend down further */ while(1) { struct stat stats; entry = readdir(dir_struct); if(!entry) { #ifdef DEBUG puts("DEBUG: EOF"); #endif /* perror(dir);*/ break; } /* skipping . and .. */ if(strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { continue; } #ifdef DEBUG printf("DEBUG: Checking dir entry %s\n", entry->d_name); #endif /* Get stats for entry */ if(stat(entry->d_name, &stats) == -1) { char *fullfilename = xmallocd(NAME_MAX + 1, "ignore"); #ifdef DEBUG printf("DEBUG: Could not get stats for %s\n", entry->d_name); #endif if(dir[strlen(dir)-1] == '/') snprintf(fullfilename, NAME_MAX, "%s%s", dir, entry->d_name); else snprintf(fullfilename, NAME_MAX, "%s/%s", dir, entry->d_name); perror(fullfilename); xfree(fullfilename); continue; } /* init inode list if necessary and check if inode was allready scanned */ if(!first_elem) { /* First run, eh? */ #ifdef DEBUG puts("DEBUG: Setting up list of scanned inodes"); #endif last_elem = xmallocd(sizeof(proc_list), "ignore"); last_elem->inode = stats.st_ino; last_elem->next = NULL; first_elem = last_elem; } else { proc_list *ptr; int skip = 0; #ifdef DEBUG assert(last_elem && first_elem); #endif ptr = first_elem; while(ptr) { if(stats.st_ino == ptr->inode) { #ifdef DEBUG puts("DEBUG: Inode allready scanned, skipping"); #endif skip = 1; break; } ptr = (proc_list*)ptr->next; } if(skip) continue; /* Add this inode to the end of the list */ last_elem->next = xmallocd(sizeof(proc_list), "ignore"); last_elem = (proc_list*)last_elem->next; last_elem->inode = stats.st_ino; last_elem->next = NULL; } if(access(entry->d_name, F_OK | R_OK) == -1) { char *fullfilename = xmallocd(NAME_MAX + 1, "ignore"); if(dir[strlen(dir)-1] == '/') snprintf(fullfilename, NAME_MAX, "%s%s", dir, entry->d_name); else snprintf(fullfilename, NAME_MAX, "%s/%s", dir, entry->d_name); perror(fullfilename); continue; } #ifdef DEBUG printf("DEBUG: Scanning inode %d\n", stats.st_ino); #endif /* Checking stats and decide what to do */ stats.st_mode &= S_IFMT; if((stats.st_mode & S_IFLNK) == S_IFLNK) { #ifdef DEBUG puts("DEBUG: inode is symbolic link, going to ignore for now.."); #endif continue; } if((stats.st_mode & S_IFREG) == S_IFREG) { #ifdef DEBUG puts("DEBUG: inode is a regular file."); #endif if(stats.st_size > 128) { do_expr(dir, entry->d_name); } #ifdef DEBUG else { puts("DEBUG: File has invalid size to have a tag"); } #endif } else if((stats.st_mode & S_IFDIR) == S_IFDIR) { char *todesc; #ifdef DEBUG puts("DEBUG: inode is a directory"); #endif if(access(entry->d_name, R_OK | X_OK) == -1) { perror(entry->d_name); } else { todesc = xmallocd(NAME_MAX + 1, "ignore"); memset(todesc, 0, NAME_MAX+1); if(dir[strlen(dir)-1] == '/') snprintf(todesc, NAME_MAX+1, "%s%s", dir, entry->d_name); else snprintf(todesc, NAME_MAX+1, "%s/%s", dir, entry->d_name); desc_dir(todesc, parent_depth) ; /* Change back to our dir */ if(chdir(dir) == -1) { #ifdef DEBUG puts("DEBUG: Could not change directory"); #endif perror(dir); return; } } } } closedir(dir_struct); }