/* PSID metadata info is available here: http://www.unusedino.de/ec64/technical/formats/sidplay.html */ bool get_sid_metadata(int fd, struct mp3entry* id3) { /* Use the trackname part of the id3 structure as a temporary buffer */ unsigned char* buf = (unsigned char *)id3->path; int read_bytes; char *p; if ((lseek(fd, 0, SEEK_SET) < 0) || ((read_bytes = read(fd, buf, 0x80)) < 0x80)) { return false; } if ((memcmp(buf, "PSID", 4) != 0)) { return false; } p = id3->id3v2buf; /* Copy Title (assumed max 0x1f letters + 1 zero byte) */ id3->title = p; buf[0x16+0x1f] = 0; p = iso_decode(&buf[0x16], p, 0, strlen(&buf[0x16])+1); /* Copy Artist (assumed max 0x1f letters + 1 zero byte) */ id3->artist = p; buf[0x36+0x1f] = 0; p = iso_decode(&buf[0x36], p, 0, strlen(&buf[0x36])+1); /* Copy Year (assumed max 4 letters + 1 zero byte) */ buf[0x56+0x4] = 0; id3->year = atoi(&buf[0x56]); /* Copy Album (assumed max 0x1f-0x05 letters + 1 zero byte) */ id3->album = p; buf[0x56+0x1f] = 0; p = iso_decode(&buf[0x5b], p, 0, strlen(&buf[0x5b])+1); id3->bitrate = 706; id3->frequency = 44100; /* New idea as posted by Marco Alanen (ravon): * Set the songlength in seconds to the number of subsongs * so every second represents a subsong. * Users can then skip the current subsong by seeking * * Note: the number of songs is a 16bit value at 0xE, so this code only * uses the lower 8 bits of the counter. */ id3->length = (buf[0xf]-1)*1000; id3->vbr = false; id3->filesize = filesize(fd); return true; }
static void decode2utf8(const unsigned char *src, unsigned char **dst, int srcsize, int *dstsize, int codepage) { unsigned char tmpbuf[srcsize * 3 + 1]; unsigned char *p; int utf8size; if (codepage < NUM_CODEPAGES) p = iso_decode(src, tmpbuf, codepage, srcsize); else /* codepage == UCS2 */ p = utf16BEdecode(src, tmpbuf, srcsize); *p = '\0'; strlcpy(*dst, tmpbuf, *dstsize); utf8size = (p - tmpbuf) + 1; if (utf8size > *dstsize) { DEBUGF("metadata warning: data length: %d > contents store buffer size: %d\n", utf8size, *dstsize); utf8size = *dstsize; } *dst += utf8size; *dstsize -= utf8size; }
static int iso_skip_frame (codec_data_t *iso) { #if 0 return (iso_decode(iso, ts, 0, NULL, buffer, buflen)); #else return 0; #endif }
bool get_spc_metadata(int fd, struct mp3entry* id3) { /* Use the trackname part of the id3 structure as a temporary buffer */ unsigned char * buf = (unsigned char *)id3->path; char * p; unsigned long length; unsigned long fade; bool isbinary = true; int i; /* try to get the ID666 tag */ if ((lseek(fd, 0x2e, SEEK_SET) < 0) || (read(fd, buf, 0xD2) < 0xD2)) { DEBUGF("lseek or read failed\n"); return false; } p = id3->id3v2buf; id3->title = p; buf[31] = 0; p = iso_decode(buf, p, 0, 32); buf += 32; id3->album = p; buf[31] = 0; p = iso_decode(buf, p, 0, 32); buf += 48; id3->comment = p; buf[31] = 0; p = iso_decode(buf, p, 0, 32); buf += 32; /* Date check */ if(buf[2] == '/' && buf[5] == '/') isbinary = false; /* Reserved bytes check */ if(buf[0xD2 - 0x2E - 112] >= '0' && buf[0xD2 - 0x2E - 112] <= '9' && buf[0xD3 - 0x2E - 112] == 0x00) isbinary = false; /* is length & fade only digits? */ for (i=0;i<8 && ( (buf[0xA9 - 0x2E - 112+i]>='0'&&buf[0xA9 - 0x2E - 112+i]<='9') || buf[0xA9 - 0x2E - 112+i]=='\0'); i++); if (i==8) isbinary = false; if(isbinary) { id3->year = buf[0] | (buf[1]<<8); buf += 11; length = (buf[0] | (buf[1]<<8) | (buf[2]<<16)) * 1000; buf += 3; fade = (buf[0] | (buf[1]<<8) | (buf[2]<<16) | (buf[3]<<24)); buf += 4; } else { char tbuf[6]; buf += 6; buf[4] = 0; id3->year = atoi(buf); buf += 5; memcpy(tbuf, buf, 3); tbuf[3] = 0; length = atoi(tbuf) * 1000; buf += 3; memcpy(tbuf, buf, 5); tbuf[5] = 0; fade = atoi(tbuf); buf += 5; } id3->artist = p; buf[31] = 0; iso_decode(buf, p, 0, 32); if (length==0) { length=3*60*1000; /* 3 minutes */ fade=5*1000; /* 5 seconds */ } id3->length = length+fade; id3->filesize = filesize(fd); id3->genre_string = id3_get_num_genre(36); return true; }
/* parse cuesheet "file" and store the information in "cue" */ bool parse_cuesheet(char *file, struct cuesheet *cue) { char line[MAX_PATH]; char *s; bool utf8 = false; int fd = open_utf8(file,O_RDONLY); if (fd < 0) { /* couln't open the file */ return false; } if(lseek(fd, 0, SEEK_CUR) > 0) utf8 = true; /* Initialization */ memset(cue, 0, sizeof(struct cuesheet)); strcpy(cue->path, file); cue->curr_track = cue->tracks; while ( read_line(fd,line,MAX_PATH) && cue->track_count < MAX_TRACKS ) { s = skip_whitespace(line); if (!strncmp(s, "TRACK", 5)) { cue->track_count++; } else if (!strncmp(s, "INDEX 01", 8)) { s = strchr(s,' '); s = skip_whitespace(s); s = strchr(s,' '); s = skip_whitespace(s); cue->tracks[cue->track_count-1].offset = 60*1000 * atoi(s); s = strchr(s,':') + 1; cue->tracks[cue->track_count-1].offset += 1000 * atoi(s); s = strchr(s,':') + 1; cue->tracks[cue->track_count-1].offset += 13 * atoi(s); } else if (!strncmp(s, "TITLE", 5) || !strncmp(s, "PERFORMER", 9) || !strncmp(s, "SONGWRITER", 10)) { char *dest = NULL; char *string = get_string(s); if (!string) break; switch (*s) { case 'T': /* TITLE */ dest = (cue->track_count <= 0) ? cue->title : cue->tracks[cue->track_count-1].title; break; case 'P': /* PERFORMER */ dest = (cue->track_count <= 0) ? cue->performer : cue->tracks[cue->track_count-1].performer; break; case 'S': /* SONGWRITER */ dest = (cue->track_count <= 0) ? cue->songwriter : cue->tracks[cue->track_count-1].songwriter; break; } if (dest) { if (!utf8) { dest = iso_decode(string, dest, -1, MIN(strlen(string), MAX_NAME)); *dest = '\0'; } else { strlcpy(dest, string, MAX_NAME*3 + 1); } } } } close(fd); /* If some songs don't have performer info, we copy the cuesheet performer */ int i; for (i = 0; i < cue->track_count; i++) { if (*(cue->tracks[i].performer) == '\0') strlcpy(cue->tracks[i].performer, cue->performer, MAX_NAME*3); if (*(cue->tracks[i].songwriter) == '\0') strlcpy(cue->tracks[i].songwriter, cue->songwriter, MAX_NAME*3); } return true; }
int main(int argc, char **argv) { int mini = 0; int i, j; unsigned char k; unsigned short uni; FILE *of; for (i = 1;i < argc;i++) { if (argv[i][0] == '-') { switch (argv[i][1]) { case 'm': /* create isomini.cp only */ mini = 1; break; case 'h': /* help */ case '?': print_usage(); exit(1); break; default: print_usage(); exit(1); break; } } } for (i=0; i < MAX_TABLE_SIZE; i++) iso_table[i] = 0; if (mini) { of = fopen("isomini.cp", "wb"); if (!of) return 1; for (i=1; i<6; i++) { for (j=0; j<128; j++) { k = (unsigned char)j + 128; uni = iso_decode(&k, mini_index[i], 1); writeshort(of, uni); } } fclose(of); } else { of = fopen("iso.cp", "wb"); if (!of) return 1; for (i=1; i<9; i++) { for (j=0; j<128; j++) { k = (unsigned char)j + 128; uni = iso_decode(&k, i, 1); writeshort(of, uni); } } fclose(of); of = fopen("932.cp", "wb"); if (!of) return 1; for (i=0; i < MAX_TABLE_SIZE; i++) writeshort(of, cp932_table[i]); fclose(of); of = fopen("936.cp", "wb"); if (!of) return 1; for (i=0; i < MAX_TABLE_SIZE; i++) writeshort(of, cp936_table[i]); fclose(of); of = fopen("949.cp", "wb"); if (!of) return 1; for (i=0; i < MAX_TABLE_SIZE; i++) writeshort(of, cp949_table[i]); fclose(of); of = fopen("950.cp", "wb"); if (!of) return 1; for (i=0; i < MAX_TABLE_SIZE; i++) writeshort(of, cp950_table[i]); fclose(of); } return 0; }
/* parse cuesheet "cue_file" and store the information in "cue" */ bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue) { char line[MAX_PATH]; char *s; unsigned char char_enc = CHAR_ENC_ISO_8859_1; bool is_embedded = false; int line_len; int bytes_left = 0; int read_bytes = MAX_PATH; unsigned char utf16_buf[MAX_PATH]; int fd = open(cue_file->path, O_RDONLY, 0644); if(fd < 0) return false; if (cue_file->pos > 0) { is_embedded = true; lseek(fd, cue_file->pos, SEEK_SET); bytes_left = cue_file->size; char_enc = cue_file->encoding; } /* Look for a Unicode BOM */ unsigned char bom_read = 0; read(fd, line, BOM_UTF_8_SIZE); if(!memcmp(line, BOM_UTF_8, BOM_UTF_8_SIZE)) { char_enc = CHAR_ENC_UTF_8; bom_read = BOM_UTF_8_SIZE; } else if(!memcmp(line, BOM_UTF_16_LE, BOM_UTF_16_SIZE)) { char_enc = CHAR_ENC_UTF_16_LE; bom_read = BOM_UTF_16_SIZE; } else if(!memcmp(line, BOM_UTF_16_BE, BOM_UTF_16_SIZE)) { char_enc = CHAR_ENC_UTF_16_BE; bom_read = BOM_UTF_16_SIZE; } if (bom_read < BOM_UTF_8_SIZE) lseek(fd, cue_file->pos + bom_read, SEEK_SET); if (is_embedded) { if (bom_read > 0) bytes_left -= bom_read; if (read_bytes > bytes_left) read_bytes = bytes_left; } /* Initialization */ memset(cue, 0, sizeof(struct cuesheet)); strcpy(cue->path, cue_file->path); cue->curr_track = cue->tracks; while ((line_len = read_line(fd, line, read_bytes)) > 0 && cue->track_count < MAX_TRACKS ) { if (char_enc == CHAR_ENC_UTF_16_LE) { s = utf16LEdecode(line, utf16_buf, line_len); /* terminate the string at the newline */ *s = '\0'; strcpy(line, utf16_buf); /* chomp the trailing 0 after the newline */ lseek(fd, 1, SEEK_CUR); line_len++; } else if (char_enc == CHAR_ENC_UTF_16_BE) { s = utf16BEdecode(line, utf16_buf, line_len); *s = '\0'; strcpy(line, utf16_buf); } s = skip_whitespace(line); if (!strncmp(s, "TRACK", 5)) { cue->track_count++; } else if (!strncmp(s, "INDEX 01", 8)) { s = strchr(s,' '); s = skip_whitespace(s); s = strchr(s,' '); s = skip_whitespace(s); cue->tracks[cue->track_count-1].offset = 60*1000 * atoi(s); s = strchr(s,':') + 1; cue->tracks[cue->track_count-1].offset += 1000 * atoi(s); s = strchr(s,':') + 1; cue->tracks[cue->track_count-1].offset += 13 * atoi(s); } else if (!strncmp(s, "TITLE", 5) || !strncmp(s, "PERFORMER", 9) || !strncmp(s, "SONGWRITER", 10)) { char *dest = NULL; char *string = get_string(s); if (!string) break; switch (*s) { case 'T': /* TITLE */ dest = (cue->track_count <= 0) ? cue->title : cue->tracks[cue->track_count-1].title; break; case 'P': /* PERFORMER */ dest = (cue->track_count <= 0) ? cue->performer : cue->tracks[cue->track_count-1].performer; break; case 'S': /* SONGWRITER */ dest = (cue->track_count <= 0) ? cue->songwriter : cue->tracks[cue->track_count-1].songwriter; break; } if (dest) { if (char_enc == CHAR_ENC_ISO_8859_1) { dest = iso_decode(string, dest, -1, MIN(strlen(string), MAX_NAME)); *dest = '\0'; } else { strlcpy(dest, string, MAX_NAME*3 + 1); } } } if (is_embedded) { bytes_left -= line_len; if (bytes_left <= 0) break; if (bytes_left < read_bytes) read_bytes = bytes_left; } } close(fd); /* If some songs don't have performer info, we copy the cuesheet performer */ int i; for (i = 0; i < cue->track_count; i++) { if (*(cue->tracks[i].performer) == '\0') strlcpy(cue->tracks[i].performer, cue->performer, MAX_NAME*3); if (*(cue->tracks[i].songwriter) == '\0') strlcpy(cue->tracks[i].songwriter, cue->songwriter, MAX_NAME*3); } return true; }