~ubuntu-branches/ubuntu/saucy/flac/saucy

« back to all changes in this revision

Viewing changes to src/metaflac/main.c

  • Committer: Bazaar Package Importer
  • Author(s): Matt Zimmerman
  • Date: 2001-12-10 03:09:22 UTC
  • Revision ID: james.westby@ubuntu.com-20011210030922-0vdtpz6a7mfwefo5
Tags: upstream-1.0.2
ImportĀ upstreamĀ versionĀ 1.0.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* metaflac - Command-line FLAC metadata editor
 
2
 * Copyright (C) 2001  Josh Coalson
 
3
 *
 
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.
 
8
 *
 
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.
 
13
 *
 
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.
 
17
 */
 
18
 
 
19
/*
 
20
 * WATCHOUT - this is meant to be very lightweight an not even dependent
 
21
 * on libFLAC, so there are a couple places where FLAC__* variables are
 
22
 * duplicated here.  Look for 'DUPLICATE:' in comments.
 
23
 */
 
24
 
 
25
#include <ctype.h>
 
26
#include <stdarg.h>
 
27
#include <stdio.h>
 
28
#include <stdlib.h>
 
29
#include <string.h>
 
30
#include "FLAC/all.h"
 
31
 
 
32
static const char *sync_string_ = "fLaC"; /* DUPLICATE:FLAC__STREAM_SYNC_STRING */
 
33
static const char *metadata_type_string_[] = { /* DUPLICATE:FLAC__MetaDataTypeString */
 
34
        "STREAMINFO",
 
35
        "PADDING",
 
36
        "APPLICATION",
 
37
        "SEEKTABLE"
 
38
};
 
39
static const unsigned SEEKPOINT_LEN_ = 18; /* DUPLICATE:FLAC__STREAM_METADATA_SEEKPOINT_LEN */
 
40
 
 
41
static int usage(const char *message, ...);
 
42
static FLAC__bool list(FILE *f, FLAC__bool verbose);
 
43
static FLAC__uint32 unpack_uint32(FLAC__byte *b, unsigned bytes);
 
44
static FLAC__uint64 unpack_uint64(FLAC__byte *b, unsigned bytes);
 
45
static void hexdump(const FLAC__byte *buf, unsigned bytes, const char *indent);
 
46
 
 
47
int main(int argc, char *argv[])
 
48
{
 
49
        int i, first_file, retval = 0;
 
50
        FLAC__bool verbose = false, list_mode = true;
 
51
 
 
52
        if(argc <= 1)
 
53
                return usage(0);
 
54
 
 
55
        /* get the options */
 
56
        for(i = 1; i < argc; i++) {
 
57
                if(argv[i][0] != '-' || argv[i][1] == 0)
 
58
                        break;
 
59
                if(0 == strcmp(argv[i], "-l"))
 
60
                        list_mode = true;
 
61
                else if(0 == strcmp(argv[i], "-v"))
 
62
                        verbose = true;
 
63
                else if(0 == strcmp(argv[i], "-v-"))
 
64
                        verbose = false;
 
65
                else {
 
66
                        return usage("ERROR: invalid option '%s'\n", argv[i]);
 
67
                }
 
68
        }
 
69
        if(i == argc)
 
70
                return usage(0);
 
71
 
 
72
        if(list_mode) {
 
73
                for(first_file = i; i < argc; i++) {
 
74
                        FILE *f = fopen(argv[i], "r");
 
75
 
 
76
                        if(0 == f) {
 
77
                                fprintf(stderr, "ERROR opening %s\n", argv[i]);
 
78
                                retval = 1;
 
79
                        }
 
80
                        else {
 
81
                                printf("%sfile: %s\n", i==first_file? "" : "\n", argv[i]);
 
82
 
 
83
                                if(!list(f, verbose))
 
84
                                        retval = 1;
 
85
 
 
86
                                fclose(f);
 
87
                        }
 
88
                }
 
89
        }
 
90
 
 
91
        return retval;
 
92
}
 
93
 
 
94
int usage(const char *message, ...)
 
