OLD | NEW |
1 /* | 1 /* |
2 * rdjpgcom.c | 2 * rdjpgcom.c |
3 * | 3 * |
4 * Copyright (C) 1994-1997, Thomas G. Lane. | 4 * Copyright (C) 1994-1997, Thomas G. Lane. |
| 5 * Modified 2009 by Bill Allombert, Guido Vollbeding. |
5 * This file is part of the Independent JPEG Group's software. | 6 * This file is part of the Independent JPEG Group's software. |
6 * For conditions of distribution and use, see the accompanying README file. | 7 * For conditions of distribution and use, see the accompanying README file. |
7 * | 8 * |
8 * This file contains a very simple stand-alone application that displays | 9 * This file contains a very simple stand-alone application that displays |
9 * the text in COM (comment) markers in a JFIF file. | 10 * the text in COM (comment) markers in a JFIF file. |
10 * This may be useful as an example of the minimum logic needed to parse | 11 * This may be useful as an example of the minimum logic needed to parse |
11 * JPEG markers. | 12 * JPEG markers. |
12 */ | 13 */ |
13 | 14 |
14 #define JPEG_CJPEG_DJPEG /* to get the command-line config symbols */ | 15 #define JPEG_CJPEG_DJPEG /* to get the command-line config symbols */ |
15 #include "jinclude.h" /* get auto-config symbols, <stdio.h> */ | 16 #include "jinclude.h" /* get auto-config symbols, <stdio.h> */ |
16 | 17 |
| 18 #ifdef HAVE_LOCALE_H |
| 19 #include <locale.h> /* Bill Allombert: use locale for isprint */ |
| 20 #endif |
17 #include <ctype.h> /* to declare isupper(), tolower() */ | 21 #include <ctype.h> /* to declare isupper(), tolower() */ |
18 #ifdef USE_SETMODE | 22 #ifdef USE_SETMODE |
19 #include <fcntl.h> /* to declare setmode()'s parameter macros */ | 23 #include <fcntl.h> /* to declare setmode()'s parameter macros */ |
20 /* If you have setmode() but not <io.h>, just delete this line: */ | 24 /* If you have setmode() but not <io.h>, just delete this line: */ |
21 #include <io.h> /* to declare setmode() */ | 25 #include <io.h> /* to declare setmode() */ |
22 #endif | 26 #endif |
23 | 27 |
24 #ifdef USE_CCOMMAND /* command-line reader for Macintosh */ | 28 #ifdef USE_CCOMMAND /* command-line reader for Macintosh */ |
25 #ifdef __MWERKS__ | 29 #ifdef __MWERKS__ |
26 #include <SIOUX.h> /* Metrowerks needs this */ | 30 #include <SIOUX.h> /* Metrowerks needs this */ |
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
211 } | 215 } |
212 | 216 |
213 | 217 |
214 /* | 218 /* |
215 * Process a COM marker. | 219 * Process a COM marker. |
216 * We want to print out the marker contents as legible text; | 220 * We want to print out the marker contents as legible text; |
217 * we must guard against non-text junk and varying newline representations. | 221 * we must guard against non-text junk and varying newline representations. |
218 */ | 222 */ |
219 | 223 |
220 static void | 224 static void |
221 process_COM (void) | 225 process_COM (int raw) |
222 { | 226 { |
223 unsigned int length; | 227 unsigned int length; |
224 int ch; | 228 int ch; |
225 int lastch = 0; | 229 int lastch = 0; |
226 | 230 |
| 231 /* Bill Allombert: set locale properly for isprint */ |
| 232 #ifdef HAVE_LOCALE_H |
| 233 setlocale(LC_CTYPE, ""); |
| 234 #endif |
| 235 |
227 /* Get the marker parameter length count */ | 236 /* Get the marker parameter length count */ |
228 length = read_2_bytes(); | 237 length = read_2_bytes(); |
229 /* Length includes itself, so must be at least 2 */ | 238 /* Length includes itself, so must be at least 2 */ |
230 if (length < 2) | 239 if (length < 2) |
231 ERREXIT("Erroneous JPEG marker length"); | 240 ERREXIT("Erroneous JPEG marker length"); |
232 length -= 2; | 241 length -= 2; |
233 | 242 |
234 while (length > 0) { | 243 while (length > 0) { |
235 ch = read_1_byte(); | 244 ch = read_1_byte(); |
| 245 if (raw) { |
| 246 putc(ch, stdout); |
236 /* Emit the character in a readable form. | 247 /* Emit the character in a readable form. |
237 * Nonprintables are converted to \nnn form, | 248 * Nonprintables are converted to \nnn form, |
238 * while \ is converted to \\. | 249 * while \ is converted to \\. |
239 * Newlines in CR, CR/LF, or LF form will be printed as one newline. | 250 * Newlines in CR, CR/LF, or LF form will be printed as one newline. |
240 */ | 251 */ |
241 if (ch == '\r') { | 252 } else if (ch == '\r') { |
242 printf("\n"); | 253 printf("\n"); |
243 } else if (ch == '\n') { | 254 } else if (ch == '\n') { |
244 if (lastch != '\r') | 255 if (lastch != '\r') |
245 printf("\n"); | 256 printf("\n"); |
246 } else if (ch == '\\') { | 257 } else if (ch == '\\') { |
247 printf("\\\\"); | 258 printf("\\\\"); |
248 } else if (isprint(ch)) { | 259 } else if (isprint(ch)) { |
249 putc(ch, stdout); | 260 putc(ch, stdout); |
250 } else { | 261 } else { |
251 printf("\\%03o", ch); | 262 printf("\\%03o", ch); |
252 } | 263 } |
253 lastch = ch; | 264 lastch = ch; |
254 length--; | 265 length--; |
255 } | 266 } |
256 printf("\n"); | 267 printf("\n"); |
| 268 |
| 269 /* Bill Allombert: revert to C locale */ |
| 270 #ifdef HAVE_LOCALE_H |
| 271 setlocale(LC_CTYPE, "C"); |
| 272 #endif |
257 } | 273 } |
258 | 274 |
259 | 275 |
260 /* | 276 /* |
261 * Process a SOFn marker. | 277 * Process a SOFn marker. |
262 * This code is only needed if you want to know the image dimensions... | 278 * This code is only needed if you want to know the image dimensions... |
263 */ | 279 */ |
264 | 280 |
265 static void | 281 static void |
266 process_SOFn (int marker) | 282 process_SOFn (int marker) |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
314 * Parse the marker stream until SOS or EOI is seen; | 330 * Parse the marker stream until SOS or EOI is seen; |
315 * display any COM markers. | 331 * display any COM markers. |
316 * While the companion program wrjpgcom will always insert COM markers before | 332 * While the companion program wrjpgcom will always insert COM markers before |
317 * SOFn, other implementations might not, so we scan to SOS before stopping. | 333 * SOFn, other implementations might not, so we scan to SOS before stopping. |
318 * If we were only interested in the image dimensions, we would stop at SOFn. | 334 * If we were only interested in the image dimensions, we would stop at SOFn. |
319 * (Conversely, if we only cared about COM markers, there would be no need | 335 * (Conversely, if we only cared about COM markers, there would be no need |
320 * for special code to handle SOFn; we could treat it like other markers.) | 336 * for special code to handle SOFn; we could treat it like other markers.) |
321 */ | 337 */ |
322 | 338 |
323 static int | 339 static int |
324 scan_JPEG_header (int verbose) | 340 scan_JPEG_header (int verbose, int raw) |
325 { | 341 { |
326 int marker; | 342 int marker; |
327 | 343 |
328 /* Expect SOI at start of file */ | 344 /* Expect SOI at start of file */ |
329 if (first_marker() != M_SOI) | 345 if (first_marker() != M_SOI) |
330 ERREXIT("Expected SOI marker first"); | 346 ERREXIT("Expected SOI marker first"); |
331 | 347 |
332 /* Scan miscellaneous markers until we reach SOS. */ | 348 /* Scan miscellaneous markers until we reach SOS. */ |
333 for (;;) { | 349 for (;;) { |
334 marker = next_marker(); | 350 marker = next_marker(); |
(...skipping 20 matching lines...) Expand all Loading... |
355 skip_variable(); | 371 skip_variable(); |
356 break; | 372 break; |
357 | 373 |
358 case M_SOS: /* stop before hitting compressed data */ | 374 case M_SOS: /* stop before hitting compressed data */ |
359 return marker; | 375 return marker; |
360 | 376 |
361 case M_EOI: /* in case it's a tables-only JPEG stream */ | 377 case M_EOI: /* in case it's a tables-only JPEG stream */ |
362 return marker; | 378 return marker; |
363 | 379 |
364 case M_COM: | 380 case M_COM: |
365 process_COM(); | 381 process_COM(raw); |
366 break; | 382 break; |
367 | 383 |
368 case M_APP12: | 384 case M_APP12: |
369 /* Some digital camera makers put useful textual information into | 385 /* Some digital camera makers put useful textual information into |
370 * APP12 markers, so we print those out too when in -verbose mode. | 386 * APP12 markers, so we print those out too when in -verbose mode. |
371 */ | 387 */ |
372 if (verbose) { | 388 if (verbose) { |
373 printf("APP12 contains:\n"); | 389 printf("APP12 contains:\n"); |
374 » process_COM(); | 390 » process_COM(raw); |
375 } else | 391 } else |
376 skip_variable(); | 392 skip_variable(); |
377 break; | 393 break; |
378 | 394 |
379 default: /* Anything else just gets skipped */ | 395 default: /* Anything else just gets skipped */ |
380 skip_variable(); /* we assume it has a parameter count... */ | 396 skip_variable(); /* we assume it has a parameter count... */ |
381 break; | 397 break; |
382 } | 398 } |
383 } /* end loop */ | 399 } /* end loop */ |
384 } | 400 } |
385 | 401 |
386 | 402 |
387 /* Command line parsing code */ | 403 /* Command line parsing code */ |
388 | 404 |
389 static const char * progname; /* program name for error messages */ | 405 static const char * progname; /* program name for error messages */ |
390 | 406 |
391 | 407 |
392 static void | 408 static void |
393 usage (void) | 409 usage (void) |
394 /* complain about bad command line */ | 410 /* complain about bad command line */ |
395 { | 411 { |
396 fprintf(stderr, "rdjpgcom displays any textual comments in a JPEG file.\n"); | 412 fprintf(stderr, "rdjpgcom displays any textual comments in a JPEG file.\n"); |
397 | 413 |
398 fprintf(stderr, "Usage: %s [switches] [inputfile]\n", progname); | 414 fprintf(stderr, "Usage: %s [switches] [inputfile]\n", progname); |
399 | 415 |
400 fprintf(stderr, "Switches (names may be abbreviated):\n"); | 416 fprintf(stderr, "Switches (names may be abbreviated):\n"); |
| 417 fprintf(stderr, " -raw Display non-printable characters in comments (u
nsafe)\n"); |
401 fprintf(stderr, " -verbose Also display dimensions of JPEG image\n"); | 418 fprintf(stderr, " -verbose Also display dimensions of JPEG image\n"); |
402 | 419 |
403 exit(EXIT_FAILURE); | 420 exit(EXIT_FAILURE); |
404 } | 421 } |
405 | 422 |
406 | 423 |
407 static int | 424 static int |
408 keymatch (char * arg, const char * keyword, int minchars) | 425 keymatch (char * arg, const char * keyword, int minchars) |
409 /* Case-insensitive matching of (possibly abbreviated) keyword switches. */ | 426 /* Case-insensitive matching of (possibly abbreviated) keyword switches. */ |
410 /* keyword is the constant keyword (must be lower case already), */ | 427 /* keyword is the constant keyword (must be lower case already), */ |
(...skipping 20 matching lines...) Expand all Loading... |
431 | 448 |
432 /* | 449 /* |
433 * The main program. | 450 * The main program. |
434 */ | 451 */ |
435 | 452 |
436 int | 453 int |
437 main (int argc, char **argv) | 454 main (int argc, char **argv) |
438 { | 455 { |
439 int argn; | 456 int argn; |
440 char * arg; | 457 char * arg; |
441 int verbose = 0; | 458 int verbose = 0, raw = 0; |
442 | 459 |
443 /* On Mac, fetch a command line. */ | 460 /* On Mac, fetch a command line. */ |
444 #ifdef USE_CCOMMAND | 461 #ifdef USE_CCOMMAND |
445 argc = ccommand(&argv); | 462 argc = ccommand(&argv); |
446 #endif | 463 #endif |
447 | 464 |
448 progname = argv[0]; | 465 progname = argv[0]; |
449 if (progname == NULL || progname[0] == 0) | 466 if (progname == NULL || progname[0] == 0) |
450 progname = "rdjpgcom"; /* in case C library doesn't provide it */ | 467 progname = "rdjpgcom"; /* in case C library doesn't provide it */ |
451 | 468 |
452 /* Parse switches, if any */ | 469 /* Parse switches, if any */ |
453 for (argn = 1; argn < argc; argn++) { | 470 for (argn = 1; argn < argc; argn++) { |
454 arg = argv[argn]; | 471 arg = argv[argn]; |
455 if (arg[0] != '-') | 472 if (arg[0] != '-') |
456 break; /* not switch, must be file name */ | 473 break; /* not switch, must be file name */ |
457 arg++; /* advance over '-' */ | 474 arg++; /* advance over '-' */ |
458 if (keymatch(arg, "verbose", 1)) { | 475 if (keymatch(arg, "verbose", 1)) { |
459 verbose++; | 476 verbose++; |
| 477 } else if (keymatch(arg, "raw", 1)) { |
| 478 raw = 1; |
460 } else | 479 } else |
461 usage(); | 480 usage(); |
462 } | 481 } |
463 | 482 |
464 /* Open the input file. */ | 483 /* Open the input file. */ |
465 /* Unix style: expect zero or one file name */ | 484 /* Unix style: expect zero or one file name */ |
466 if (argn < argc-1) { | 485 if (argn < argc-1) { |
467 fprintf(stderr, "%s: only one input file\n", progname); | 486 fprintf(stderr, "%s: only one input file\n", progname); |
468 usage(); | 487 usage(); |
469 } | 488 } |
(...skipping 11 matching lines...) Expand all Loading... |
481 if ((infile = fdopen(fileno(stdin), READ_BINARY)) == NULL) { | 500 if ((infile = fdopen(fileno(stdin), READ_BINARY)) == NULL) { |
482 fprintf(stderr, "%s: can't open stdin\n", progname); | 501 fprintf(stderr, "%s: can't open stdin\n", progname); |
483 exit(EXIT_FAILURE); | 502 exit(EXIT_FAILURE); |
484 } | 503 } |
485 #else | 504 #else |
486 infile = stdin; | 505 infile = stdin; |
487 #endif | 506 #endif |
488 } | 507 } |
489 | 508 |
490 /* Scan the JPEG headers. */ | 509 /* Scan the JPEG headers. */ |
491 (void) scan_JPEG_header(verbose); | 510 (void) scan_JPEG_header(verbose, raw); |
492 | 511 |
493 /* All done. */ | 512 /* All done. */ |
494 exit(EXIT_SUCCESS); | 513 exit(EXIT_SUCCESS); |
495 return 0; /* suppress no-return-value warnings */ | 514 return 0; /* suppress no-return-value warnings */ |
496 } | 515 } |
OLD | NEW |