1 /* metaflac - Command-line FLAC metadata editor
2 * Copyright (C) 2001,2002,2003 Josh Coalson
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 #include "FLAC/assert.h"
21 #include "share/utf8.h"
27 void die(const char *message)
29 FLAC__ASSERT(0 != message);
30 fprintf(stderr, "ERROR: %s\n", message);
34 #ifdef FLAC__VALGRIND_TESTING
35 size_t local_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
37 size_t ret = fwrite(ptr, size, nmemb, stream);
44 char *local_strdup(const char *source)
47 FLAC__ASSERT(0 != source);
48 if(0 == (ret = strdup(source)))
49 die("out of memory during strdup()");
53 void local_strcat(char **dest, const char *source)
55 unsigned ndest, nsource;
57 FLAC__ASSERT(0 != dest);
58 FLAC__ASSERT(0 != source);
60 ndest = *dest? strlen(*dest) : 0;
61 nsource = strlen(source);
66 *dest = realloc(*dest, ndest + nsource + 1);
68 die("out of memory growing string");
69 strcpy((*dest)+ndest, source);
72 void hexdump(const char *filename, const FLAC__byte *buf, unsigned bytes, const char *indent)
74 unsigned i, left = bytes;
75 const FLAC__byte *b = buf;
77 for(i = 0; i < bytes; i += 16) {
79 "%02X %02X %02X %02X %02X %02X %02X %02X "
80 "%02X %02X %02X %02X %02X %02X %02X %02X "
81 "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
82 filename? filename:"", filename? ":":"",
84 left > 0? (unsigned char)b[ 0] : 0,
85 left > 1? (unsigned char)b[ 1] : 0,
86 left > 2? (unsigned char)b[ 2] : 0,
87 left > 3? (unsigned char)b[ 3] : 0,
88 left > 4? (unsigned char)b[ 4] : 0,
89 left > 5? (unsigned char)b[ 5] : 0,
90 left > 6? (unsigned char)b[ 6] : 0,
91 left > 7? (unsigned char)b[ 7] : 0,
92 left > 8? (unsigned char)b[ 8] : 0,
93 left > 9? (unsigned char)b[ 9] : 0,
94 left > 10? (unsigned char)b[10] : 0,
95 left > 11? (unsigned char)b[11] : 0,
96 left > 12? (unsigned char)b[12] : 0,
97 left > 13? (unsigned char)b[13] : 0,
98 left > 14? (unsigned char)b[14] : 0,
99 left > 15? (unsigned char)b[15] : 0,
100 (left > 0) ? (isprint(b[ 0]) ? b[ 0] : '.') : ' ',
101 (left > 1) ? (isprint(b[ 1]) ? b[ 1] : '.') : ' ',
102 (left > 2) ? (isprint(b[ 2]) ? b[ 2] : '.') : ' ',
103 (left > 3) ? (isprint(b[ 3]) ? b[ 3] : '.') : ' ',
104 (left > 4) ? (isprint(b[ 4]) ? b[ 4] : '.') : ' ',
105 (left > 5) ? (isprint(b[ 5]) ? b[ 5] : '.') : ' ',
106 (left > 6) ? (isprint(b[ 6]) ? b[ 6] : '.') : ' ',
107 (left > 7) ? (isprint(b[ 7]) ? b[ 7] : '.') : ' ',
108 (left > 8) ? (isprint(b[ 8]) ? b[ 8] : '.') : ' ',
109 (left > 9) ? (isprint(b[ 9]) ? b[ 9] : '.') : ' ',
110 (left > 10) ? (isprint(b[10]) ? b[10] : '.') : ' ',
111 (left > 11) ? (isprint(b[11]) ? b[11] : '.') : ' ',
112 (left > 12) ? (isprint(b[12]) ? b[12] : '.') : ' ',
113 (left > 13) ? (isprint(b[13]) ? b[13] : '.') : ' ',
114 (left > 14) ? (isprint(b[14]) ? b[14] : '.') : ' ',
115 (left > 15) ? (isprint(b[15]) ? b[15] : '.') : ' '
122 FLAC__bool parse_vorbis_comment_field(const char *field_ref, char **field, char **name, char **value, unsigned *length, const char **violation)
124 static const char * const violations[] = {
125 "field name contains invalid character",
126 "field contains no '=' character"
132 *field = local_strdup(field_ref);
134 s = local_strdup(field_ref);
136 if(0 == (p = strchr(s, '='))) {
138 *violation = violations[1];
143 for(q = s; *q; q++) {
144 if(*q < 0x20 || *q > 0x7d || *q == 0x3d) {
146 *violation = violations[0];
151 *name = local_strdup(s);
152 *value = local_strdup(p);
159 void write_vc_field(const char *filename, const FLAC__StreamMetadata_VorbisComment_Entry *entry, FLAC__bool raw, FILE *f)
161 if(0 != entry->entry) {
163 fprintf(f, "%s:", filename);
167 * utf8_decode() works on NULL-terminated strings, so
168 * we append a null to the entry. @@@ Note, this means
169 * that comments that contain an embedded null will be
170 * truncated by utf_decode().
172 char *terminated, *converted;
174 if(0 == (terminated = malloc(entry->length + 1)))
175 die("out of memory allocating space for vorbis comment");
176 memcpy(terminated, entry->entry, entry->length);
177 terminated[entry->length] = '\0';
178 if(utf8_decode(terminated, &converted) >= 0) {
179 (void) local_fwrite(converted, 1, strlen(converted), f);
185 (void) local_fwrite(entry->entry, 1, entry->length, f);
189 (void) local_fwrite(entry->entry, 1, entry->length, f);
196 void write_vc_fields(const char *filename, const char *field_name, const FLAC__StreamMetadata_VorbisComment_Entry entry[], unsigned num_entries, FLAC__bool raw, FILE *f)
199 const unsigned field_name_length = (0 != field_name)? strlen(field_name) : 0;
201 for(i = 0; i < num_entries; i++) {
202 if(0 == field_name || FLAC__metadata_object_vorbiscomment_entry_matches(entry + i, field_name, field_name_length))
203 write_vc_field(filename, entry + i, raw, f);