95
{
 
96
        va_list args;
 
97
 
 
98
        if(message) {
 
99
                va_start(args, message);
 
100
 
 
101
                (void) vfprintf(stderr, message, args);
 
102
 
 
103
                va_end(args);
 
104
 
 
105
        }
 
106
        printf("==============================================================================\n");
 
107
        printf("metaflac - Command-line FLAC metadata editor version %s\n", FLAC__VERSION_STRING);
 
108
        printf("Copyright (C) 2001  Josh Coalson\n");
 
109
        printf("\n");
 
110
        printf("This program is free software; you can redistribute it and/or\n");
 
111
        printf("modify it under the terms of the GNU General Public License\n");
 
112
        printf("as published by the Free Software Foundation; either version 2\n");
 
113
        printf("of the License, or (at your option) any later version.\n");
 
114
        printf("\n");
 
115
        printf("This program is distributed in the hope that it will be useful,\n");
 
116
        printf("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
 
117
        printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
 
118
        printf("GNU General Public License for more details.\n");
 
119
        printf("\n");
 
120
        printf("You should have received a copy of the GNU General Public License\n");
 
121
        printf("along with this program; if not, write to the Free Software\n");
 
122
        printf("Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n");
 
123
        printf("==============================================================================\n");
 
124
        printf("Usage:\n");
 
125
        printf("  metaflac [options] flacfile [...]\n");
 
126
        printf("\n");
 
127
        printf("options:\n");
 
128
        printf("  -l : list metadata blocks\n");
 
129
        printf("  -v : verbose\n");
 
130
 
 
131
        return message? 1 : 0;
 
132
}
 
133
 
 
134
FLAC__bool list(FILE *f, FLAC__bool verbose)
 
135
{
 
136
        FLAC__byte buf[65536];
 
137
        FLAC__byte *b = buf;
 
138
        FLAC__StreamMetaData metadata;
 
139
        unsigned blocknum = 0, byte_offset = 0, i;
 
140
 
 
141
        /* skip any id3v2 tag */
 
142
        if(fread(buf, 1, 4, f) < 4) {
 
143
                fprintf(stderr, "ERROR: not a FLAC file\n");
 
144
                return false;
 
145
        }
 
146
        if(0 == memcmp(buf, "ID3", 3)) {
 
147
                unsigned tag_length = 0;
 
148
 
 
149
                /* skip to the tag length */
 
150
                if(fseek(f, 2, SEEK_CUR) < 0) {
 
151
                        fprintf(stderr, "ERROR: bad ID3v2 tag\n");
 
152
                        return false;
 
153
                }
 
154
 
 
155
                /* read the length */
 
156
                for(i = 0; i < 4; i++) {
 
157
                        if(fread(buf, 1, 1, f) < 1 || buf[0] & 0x80) {
 
158
                                fprintf(stderr, "ERROR: bad ID3v2 tag\n");
 
159
                                return false;
 
160
                        }
 
161
                        tag_length <<= 7;
 
162
                        tag_length |= (buf[0] & 0x7f);
 
163
                }
 
164
 
 
165
                /* skip the rest of the tag */
 
166
                if(fseek(f, tag_length, SEEK_CUR) < 0) {
 
167
                        fprintf(stderr, "ERROR: bad ID3v2 tag\n");
 
168
                        return false;
 
169
                }
 
170
 
 
171
                /* read the stream sync code */
 
172
                if(fread(buf, 1, 4, f) < 4) {
 
173
                        fprintf(stderr, "ERROR: not a FLAC file (no '%s' header)\n", sync_string_);
 
174
                        return false;
 
175
                }
 
176
        }
 
177
 
 
178
        /* check the stream sync code */
 
179
        if(memcmp(buf, sync_string_, 4)) {
 
180
                fprintf(stderr, "ERROR: not a FLAC file (no '%s' header)\n", sync_string_);
 
181
                return false;
 
182
        }
 
183
        byte_offset += 4;
 
184
 
 
185
        /* read the metadata blocks */
 
186
        do {
 
187
                /* read the metadata block header */
 
188
                if(fread(buf, 1, 4, f) < 4) {
 
189
                        fprintf(stderr, "ERROR: short count reading metadata block header\n");
 
190
                        return false;
 
191
                }
 
192
                metadata.is_last = (buf[0] & 0x80)? true:false;
 
193
                metadata.type = (FLAC__MetaDataType)(buf[0] & 0x7f);
 
194
                metadata.length = unpack_uint32(buf+1, 3);
 
195
 
 
196
                /* print header */
 
197
                printf("METADATA block #%u\n", blocknum);
 
198
                printf("  byte offset: %u\n", byte_offset);
 
199
                printf("  type: %u (%s)\n", (unsigned)metadata.type, metadata.type<=FLAC__METADATA_TYPE_SEEKTABLE? metadata_type_string_[metadata.type] : "UNKNOWN");
 
200
                printf("  is last: %s\n", metadata.is_last? "true":"false");
 
201
                printf("  length: %u\n", metadata.length);
 
202
 
 
203
                if(metadata.length > sizeof(buf)) {
 
204
                        printf("  SKIPPING large block\n");
 
205
                        if(fseek(f, metadata.length, SEEK_CUR) < 0) {
 
206
                                fprintf(stderr, "ERROR: short count skipping metadata block data\n");
 
207
                                return false;
 
208
                        }
 
209
                        continue;
 
210
                }
 
211
 
 
212
                /* read the metadata block data */
 
213
                if(fread(buf, 1, metadata.length, f) < metadata.length) {
 
214
                        fprintf(stderr, "ERROR: short count reading metadata block data\n");
 
215
                        return false;
 
216
                }
 
217
                switch(metadata.type) {
 
218
                        case FLAC__METADATA_TYPE_STREAMINFO:
 
219
                                b = buf;
 
220
                                metadata.data.stream_info.min_blocksize = unpack_uint32(b, 2); b += 2;
 
221
                                metadata.data.stream_info.max_blocksize = unpack_uint32(b, 2); b += 2;
 
222
                                metadata.data.stream_info.min_framesize = unpack_uint32(b, 3); b += 3;
 
223
                                metadata.data.stream_info.max_framesize = unpack_uint32(b, 3); b += 3;
 
224
                                metadata.data.stream_info.sample_rate = (unpack_uint32(b, 2) << 4) | ((unsigned)(b[2] & 0xf0) >> 4);
 
225
                                metadata.data.stream_info.channels = (unsigned)((b[2] & 0x0e) >> 1) + 1;
 
226
                                metadata.data.stream_info.bits_per_sample = ((((unsigned)(b[2] & 0x01)) << 1) | (((unsigned)(b[3] & 0xf0)) >> 4)) + 1;
 
227
                                metadata.data.stream_info.total_samples = (((FLAC__uint64)(b[3] & 0x0f)) << 32) | unpack_uint64(b+4, 4);
 
228
                                memcpy(metadata.data.stream_info.md5sum, b+8, 16);
 
229
                                break;
 
230
                        case FLAC__METADATA_TYPE_PADDING:
 
231
                                if(verbose) {
 
232
                                        /* dump contents */
 
233
                                }
 
234
                                break;
 
235
                        case FLAC__METADATA_TYPE_APPLICATION:
 
236
                                memcpy(buf, metadata.data.application.id, 4);
 
237
                                metadata.data.application.data = buf+4;
 
238
                                break;
 
239
                        case FLAC__METADATA_TYPE_SEEKTABLE:
 
240
                                metadata.data.seek_table.num_points = metadata.length / SEEKPOINT_LEN_;
 
241
                                b = buf; /* we leave the points in buf for printing later */
 
242
                                break;
 
243
                        default:
 
244
                                printf("SKIPPING block of unknown type\n");
 
245
                                continue;
 
246
                }
 
247
 
 
248
                /* print data */
 
249
                switch(metadata.type) {
 
250
                        case FLAC__METADATA_TYPE_STREAMINFO:
 
251
                                printf("  minumum blocksize: %u samples\n", metadata.data.stream_info.min_blocksize);
 
252
                                printf("  maximum blocksize: %u samples\n", metadata.data.stream_info.max_blocksize);
 
253
                                printf("  minimum framesize: %u bytes\n", metadata.data.stream_info.min_framesize);
 
254
                                printf("  maximum framesize: %u bytes\n", metadata.data.stream_info.max_framesize);
 
255
                                printf("  sample_rate: %u Hz\n", metadata.data.stream_info.sample_rate);
 
256
                                printf("  channels: %u\n", metadata.data.stream_info.channels);
 
257
                                printf("  bits-per-sample: %u\n", metadata.data.stream_info.bits_per_sample);
 
258
                                printf("  total samples: %llu\n", metadata.data.stream_info.total_samples);
 
259
                                printf("  MD5 signature: ");
 
260
                                for(i = 0; i < 16; i++)
 
261
                                        printf("%02x", metadata.data.stream_info.md5sum[i]);
 
262
                                printf("\n");
 
263
                                break;
 
264
                        case FLAC__METADATA_TYPE_PADDING:
 
265
                                if(verbose) {
 
266
                                        printf("  pad contents:\n");
 
267
                                        hexdump(buf, metadata.length, "    ");
 
268
                                }
 
269
                                break;
 
270
                        case FLAC__METADATA_TYPE_APPLICATION:
 
271
                                printf("  application ID: ");
 
272
                                for(i = 0; i < 4; i++)
 
273
                                        printf("%02x", metadata.data.application.id[i]);
 
274
                                printf("\n");
 
275
                                if(verbose) {
 
276
                                        printf("  data contents:\n");
 
277
                                        hexdump(metadata.data.application.data, metadata.length, "    ");
 
278
                                }
 
279
                                break;
 
280
                        case FLAC__METADATA_TYPE_SEEKTABLE:
 
281
                                printf("  seek points: %u\n", metadata.data.seek_table.num_points);
 
282
                                if(verbose) {
 
283
                                        for(i = 0; i < metadata.data.seek_table.num_points; i++, b += SEEKPOINT_LEN_)
 
284
                                                printf("    point %d: sample_number=%llu, stream_offset=%llu, frame_samples=%u\n", i, unpack_uint64(b, 8), unpack_uint64(b+8, 8), unpack_uint32(b+16, 2));
 
285
                                }
 
286
                                break;
 
287
                        default:
 
288
                                FLAC__ASSERT(0);
 
289
                }
 
290
 
 
291
                blocknum++;
 
292
                byte_offset += (4 + metadata.length);
 
293
        } while (!metadata.is_last);
 
294
 
 
295
        return true;
 
296
}
 
297
 
 
298
FLAC__uint32 unpack_uint32(FLAC__byte *b, unsigned bytes)
 
299
{
 
300
        FLAC__uint32 ret = 0;
 
301
        unsigned i;
 
302
 
 
303
        for(i = 0; i < bytes; i++)
 
304
                ret = (ret << 8) | (FLAC__uint32)(*b++);
 
305
 
 
306
        return ret;
 
307
}
 
308
 
 
309
FLAC__uint64 unpack_uint64(FLAC__byte *b, unsigned bytes)
 
310
{
 
311
        FLAC__uint64 ret = 0;
 
312
        unsigned i;
 
313
 
 
314
        for(i = 0; i < bytes; i++)
 
315
                ret = (ret << 8) | (FLAC__uint64)(*b++);
 
316
 
 
317
        return ret;
 
318
}
 
319
 
 
320
void hexdump(const FLAC__byte *buf, unsigned bytes, const char *indent)
 
321
{
 
322
        unsigned i, left = bytes;
 
323
        const FLAC__byte *b = buf;
 
324
 
 
325
        for(i = 0; i < bytes; i += 16) {
 
326
                printf("%s%08X: "
 
327
                        "%02X %02X %02X %02X %02X %02X %02X %02X "
 
328
                        "%02X %02X %02X %02X %02X %02X %02X %02X "
 
329
                        "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
 
330
                        indent, i,
 
331
                        left >  0? (unsigned char)b[ 0] : 0,
 
332
                        left >  1? (unsigned char)b[ 1] : 0,
 
333
                        left >  2? (unsigned char)b[ 2] : 0,
 
334
                        left >  3? (unsigned char)b[ 3] : 0,
 
335
                        left >  4? (unsigned char)b[ 4] : 0,
 
336
                        left >  5? (unsigned char)b[ 5] : 0,
 
337
                        left >  6? (unsigned char)b[ 6] : 0,
 
338
                        left >  7? (unsigned char)b[ 7] : 0,
 
339
                        left >  8? (unsigned char)b[ 8] : 0,
 
340
                        left >  9? (unsigned char)b[ 9] : 0,
 
341
                        left > 10? (unsigned char)b[10] : 0,
 
342
                        left > 11? (unsigned char)b[11] : 0,
 
343
                        left > 12? (unsigned char)b[12] : 0,
 
344
                        left > 13? (unsigned char)b[13] : 0,
 
345
                        left > 14? (unsigned char)b[14] : 0,
 
346
                        left > 15? (unsigned char)b[15] : 0,
 
347
                        (left >  0) ? (isprint(b[ 0]) ? b[ 0] : '.') : ' ',
 
348
                        (left >  1) ? (isprint(b[ 1]) ? b[ 1] : '.') : ' ',
 
349
                        (left >  2) ? (isprint(b[ 2]) ? b[ 2] : '.') : ' ',
 
350
                        (left >  3) ? (isprint(b[ 3]) ? b[ 3] : '.') : ' ',
 
351
                        (left >  4) ? (isprint(b[ 4]) ? b[ 4] : '.') : ' ',
 
352
                        (left >  5) ? (isprint(b[ 5]) ? b[ 5] : '.') : ' ',
 
353
                        (left >  6) ? (isprint(b[ 6]) ? b[ 6] : '.') : ' ',
 
354
                        (left >  7) ? (isprint(b[ 7]) ? b[ 7] : '.') : ' ',
 
355
                        (left >  8) ? (isprint(b[ 8]) ? b[ 8] : '.') : ' ',
 
356
                        (left >  9) ? (isprint(b[ 9]) ? b[ 9] : '.') : ' ',
 
357
                        (left > 10) ? (isprint(b[10]) ? b[10] : '.') : ' ',
 
358
                        (left > 11) ? (isprint(b[11]) ? b[11] : '.') : ' ',
 
359
                        (left > 12) ? (isprint(b[12]) ? b[12] : '.') : ' ',
 
360
                        (left > 13) ? (isprint(b[13]) ? b[13] : '.') : ' ',
 
361
                        (left > 14) ? (isprint(b[14]) ? b[14] : '.') : ' ',
 
362
                        (left > 15) ? (isprint(b[15]) ? b[15] : '.') : ' '
 
363
                );
 
364
                left -= 16;
 
365
                b += 16;
 
366
   }
 
367
}