operations.c
上传用户:wstnjxml
上传日期:2014-04-03
资源大小:7248k
文件大小:24k
源码类别:

Windows CE

开发平台:

C/C++

  1. /* metaflac - Command-line FLAC metadata editor
  2.  * Copyright (C) 2001,2002,2003,2004,2005  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. #include "operations.h"
  19. #include "usage.h"
  20. #include "utils.h"
  21. #include "FLAC/assert.h"
  22. #include "FLAC/metadata.h"
  23. #include "share/grabbag.h"
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. static void show_version();
  28. static FLAC__bool do_major_operation(const CommandLineOptions *options);
  29. static FLAC__bool do_major_operation_on_file(const char *filename, const CommandLineOptions *options);
  30. static FLAC__bool do_major_operation__list(const char *filename, FLAC__Metadata_Chain *chain, const CommandLineOptions *options);
  31. static FLAC__bool do_major_operation__append(FLAC__Metadata_Chain *chain, const CommandLineOptions *options);
  32. static FLAC__bool do_major_operation__remove(FLAC__Metadata_Chain *chain, const CommandLineOptions *options);
  33. static FLAC__bool do_major_operation__remove_all(FLAC__Metadata_Chain *chain, const CommandLineOptions *options);
  34. static FLAC__bool do_shorthand_operations(const CommandLineOptions *options);
  35. static FLAC__bool do_shorthand_operations_on_file(const char *filename, const CommandLineOptions *options);
  36. static FLAC__bool do_shorthand_operation(const char *filename, FLAC__bool prefix_with_filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write, FLAC__bool utf8_convert);
  37. static FLAC__bool do_shorthand_operation__add_replay_gain(char **filenames, unsigned num_files, FLAC__bool preserve_modtime);
  38. static FLAC__bool do_shorthand_operation__add_padding(const char *filename, FLAC__Metadata_Chain *chain, unsigned length, FLAC__bool *needs_write);
  39. static FLAC__bool passes_filter(const CommandLineOptions *options, const FLAC__StreamMetadata *block, unsigned block_number);
  40. static void write_metadata(const char *filename, FLAC__StreamMetadata *block, unsigned block_number, FLAC__bool raw, FLAC__bool hexdump_application);
  41. /* from operations_shorthand_seektable.c */
  42. extern FLAC__bool do_shorthand_operation__add_seekpoints(const char *filename, FLAC__Metadata_Chain *chain, const char *specification, FLAC__bool *needs_write);
  43. /* from operations_shorthand_streaminfo.c */
  44. extern FLAC__bool do_shorthand_operation__streaminfo(const char *filename, FLAC__bool prefix_with_filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write);
  45. /* from operations_shorthand_vorbiscomment.c */
  46. extern FLAC__bool do_shorthand_operation__vorbis_comment(const char *filename, FLAC__bool prefix_with_filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write, FLAC__bool raw);
  47. /* from operations_shorthand_cuesheet.c */
  48. extern FLAC__bool do_shorthand_operation__cuesheet(const char *filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write);
  49. FLAC__bool do_operations(const CommandLineOptions *options)
  50. {
  51. FLAC__bool ok = true;
  52. if(options->show_long_help) {
  53. long_usage(0);
  54. }
  55. if(options->show_version) {
  56. show_version();
  57. }
  58. else if(options->args.checks.num_major_ops > 0) {
  59. FLAC__ASSERT(options->args.checks.num_shorthand_ops == 0);
  60. FLAC__ASSERT(options->args.checks.num_major_ops == 1);
  61. FLAC__ASSERT(options->args.checks.num_major_ops == options->ops.num_operations);
  62. ok = do_major_operation(options);
  63. }
  64. else if(options->args.checks.num_shorthand_ops > 0) {
  65. FLAC__ASSERT(options->args.checks.num_shorthand_ops == options->ops.num_operations);
  66. ok = do_shorthand_operations(options);
  67. }
  68. return ok;
  69. }
  70. /*
  71.  * local routines
  72.  */
  73. void show_version()
  74. {
  75. printf("metaflac %sn", FLAC__VERSION_STRING);
  76. }
  77. FLAC__bool do_major_operation(const CommandLineOptions *options)
  78. {
  79. unsigned i;
  80. FLAC__bool ok = true;
  81. /*@@@ to die after first error,  v---  add '&& ok' here */
  82. for(i = 0; i < options->num_files; i++)
  83. ok &= do_major_operation_on_file(options->filenames[i], options);
  84. return ok;
  85. }
  86. FLAC__bool do_major_operation_on_file(const char *filename, const CommandLineOptions *options)
  87. {
  88. FLAC__bool ok = true, needs_write = false;
  89. FLAC__Metadata_Chain *chain = FLAC__metadata_chain_new();
  90. if(0 == chain)
  91. die("out of memory allocating chain");
  92. if(!FLAC__metadata_chain_read(chain, filename)) {
  93. print_error_with_chain_status(chain, "%s: ERROR: reading metadata", filename);
  94. FLAC__metadata_chain_delete(chain);
  95. return false;
  96. }
  97. switch(options->ops.operations[0].type) {
  98. case OP__LIST:
  99. ok = do_major_operation__list(options->prefix_with_filename? filename : 0, chain, options);
  100. break;
  101. case OP__APPEND:
  102. ok = do_major_operation__append(chain, options);
  103. needs_write = true;
  104. break;
  105. case OP__REMOVE:
  106. ok = do_major_operation__remove(chain, options);
  107. needs_write = true;
  108. break;
  109. case OP__REMOVE_ALL:
  110. ok = do_major_operation__remove_all(chain, options);
  111. needs_write = true;
  112. break;
  113. case OP__MERGE_PADDING:
  114. FLAC__metadata_chain_merge_padding(chain);
  115. needs_write = true;
  116. break;
  117. case OP__SORT_PADDING:
  118. FLAC__metadata_chain_sort_padding(chain);
  119. needs_write = true;
  120. break;
  121. default:
  122. FLAC__ASSERT(0);
  123. return false;
  124. }
  125. if(ok && needs_write) {
  126. if(options->use_padding)
  127. FLAC__metadata_chain_sort_padding(chain);
  128. ok = FLAC__metadata_chain_write(chain, options->use_padding, options->preserve_modtime);
  129. if(!ok)
  130. print_error_with_chain_status(chain, "%s: ERROR: writing FLAC file", filename);
  131. }
  132. FLAC__metadata_chain_delete(chain);
  133. return ok;
  134. }
  135. FLAC__bool do_major_operation__list(const char *filename, FLAC__Metadata_Chain *chain, const CommandLineOptions *options)
  136. {
  137. FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new();
  138. FLAC__StreamMetadata *block;
  139. FLAC__bool ok = true;
  140. unsigned block_number;
  141. if(0 == iterator)
  142. die("out of memory allocating iterator");
  143. FLAC__metadata_iterator_init(iterator, chain);
  144. block_number = 0;
  145. do {
  146. block = FLAC__metadata_iterator_get_block(iterator);
  147. ok &= (0 != block);
  148. if(!ok)
  149. fprintf(stderr, "%s: ERROR: couldn't get block from chainn", filename);
  150. else if(passes_filter(options, FLAC__metadata_iterator_get_block(iterator), block_number))
  151. write_metadata(filename, block, block_number, !options->utf8_convert, options->application_data_format_is_hexdump);
  152. block_number++;
  153. } while(ok && FLAC__metadata_iterator_next(iterator));
  154. FLAC__metadata_iterator_delete(iterator);
  155. return ok;
  156. }
  157. FLAC__bool do_major_operation__append(FLAC__Metadata_Chain *chain, const CommandLineOptions *options)
  158. {
  159. (void) chain, (void) options;
  160. fprintf(stderr, "ERROR: --append not implemented yetn"); /*@@@*/
  161. return false;
  162. }
  163. FLAC__bool do_major_operation__remove(FLAC__Metadata_Chain *chain, const CommandLineOptions *options)
  164. {
  165. FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new();
  166. FLAC__bool ok = true;
  167. unsigned block_number;
  168. if(0 == iterator)
  169. die("out of memory allocating iterator");
  170. FLAC__metadata_iterator_init(iterator, chain);
  171. block_number = 0;
  172. while(ok && FLAC__metadata_iterator_next(iterator)) {
  173. block_number++;
  174. if(passes_filter(options, FLAC__metadata_iterator_get_block(iterator), block_number)) {
  175. ok &= FLAC__metadata_iterator_delete_block(iterator, options->use_padding);
  176. if(options->use_padding)
  177. ok &= FLAC__metadata_iterator_next(iterator);
  178. }
  179. }
  180. FLAC__metadata_iterator_delete(iterator);
  181. return ok;
  182. }
  183. FLAC__bool do_major_operation__remove_all(FLAC__Metadata_Chain *chain, const CommandLineOptions *options)
  184. {
  185. FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new();
  186. FLAC__bool ok = true;
  187. if(0 == iterator)
  188. die("out of memory allocating iterator");
  189. FLAC__metadata_iterator_init(iterator, chain);
  190. while(ok && FLAC__metadata_iterator_next(iterator)) {
  191. ok &= FLAC__metadata_iterator_delete_block(iterator, options->use_padding);
  192. if(options->use_padding)
  193. ok &= FLAC__metadata_iterator_next(iterator);
  194. }
  195. FLAC__metadata_iterator_delete(iterator);
  196. return ok;
  197. }
  198. FLAC__bool do_shorthand_operations(const CommandLineOptions *options)
  199. {
  200. unsigned i;
  201. FLAC__bool ok = true;
  202. /* to die after first error,     v---  add '&& ok' here */
  203. for(i = 0; i < options->num_files; i++)
  204. ok &= do_shorthand_operations_on_file(options->filenames[i], options);
  205. /* check if OP__ADD_REPLAY_GAIN requested */
  206. if(ok && options->num_files > 0) {
  207. for(i = 0; i < options->ops.num_operations; i++) {
  208. if(options->ops.operations[i].type == OP__ADD_REPLAY_GAIN)
  209. ok = do_shorthand_operation__add_replay_gain(options->filenames, options->num_files, options->preserve_modtime);
  210. }
  211. }
  212. return ok;
  213. }
  214. FLAC__bool do_shorthand_operations_on_file(const char *filename, const CommandLineOptions *options)
  215. {
  216. unsigned i;
  217. FLAC__bool ok = true, needs_write = false, use_padding = options->use_padding;
  218. FLAC__Metadata_Chain *chain = FLAC__metadata_chain_new();
  219. if(0 == chain)
  220. die("out of memory allocating chain");
  221. if(!FLAC__metadata_chain_read(chain, filename)) {
  222. print_error_with_chain_status(chain, "%s: ERROR: reading metadata", filename);
  223. return false;
  224. }
  225. for(i = 0; i < options->ops.num_operations && ok; i++) {
  226. /*
  227.  * Do OP__ADD_SEEKPOINT last to avoid decoding twice if both
  228.  * --add-seekpoint and --import-cuesheet-from are used.
  229.  */
  230. if(options->ops.operations[i].type != OP__ADD_SEEKPOINT)
  231. ok &= do_shorthand_operation(filename, options->prefix_with_filename, chain, &options->ops.operations[i], &needs_write, options->utf8_convert);
  232. /* The following seems counterintuitive but the meaning
  233.  * of 'use_padding' is 'try to keep the overall metadata
  234.  * to its original size, adding or truncating extra
  235.  * padding if necessary' which is why we need to turn it
  236.  * off in this case.  If we don't, the extra padding block
  237.  * will just be truncated.
  238.  */
  239. if(options->ops.operations[i].type == OP__ADD_PADDING)
  240. use_padding = false;
  241. }
  242. /*
  243.  * Do OP__ADD_SEEKPOINT last to avoid decoding twice if both
  244.  * --add-seekpoint and --import-cuesheet-from are used.
  245.  */
  246. for(i = 0; i < options->ops.num_operations && ok; i++) {
  247. if(options->ops.operations[i].type == OP__ADD_SEEKPOINT)
  248. ok &= do_shorthand_operation(filename, options->prefix_with_filename, chain, &options->ops.operations[i], &needs_write, options->utf8_convert);
  249. }
  250. if(ok && needs_write) {
  251. if(use_padding)
  252. FLAC__metadata_chain_sort_padding(chain);
  253. ok = FLAC__metadata_chain_write(chain, use_padding, options->preserve_modtime);
  254. if(!ok)
  255. print_error_with_chain_status(chain, "%s: ERROR: writing FLAC file", filename);
  256. }
  257. FLAC__metadata_chain_delete(chain);
  258. return ok;
  259. }
  260. FLAC__bool do_shorthand_operation(const char *filename, FLAC__bool prefix_with_filename, FLAC__Metadata_Chain *chain, const Operation *operation, FLAC__bool *needs_write, FLAC__bool utf8_convert)
  261. {
  262. FLAC__bool ok = true;
  263. switch(operation->type) {
  264. case OP__SHOW_MD5SUM:
  265. case OP__SHOW_MIN_BLOCKSIZE:
  266. case OP__SHOW_MAX_BLOCKSIZE:
  267. case OP__SHOW_MIN_FRAMESIZE:
  268. case OP__SHOW_MAX_FRAMESIZE:
  269. case OP__SHOW_SAMPLE_RATE:
  270. case OP__SHOW_CHANNELS:
  271. case OP__SHOW_BPS:
  272. case OP__SHOW_TOTAL_SAMPLES:
  273. case OP__SET_MD5SUM:
  274. case OP__SET_MIN_BLOCKSIZE:
  275. case OP__SET_MAX_BLOCKSIZE:
  276. case OP__SET_MIN_FRAMESIZE:
  277. case OP__SET_MAX_FRAMESIZE:
  278. case OP__SET_SAMPLE_RATE:
  279. case OP__SET_CHANNELS:
  280. case OP__SET_BPS:
  281. case OP__SET_TOTAL_SAMPLES:
  282. ok = do_shorthand_operation__streaminfo(filename, prefix_with_filename, chain, operation, needs_write);
  283. break;
  284. case OP__SHOW_VC_VENDOR:
  285. case OP__SHOW_VC_FIELD:
  286. case OP__REMOVE_VC_ALL:
  287. case OP__REMOVE_VC_FIELD:
  288. case OP__REMOVE_VC_FIRSTFIELD:
  289. case OP__SET_VC_FIELD:
  290. case OP__IMPORT_VC_FROM:
  291. case OP__EXPORT_VC_TO:
  292. ok = do_shorthand_operation__vorbis_comment(filename, prefix_with_filename, chain, operation, needs_write, !utf8_convert);
  293. break;
  294. case OP__IMPORT_CUESHEET_FROM:
  295. case OP__EXPORT_CUESHEET_TO:
  296. ok = do_shorthand_operation__cuesheet(filename, chain, operation, needs_write);
  297. break;
  298. case OP__ADD_SEEKPOINT:
  299. ok = do_shorthand_operation__add_seekpoints(filename, chain, operation->argument.add_seekpoint.specification, needs_write);
  300. break;
  301. case OP__ADD_REPLAY_GAIN:
  302. /* this command is always executed last */
  303. ok = true;
  304. break;
  305. case OP__ADD_PADDING:
  306. ok = do_shorthand_operation__add_padding(filename, chain, operation->argument.add_padding.length, needs_write);
  307. break;
  308. default:
  309. ok = false;
  310. FLAC__ASSERT(0);
  311. break;
  312. };
  313. return ok;
  314. }
  315. FLAC__bool do_shorthand_operation__add_replay_gain(char **filenames, unsigned num_files, FLAC__bool preserve_modtime)
  316. {
  317. FLAC__StreamMetadata streaminfo;
  318. float *title_gains = 0, *title_peaks = 0;
  319. float album_gain, album_peak;
  320. unsigned sample_rate = 0;
  321. unsigned bits_per_sample = 0;
  322. unsigned channels = 0;
  323. unsigned i;
  324. const char *error;
  325. FLAC__bool first = true;
  326. FLAC__ASSERT(num_files > 0);
  327. for(i = 0; i < num_files; i++) {
  328. FLAC__ASSERT(0 != filenames[i]);
  329. if(!FLAC__metadata_get_streaminfo(filenames[i], &streaminfo)) {
  330. fprintf(stderr, "%s: ERROR: can't open file or get STREAMINFO blockn", filenames[i]);
  331. return false;
  332. }
  333. if(first) {
  334. first = false;
  335. sample_rate = streaminfo.data.stream_info.sample_rate;
  336. bits_per_sample = streaminfo.data.stream_info.bits_per_sample;
  337. channels = streaminfo.data.stream_info.channels;
  338. }
  339. else {
  340. if(sample_rate != streaminfo.data.stream_info.sample_rate) {
  341. fprintf(stderr, "%s: ERROR: sample rate of %u Hz does not match previous files' %u Hzn", filenames[i], streaminfo.data.stream_info.sample_rate, sample_rate);
  342. return false;
  343. }
  344. if(bits_per_sample != streaminfo.data.stream_info.bits_per_sample) {
  345. fprintf(stderr, "%s: ERROR: resolution of %u bps does not match previous files' %u bpsn", filenames[i], streaminfo.data.stream_info.bits_per_sample, bits_per_sample);
  346. return false;
  347. }
  348. if(channels != streaminfo.data.stream_info.channels) {
  349. fprintf(stderr, "%s: ERROR: # channels (%u) does not match previous files' (%u)n", filenames[i], streaminfo.data.stream_info.channels, channels);
  350. return false;
  351. }
  352. }
  353. if(!grabbag__replaygain_is_valid_sample_frequency(sample_rate)) {
  354. fprintf(stderr, "%s: ERROR: sample rate of %u Hz is not supportedn", filenames[i], sample_rate);
  355. return false;
  356. }
  357. if(channels != 1 && channels != 2) {
  358. fprintf(stderr, "%s: ERROR: # of channels (%u) is not supported, must be 1 or 2n", filenames[i], channels);
  359. return false;
  360. }
  361. }
  362. FLAC__ASSERT(bits_per_sample >= FLAC__MIN_BITS_PER_SAMPLE && bits_per_sample <= FLAC__MAX_BITS_PER_SAMPLE);
  363. if(!grabbag__replaygain_init(sample_rate)) {
  364. FLAC__ASSERT(0);
  365. /* double protection */
  366. fprintf(stderr, "internal errorn");
  367. return false;
  368. }
  369. if(
  370. 0 == (title_gains = (float*)malloc(sizeof(float) * num_files)) ||
  371. 0 == (title_peaks = (float*)malloc(sizeof(float) * num_files))
  372. )
  373. die("out of memory allocating space for title gains/peaks");
  374. for(i = 0; i < num_files; i++) {
  375. if(0 != (error = grabbag__replaygain_analyze_file(filenames[i], title_gains+i, title_peaks+i))) {
  376. fprintf(stderr, "%s: ERROR: during analysis (%s)n", filenames[i], error);
  377. free(title_gains);
  378. free(title_peaks);
  379. return false;
  380. }
  381. }
  382. grabbag__replaygain_get_album(&album_gain, &album_peak);
  383. for(i = 0; i < num_files; i++) {
  384. if(0 != (error = grabbag__replaygain_store_to_file(filenames[i], album_gain, album_peak, title_gains[i], title_peaks[i], preserve_modtime))) {
  385. fprintf(stderr, "%s: ERROR: writing tags (%s)n", filenames[i], error);
  386. free(title_gains);
  387. free(title_peaks);
  388. return false;
  389. }
  390. }
  391. free(title_gains);
  392. free(title_peaks);
  393. return true;
  394. }
  395. FLAC__bool do_shorthand_operation__add_padding(const char *filename, FLAC__Metadata_Chain *chain, unsigned length, FLAC__bool *needs_write)
  396. {
  397. FLAC__StreamMetadata *padding = 0;
  398. FLAC__Metadata_Iterator *iterator = FLAC__metadata_iterator_new();
  399. if(0 == iterator)
  400. die("out of memory allocating iterator");
  401. FLAC__metadata_iterator_init(iterator, chain);
  402. while(FLAC__metadata_iterator_next(iterator))
  403. ;
  404. padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING);
  405. if(0 == padding)
  406. die("out of memory allocating PADDING block");
  407. padding->length = length;
  408. if(!FLAC__metadata_iterator_insert_block_after(iterator, padding)) {
  409. print_error_with_chain_status(chain, "%s: ERROR: adding new PADDING block to metadata", filename);
  410. FLAC__metadata_object_delete(padding);
  411. FLAC__metadata_iterator_delete(iterator);
  412. return false;
  413. }
  414. FLAC__metadata_iterator_delete(iterator);
  415. *needs_write = true;
  416. return true;
  417. }
  418. FLAC__bool passes_filter(const CommandLineOptions *options, const FLAC__StreamMetadata *block, unsigned block_number)
  419. {
  420. unsigned i, j;
  421. FLAC__bool matches_number = false, matches_type = false;
  422. FLAC__bool has_block_number_arg = false;
  423. for(i = 0; i < options->args.num_arguments; i++) {
  424. if(options->args.arguments[i].type == ARG__BLOCK_TYPE || options->args.arguments[i].type == ARG__EXCEPT_BLOCK_TYPE) {
  425. for(j = 0; j < options->args.arguments[i].value.block_type.num_entries; j++) {
  426. if(options->args.arguments[i].value.block_type.entries[j].type == block->type) {
  427. if(block->type != FLAC__METADATA_TYPE_APPLICATION || !options->args.arguments[i].value.block_type.entries[j].filter_application_by_id || 0 == memcmp(options->args.arguments[i].value.block_type.entries[j].application_id, block->data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8))
  428. matches_type = true;
  429. }
  430. }
  431. }
  432. else if(options->args.arguments[i].type == ARG__BLOCK_NUMBER) {
  433. has_block_number_arg = true;
  434. for(j = 0; j < options->args.arguments[i].value.block_number.num_entries; j++) {
  435. if(options->args.arguments[i].value.block_number.entries[j] == block_number)
  436. matches_number = true;
  437. }
  438. }
  439. }
  440. if(!has_block_number_arg)
  441. matches_number = true;
  442. if(options->args.checks.has_block_type) {
  443. FLAC__ASSERT(!options->args.checks.has_except_block_type);
  444. }
  445. else if(options->args.checks.has_except_block_type)
  446. matches_type = !matches_type;
  447. else
  448. matches_type = true;
  449. return matches_number && matches_type;
  450. }
  451. void write_metadata(const char *filename, FLAC__StreamMetadata *block, unsigned block_number, FLAC__bool raw, FLAC__bool hexdump_application)
  452. {
  453. unsigned i, j;
  454. /*@@@ yuck, should do this with a varargs function or something: */
  455. #define PPR if(filename)printf("%s:",filename);
  456. PPR; printf("METADATA block #%un", block_number);
  457. PPR; printf("  type: %u (%s)n", (unsigned)block->type, block->type < FLAC__METADATA_TYPE_UNDEFINED? FLAC__MetadataTypeString[block->type] : "UNKNOWN");
  458. PPR; printf("  is last: %sn", block->is_last? "true":"false");
  459. PPR; printf("  length: %un", block->length);
  460. switch(block->type) {
  461. case FLAC__METADATA_TYPE_STREAMINFO:
  462. PPR; printf("  minumum blocksize: %u samplesn", block->data.stream_info.min_blocksize);
  463. PPR; printf("  maximum blocksize: %u samplesn", block->data.stream_info.max_blocksize);
  464. PPR; printf("  minimum framesize: %u bytesn", block->data.stream_info.min_framesize);
  465. PPR; printf("  maximum framesize: %u bytesn", block->data.stream_info.max_framesize);
  466. PPR; printf("  sample_rate: %u Hzn", block->data.stream_info.sample_rate);
  467. PPR; printf("  channels: %un", block->data.stream_info.channels);
  468. PPR; printf("  bits-per-sample: %un", block->data.stream_info.bits_per_sample);
  469. #ifdef _MSC_VER
  470. PPR; printf("  total samples: %I64un", block->data.stream_info.total_samples);
  471. #else
  472. PPR; printf("  total samples: %llun", block->data.stream_info.total_samples);
  473. #endif
  474. PPR; printf("  MD5 signature: ");
  475. for(i = 0; i < 16; i++) {
  476. printf("%02x", (unsigned)block->data.stream_info.md5sum[i]);
  477. }
  478. printf("n");
  479. break;
  480. case FLAC__METADATA_TYPE_PADDING:
  481. /* nothing to print */
  482. break;
  483. case FLAC__METADATA_TYPE_APPLICATION:
  484. PPR; printf("  application ID: ");
  485. for(i = 0; i < 4; i++)
  486. printf("%02x", block->data.application.id[i]);
  487. printf("n");
  488. PPR; printf("  data contents:n");
  489. if(0 != block->data.application.data) {
  490. if(hexdump_application)
  491. hexdump(filename, block->data.application.data, block->length - FLAC__STREAM_METADATA_HEADER_LENGTH, "    ");
  492. else
  493. (void) local_fwrite(block->data.application.data, 1, block->length - FLAC__STREAM_METADATA_HEADER_LENGTH, stdout);
  494. }
  495. break;
  496. case FLAC__METADATA_TYPE_SEEKTABLE:
  497. PPR; printf("  seek points: %un", block->data.seek_table.num_points);
  498. for(i = 0; i < block->data.seek_table.num_points; i++) {
  499. if(block->data.seek_table.points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER) {
  500. #ifdef _MSC_VER
  501. PPR; printf("    point %u: sample_number=%I64u, stream_offset=%I64u, frame_samples=%un", i, block->data.seek_table.points[i].sample_number, block->data.seek_table.points[i].stream_offset, block->data.seek_table.points[i].frame_samples);
  502. #else
  503. PPR; printf("    point %u: sample_number=%llu, stream_offset=%llu, frame_samples=%un", i, block->data.seek_table.points[i].sample_number, block->data.seek_table.points[i].stream_offset, block->data.seek_table.points[i].frame_samples);
  504. #endif
  505. }
  506. else {
  507. PPR; printf("    point %u: PLACEHOLDERn", i);
  508. }
  509. }
  510. break;
  511. case FLAC__METADATA_TYPE_VORBIS_COMMENT:
  512. PPR; printf("  vendor string: ");
  513. write_vc_field(0, &block->data.vorbis_comment.vendor_string, raw, stdout);
  514. PPR; printf("  comments: %un", block->data.vorbis_comment.num_comments);
  515. for(i = 0; i < block->data.vorbis_comment.num_comments; i++) {
  516. PPR; printf("    comment[%u]: ", i);
  517. write_vc_field(0, &block->data.vorbis_comment.comments[i], raw, stdout);
  518. }
  519. break;
  520. case FLAC__METADATA_TYPE_CUESHEET:
  521. PPR; printf("  media catalog number: %sn", block->data.cue_sheet.media_catalog_number);
  522. #ifdef _MSC_VER
  523. PPR; printf("  lead-in: %I64un", block->data.cue_sheet.lead_in);
  524. #else
  525. PPR; printf("  lead-in: %llun", block->data.cue_sheet.lead_in);
  526. #endif
  527. PPR; printf("  is CD: %sn", block->data.cue_sheet.is_cd? "true":"false");
  528. PPR; printf("  number of tracks: %un", block->data.cue_sheet.num_tracks);
  529. for(i = 0; i < block->data.cue_sheet.num_tracks; i++) {
  530. const FLAC__StreamMetadata_CueSheet_Track *track = block->data.cue_sheet.tracks+i;
  531. const FLAC__bool is_last = (i == block->data.cue_sheet.num_tracks-1);
  532. const FLAC__bool is_leadout = is_last && track->num_indices == 0;
  533. PPR; printf("    track[%u]n", i);
  534. #ifdef _MSC_VER
  535. PPR; printf("      offset: %I64un", track->offset);
  536. #else
  537. PPR; printf("      offset: %llun", track->offset);
  538. #endif
  539. if(is_last) {
  540. PPR; printf("      number: %u (%s)n", (unsigned)track->number, is_leadout? "LEAD-OUT" : "INVALID");
  541. }
  542. else {
  543. PPR; printf("      number: %un", (unsigned)track->number);
  544. }
  545. if(!is_leadout) {
  546. PPR; printf("      ISRC: %sn", track->isrc);
  547. PPR; printf("      type: %sn", track->type == 1? "DATA" : "AUDIO");
  548. PPR; printf("      pre-emphasis: %sn", track->pre_emphasis? "true":"false");
  549. PPR; printf("      number of index points: %un", track->num_indices);
  550. for(j = 0; j < track->num_indices; j++) {
  551. const FLAC__StreamMetadata_CueSheet_Index *index = track->indices+j;
  552. PPR; printf("        index[%u]n", j);
  553. #ifdef _MSC_VER
  554. PPR; printf("          offset: %I64un", index->offset);
  555. #else
  556. PPR; printf("          offset: %llun", index->offset);
  557. #endif
  558. PPR; printf("          number: %un", (unsigned)index->number);
  559. }
  560. }
  561. }
  562. break;
  563. default:
  564. PPR; printf("  data contents:n");
  565. if(0 != block->data.unknown.data)
  566. hexdump(filename, block->data.unknown.data, block->length, "    ");
  567. break;
  568. }
  569. #undef PPR
  570. }