OLD | NEW |
1 /* | 1 /* |
2 * wrjpgcom.c | 2 * wrjpgcom.c |
3 * | 3 * |
| 4 * This file was part of the Independent JPEG Group's software: |
4 * Copyright (C) 1994-1997, Thomas G. Lane. | 5 * Copyright (C) 1994-1997, Thomas G. Lane. |
5 * This file is part of the Independent JPEG Group's software. | 6 * libjpeg-turbo Modifications: |
6 * For conditions of distribution and use, see the accompanying README file. | 7 * Copyright (C) 2014, D. R. Commander |
| 8 * For conditions of distribution and use, see the accompanying README.ijg |
| 9 * file. |
7 * | 10 * |
8 * This file contains a very simple stand-alone application that inserts | 11 * This file contains a very simple stand-alone application that inserts |
9 * user-supplied text as a COM (comment) marker in a JFIF file. | 12 * user-supplied text as a COM (comment) marker in a JFIF file. |
10 * This may be useful as an example of the minimum logic needed to parse | 13 * This may be useful as an example of the minimum logic needed to parse |
11 * JPEG markers. | 14 * JPEG markers. |
12 */ | 15 */ |
13 | 16 |
14 #define JPEG_CJPEG_DJPEG» /* to get the command-line config symbols */ | 17 #define JPEG_CJPEG_DJPEG /* to get the command-line config symbols */ |
15 #include "jinclude.h"» » /* get auto-config symbols, <stdio.h> */ | 18 #include "jinclude.h" /* get auto-config symbols, <stdio.h> */ |
16 | 19 |
17 #ifndef HAVE_STDLIB_H» » /* <stdlib.h> should declare malloc() */ | 20 #ifndef HAVE_STDLIB_H /* <stdlib.h> should declare malloc() */ |
18 extern void * malloc (); | 21 extern void *malloc (); |
19 #endif | 22 #endif |
20 #include <ctype.h>» » /* to declare isupper(), tolower() */ | 23 #include <ctype.h> /* to declare isupper(), tolower() */ |
21 #ifdef USE_SETMODE | 24 #ifdef USE_SETMODE |
22 #include <fcntl.h>» » /* to declare setmode()'s parameter macros */ | 25 #include <fcntl.h> /* to declare setmode()'s parameter macros */ |
23 /* If you have setmode() but not <io.h>, just delete this line: */ | 26 /* If you have setmode() but not <io.h>, just delete this line: */ |
24 #include <io.h>»» » /* to declare setmode() */ | 27 #include <io.h> /* to declare setmode() */ |
25 #endif | 28 #endif |
26 | 29 |
27 #ifdef USE_CCOMMAND» » /* command-line reader for Macintosh */ | 30 #ifdef USE_CCOMMAND /* command-line reader for Macintosh */ |
28 #ifdef __MWERKS__ | 31 #ifdef __MWERKS__ |
29 #include <SIOUX.h> /* Metrowerks needs this */ | 32 #include <SIOUX.h> /* Metrowerks needs this */ |
30 #include <console.h>» » /* ... and this */ | 33 #include <console.h> /* ... and this */ |
31 #endif | 34 #endif |
32 #ifdef THINK_C | 35 #ifdef THINK_C |
33 #include <console.h>» » /* Think declares it here */ | 36 #include <console.h> /* Think declares it here */ |
34 #endif | 37 #endif |
35 #endif | 38 #endif |
36 | 39 |
37 #ifdef DONT_USE_B_MODE» » /* define mode parameters for fopen() */ | 40 #ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */ |
38 #define READ_BINARY» "r" | 41 #define READ_BINARY "r" |
39 #define WRITE_BINARY» "w" | 42 #define WRITE_BINARY "w" |
40 #else | 43 #else |
41 #ifdef VMS» » » /* VMS is very nonstandard */ | 44 #define READ_BINARY "rb" |
42 #define READ_BINARY» "rb", "ctx=stm" | 45 #define WRITE_BINARY "wb" |
43 #define WRITE_BINARY» "wb", "ctx=stm" | |
44 #else» » » » /* standard ANSI-compliant case */ | |
45 #define READ_BINARY» "rb" | |
46 #define WRITE_BINARY» "wb" | |
47 #endif | |
48 #endif | 46 #endif |
49 | 47 |
50 #ifndef EXIT_FAILURE» » /* define exit() codes if not provided */ | 48 #ifndef EXIT_FAILURE /* define exit() codes if not provided */ |
51 #define EXIT_FAILURE 1 | 49 #define EXIT_FAILURE 1 |
52 #endif | 50 #endif |
53 #ifndef EXIT_SUCCESS | 51 #ifndef EXIT_SUCCESS |
54 #ifdef VMS | |
55 #define EXIT_SUCCESS 1 /* VMS is very nonstandard */ | |
56 #else | |
57 #define EXIT_SUCCESS 0 | 52 #define EXIT_SUCCESS 0 |
58 #endif | 53 #endif |
59 #endif | |
60 | 54 |
61 /* Reduce this value if your malloc() can't allocate blocks up to 64K. | 55 /* Reduce this value if your malloc() can't allocate blocks up to 64K. |
62 * On DOS, compiling in large model is usually a better solution. | 56 * On DOS, compiling in large model is usually a better solution. |
63 */ | 57 */ |
64 | 58 |
65 #ifndef MAX_COM_LENGTH | 59 #ifndef MAX_COM_LENGTH |
66 #define MAX_COM_LENGTH 65000L» /* must be <= 65533 in any case */ | 60 #define MAX_COM_LENGTH 65000L /* must be <= 65533 in any case */ |
67 #endif | 61 #endif |
68 | 62 |
69 | 63 |
70 /* | 64 /* |
71 * These macros are used to read the input file and write the output file. | 65 * These macros are used to read the input file and write the output file. |
72 * To reuse this code in another application, you might need to change these. | 66 * To reuse this code in another application, you might need to change these. |
73 */ | 67 */ |
74 | 68 |
75 static FILE * infile;» » /* input JPEG file */ | 69 static FILE *infile; /* input JPEG file */ |
76 | 70 |
77 /* Return next input byte, or EOF if no more */ | 71 /* Return next input byte, or EOF if no more */ |
78 #define NEXTBYTE() getc(infile) | 72 #define NEXTBYTE() getc(infile) |
79 | 73 |
80 static FILE * outfile;» » /* output JPEG file */ | 74 static FILE *outfile; /* output JPEG file */ |
81 | 75 |
82 /* Emit an output byte */ | 76 /* Emit an output byte */ |
83 #define PUTBYTE(x) putc((x), outfile) | 77 #define PUTBYTE(x) putc((x), outfile) |
84 | 78 |
85 | 79 |
86 /* Error exit handler */ | 80 /* Error exit handler */ |
87 #define ERREXIT(msg) (fprintf(stderr, "%s\n", msg), exit(EXIT_FAILURE)) | 81 #define ERREXIT(msg) (fprintf(stderr, "%s\n", msg), exit(EXIT_FAILURE)) |
88 | 82 |
89 | 83 |
90 /* Read one byte, testing for EOF */ | 84 /* Read one byte, testing for EOF */ |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
147 PUTBYTE(c); | 141 PUTBYTE(c); |
148 } | 142 } |
149 | 143 |
150 | 144 |
151 /* | 145 /* |
152 * JPEG markers consist of one or more 0xFF bytes, followed by a marker | 146 * JPEG markers consist of one or more 0xFF bytes, followed by a marker |
153 * code byte (which is not an FF). Here are the marker codes of interest | 147 * code byte (which is not an FF). Here are the marker codes of interest |
154 * in this program. (See jdmarker.c for a more complete list.) | 148 * in this program. (See jdmarker.c for a more complete list.) |
155 */ | 149 */ |
156 | 150 |
157 #define M_SOF0 0xC0» » /* Start Of Frame N */ | 151 #define M_SOF0 0xC0 /* Start Of Frame N */ |
158 #define M_SOF1 0xC1» » /* N indicates which compression process */ | 152 #define M_SOF1 0xC1 /* N indicates which compression process */ |
159 #define M_SOF2 0xC2» » /* Only SOF0-SOF2 are now in common use */ | 153 #define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */ |
160 #define M_SOF3 0xC3 | 154 #define M_SOF3 0xC3 |
161 #define M_SOF5 0xC5» » /* NB: codes C4 and CC are NOT SOF markers */ | 155 #define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */ |
162 #define M_SOF6 0xC6 | 156 #define M_SOF6 0xC6 |
163 #define M_SOF7 0xC7 | 157 #define M_SOF7 0xC7 |
164 #define M_SOF9 0xC9 | 158 #define M_SOF9 0xC9 |
165 #define M_SOF10 0xCA | 159 #define M_SOF10 0xCA |
166 #define M_SOF11 0xCB | 160 #define M_SOF11 0xCB |
167 #define M_SOF13 0xCD | 161 #define M_SOF13 0xCD |
168 #define M_SOF14 0xCE | 162 #define M_SOF14 0xCE |
169 #define M_SOF15 0xCF | 163 #define M_SOF15 0xCF |
170 #define M_SOI 0xD8» » /* Start Of Image (beginning of datastream) */ | 164 #define M_SOI 0xD8 /* Start Of Image (beginning of datastream) */ |
171 #define M_EOI 0xD9» » /* End Of Image (end of datastream) */ | 165 #define M_EOI 0xD9 /* End Of Image (end of datastream) */ |
172 #define M_SOS 0xDA» » /* Start Of Scan (begins compressed data) */ | 166 #define M_SOS 0xDA /* Start Of Scan (begins compressed data) */ |
173 #define M_COM 0xFE» » /* COMment */ | 167 #define M_COM 0xFE /* COMment */ |
174 | 168 |
175 | 169 |
176 /* | 170 /* |
177 * Find the next JPEG marker and return its marker code. | 171 * Find the next JPEG marker and return its marker code. |
178 * We expect at least one FF byte, possibly more if the compressor used FFs | 172 * We expect at least one FF byte, possibly more if the compressor used FFs |
179 * to pad the file. (Padding FFs will NOT be replicated in the output file.) | 173 * to pad the file. (Padding FFs will NOT be replicated in the output file.) |
180 * There could also be non-FF garbage between markers. The treatment of such | 174 * There could also be non-FF garbage between markers. The treatment of such |
181 * garbage is unspecified; we choose to skip over it but emit a warning msg. | 175 * garbage is unspecified; we choose to skip over it but emit a warning msg. |
182 * NB: this routine must not be used after seeing SOS marker, since it will | 176 * NB: this routine must not be used after seeing SOS marker, since it will |
183 * not deal correctly with FF/00 sequences in the compressed image data... | 177 * not deal correctly with FF/00 sequences in the compressed image data... |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
295 ERREXIT("Expected SOI marker first"); | 289 ERREXIT("Expected SOI marker first"); |
296 write_marker(M_SOI); | 290 write_marker(M_SOI); |
297 | 291 |
298 /* Scan miscellaneous markers until we reach SOFn. */ | 292 /* Scan miscellaneous markers until we reach SOFn. */ |
299 for (;;) { | 293 for (;;) { |
300 marker = next_marker(); | 294 marker = next_marker(); |
301 switch (marker) { | 295 switch (marker) { |
302 /* Note that marker codes 0xC4, 0xC8, 0xCC are not, and must not be, | 296 /* Note that marker codes 0xC4, 0xC8, 0xCC are not, and must not be, |
303 * treated as SOFn. C4 in particular is actually DHT. | 297 * treated as SOFn. C4 in particular is actually DHT. |
304 */ | 298 */ |
305 case M_SOF0:» » /* Baseline */ | 299 case M_SOF0: /* Baseline */ |
306 case M_SOF1:» » /* Extended sequential, Huffman */ | 300 case M_SOF1: /* Extended sequential, Huffman */ |
307 case M_SOF2:» » /* Progressive, Huffman */ | 301 case M_SOF2: /* Progressive, Huffman */ |
308 case M_SOF3:» » /* Lossless, Huffman */ | 302 case M_SOF3: /* Lossless, Huffman */ |
309 case M_SOF5:» » /* Differential sequential, Huffman */ | 303 case M_SOF5: /* Differential sequential, Huffman */ |
310 case M_SOF6:» » /* Differential progressive, Huffman */ | 304 case M_SOF6: /* Differential progressive, Huffman */ |
311 case M_SOF7:» » /* Differential lossless, Huffman */ | 305 case M_SOF7: /* Differential lossless, Huffman */ |
312 case M_SOF9:» » /* Extended sequential, arithmetic */ | 306 case M_SOF9: /* Extended sequential, arithmetic */ |
313 case M_SOF10:» » /* Progressive, arithmetic */ | 307 case M_SOF10: /* Progressive, arithmetic */ |
314 case M_SOF11:» » /* Lossless, arithmetic */ | 308 case M_SOF11: /* Lossless, arithmetic */ |
315 case M_SOF13:» » /* Differential sequential, arithmetic */ | 309 case M_SOF13: /* Differential sequential, arithmetic */ |
316 case M_SOF14:» » /* Differential progressive, arithmetic */ | 310 case M_SOF14: /* Differential progressive, arithmetic */ |
317 case M_SOF15:» » /* Differential lossless, arithmetic */ | 311 case M_SOF15: /* Differential lossless, arithmetic */ |
318 return marker; | 312 return marker; |
319 | 313 |
320 case M_SOS:»» » /* should not see compressed data before SOF */ | 314 case M_SOS: /* should not see compressed data before SOF */ |
321 ERREXIT("SOS without prior SOFn"); | 315 ERREXIT("SOS without prior SOFn"); |
322 break; | 316 break; |
323 | 317 |
324 case M_EOI:»» » /* in case it's a tables-only JPEG stream */ | 318 case M_EOI: /* in case it's a tables-only JPEG stream */ |
325 return marker; | 319 return marker; |
326 | 320 |
327 case M_COM:»» » /* Existing COM: conditionally discard */ | 321 case M_COM: /* Existing COM: conditionally discard */ |
328 if (keep_COM) { | 322 if (keep_COM) { |
329 » write_marker(marker); | 323 write_marker(marker); |
330 » copy_variable(); | 324 copy_variable(); |
331 } else { | 325 } else { |
332 » skip_variable(); | 326 skip_variable(); |
333 } | 327 } |
334 break; | 328 break; |
335 | 329 |
336 default:» » » /* Anything else just gets copied */ | 330 default: /* Anything else just gets copied */ |
337 write_marker(marker); | 331 write_marker(marker); |
338 copy_variable();» » /* we assume it has a parameter count... */ | 332 copy_variable(); /* we assume it has a parameter count... */ |
339 break; | 333 break; |
340 } | 334 } |
341 } /* end loop */ | 335 } /* end loop */ |
342 } | 336 } |
343 | 337 |
344 | 338 |
345 /* Command line parsing code */ | 339 /* Command line parsing code */ |
346 | 340 |
347 static const char * progname;» /* program name for error messages */ | 341 static const char *progname; /* program name for error messages */ |
348 | 342 |
349 | 343 |
350 static void | 344 static void |
351 usage (void) | 345 usage (void) |
352 /* complain about bad command line */ | 346 /* complain about bad command line */ |
353 { | 347 { |
354 fprintf(stderr, "wrjpgcom inserts a textual comment in a JPEG file.\n"); | 348 fprintf(stderr, "wrjpgcom inserts a textual comment in a JPEG file.\n"); |
355 fprintf(stderr, "You can add to or replace any existing comment(s).\n"); | 349 fprintf(stderr, "You can add to or replace any existing comment(s).\n"); |
356 | 350 |
357 fprintf(stderr, "Usage: %s [switches] ", progname); | 351 fprintf(stderr, "Usage: %s [switches] ", progname); |
358 #ifdef TWO_FILE_COMMANDLINE | 352 #ifdef TWO_FILE_COMMANDLINE |
359 fprintf(stderr, "inputfile outputfile\n"); | 353 fprintf(stderr, "inputfile outputfile\n"); |
360 #else | 354 #else |
361 fprintf(stderr, "[inputfile]\n"); | 355 fprintf(stderr, "[inputfile]\n"); |
362 #endif | 356 #endif |
363 | 357 |
364 fprintf(stderr, "Switches (names may be abbreviated):\n"); | 358 fprintf(stderr, "Switches (names may be abbreviated):\n"); |
365 fprintf(stderr, " -replace Delete any existing comments\n"); | 359 fprintf(stderr, " -replace Delete any existing comments\n"); |
366 fprintf(stderr, " -comment \"text\" Insert comment with given text\n"); | 360 fprintf(stderr, " -comment \"text\" Insert comment with given text\n"); |
367 fprintf(stderr, " -cfile name Read comment from named file\n"); | 361 fprintf(stderr, " -cfile name Read comment from named file\n"); |
368 fprintf(stderr, "Notice that you must put quotes around the comment text\n"); | 362 fprintf(stderr, "Notice that you must put quotes around the comment text\n"); |
369 fprintf(stderr, "when you use -comment.\n"); | 363 fprintf(stderr, "when you use -comment.\n"); |
370 fprintf(stderr, "If you do not give either -comment or -cfile on the command l
ine,\n"); | 364 fprintf(stderr, "If you do not give either -comment or -cfile on the command l
ine,\n"); |
371 fprintf(stderr, "then the comment text is read from standard input.\n"); | 365 fprintf(stderr, "then the comment text is read from standard input.\n"); |
372 fprintf(stderr, "It can be multiple lines, up to %u characters total.\n", | 366 fprintf(stderr, "It can be multiple lines, up to %u characters total.\n", |
373 » (unsigned int) MAX_COM_LENGTH); | 367 (unsigned int) MAX_COM_LENGTH); |
374 #ifndef TWO_FILE_COMMANDLINE | 368 #ifndef TWO_FILE_COMMANDLINE |
375 fprintf(stderr, "You must specify an input JPEG file name when supplying\n"); | 369 fprintf(stderr, "You must specify an input JPEG file name when supplying\n"); |
376 fprintf(stderr, "comment text from standard input.\n"); | 370 fprintf(stderr, "comment text from standard input.\n"); |
377 #endif | 371 #endif |
378 | 372 |
379 exit(EXIT_FAILURE); | 373 exit(EXIT_FAILURE); |
380 } | 374 } |
381 | 375 |
382 | 376 |
383 static int | 377 static int |
384 keymatch (char * arg, const char * keyword, int minchars) | 378 keymatch (char *arg, const char *keyword, int minchars) |
385 /* Case-insensitive matching of (possibly abbreviated) keyword switches. */ | 379 /* Case-insensitive matching of (possibly abbreviated) keyword switches. */ |
386 /* keyword is the constant keyword (must be lower case already), */ | 380 /* keyword is the constant keyword (must be lower case already), */ |
387 /* minchars is length of minimum legal abbreviation. */ | 381 /* minchars is length of minimum legal abbreviation. */ |
388 { | 382 { |
389 register int ca, ck; | 383 register int ca, ck; |
390 register int nmatched = 0; | 384 register int nmatched = 0; |
391 | 385 |
392 while ((ca = *arg++) != '\0') { | 386 while ((ca = *arg++) != '\0') { |
393 if ((ck = *keyword++) == '\0') | 387 if ((ck = *keyword++) == '\0') |
394 return 0;»» » /* arg longer than keyword, no good */ | 388 return 0; /* arg longer than keyword, no good */ |
395 if (isupper(ca))» » /* force arg to lcase (assume ck is already) */ | 389 if (isupper(ca)) /* force arg to lcase (assume ck is already) */ |
396 ca = tolower(ca); | 390 ca = tolower(ca); |
397 if (ca != ck) | 391 if (ca != ck) |
398 return 0;»» » /* no good */ | 392 return 0; /* no good */ |
399 nmatched++;»» » /* count matched characters */ | 393 nmatched++; /* count matched characters */ |
400 } | 394 } |
401 /* reached end of argument; fail if it's too short for unique abbrev */ | 395 /* reached end of argument; fail if it's too short for unique abbrev */ |
402 if (nmatched < minchars) | 396 if (nmatched < minchars) |
403 return 0; | 397 return 0; |
404 return 1;» » » /* A-OK */ | 398 return 1; /* A-OK */ |
405 } | 399 } |
406 | 400 |
407 | 401 |
408 /* | 402 /* |
409 * The main program. | 403 * The main program. |
410 */ | 404 */ |
411 | 405 |
412 int | 406 int |
413 main (int argc, char **argv) | 407 main (int argc, char **argv) |
414 { | 408 { |
415 int argn; | 409 int argn; |
416 char * arg; | 410 char *arg; |
417 int keep_COM = 1; | 411 int keep_COM = 1; |
418 char * comment_arg = NULL; | 412 char *comment_arg = NULL; |
419 FILE * comment_file = NULL; | 413 FILE *comment_file = NULL; |
420 unsigned int comment_length = 0; | 414 unsigned int comment_length = 0; |
421 int marker; | 415 int marker; |
422 | 416 |
423 /* On Mac, fetch a command line. */ | 417 /* On Mac, fetch a command line. */ |
424 #ifdef USE_CCOMMAND | 418 #ifdef USE_CCOMMAND |
425 argc = ccommand(&argv); | 419 argc = ccommand(&argv); |
426 #endif | 420 #endif |
427 | 421 |
428 progname = argv[0]; | 422 progname = argv[0]; |
429 if (progname == NULL || progname[0] == 0) | 423 if (progname == NULL || progname[0] == 0) |
430 progname = "wrjpgcom";» /* in case C library doesn't provide it */ | 424 progname = "wrjpgcom"; /* in case C library doesn't provide it */ |
431 | 425 |
432 /* Parse switches, if any */ | 426 /* Parse switches, if any */ |
433 for (argn = 1; argn < argc; argn++) { | 427 for (argn = 1; argn < argc; argn++) { |
434 arg = argv[argn]; | 428 arg = argv[argn]; |
435 if (arg[0] != '-') | 429 if (arg[0] != '-') |
436 break;» » » /* not switch, must be file name */ | 430 break; /* not switch, must be file name */ |
437 arg++;» » » /* advance over '-' */ | 431 arg++; /* advance over '-' */ |
438 if (keymatch(arg, "replace", 1)) { | 432 if (keymatch(arg, "replace", 1)) { |
439 keep_COM = 0; | 433 keep_COM = 0; |
440 } else if (keymatch(arg, "cfile", 2)) { | 434 } else if (keymatch(arg, "cfile", 2)) { |
441 if (++argn >= argc) usage(); | 435 if (++argn >= argc) usage(); |
442 if ((comment_file = fopen(argv[argn], "r")) == NULL) { | 436 if ((comment_file = fopen(argv[argn], "r")) == NULL) { |
443 » fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]); | 437 fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]); |
444 » exit(EXIT_FAILURE); | 438 exit(EXIT_FAILURE); |
445 } | 439 } |
446 } else if (keymatch(arg, "comment", 1)) { | 440 } else if (keymatch(arg, "comment", 1)) { |
447 if (++argn >= argc) usage(); | 441 if (++argn >= argc) usage(); |
448 comment_arg = argv[argn]; | 442 comment_arg = argv[argn]; |
449 /* If the comment text starts with '"', then we are probably running | 443 /* If the comment text starts with '"', then we are probably running |
450 * under MS-DOG and must parse out the quoted string ourselves. Sigh. | 444 * under MS-DOG and must parse out the quoted string ourselves. Sigh. |
451 */ | 445 */ |
452 if (comment_arg[0] == '"') { | 446 if (comment_arg[0] == '"') { |
453 » comment_arg = (char *) malloc((size_t) MAX_COM_LENGTH); | 447 comment_arg = (char *) malloc((size_t) MAX_COM_LENGTH); |
454 » if (comment_arg == NULL) | 448 if (comment_arg == NULL) |
455 » ERREXIT("Insufficient memory"); | 449 ERREXIT("Insufficient memory"); |
456 » strcpy(comment_arg, argv[argn]+1); | 450 if (strlen(argv[argn]) + 2 >= (size_t) MAX_COM_LENGTH) { |
457 » for (;;) { | 451 fprintf(stderr, "Comment text may not exceed %u bytes\n", |
458 » comment_length = (unsigned int) strlen(comment_arg); | 452 (unsigned int) MAX_COM_LENGTH); |
459 » if (comment_length > 0 && comment_arg[comment_length-1] == '"') { | 453 exit(EXIT_FAILURE); |
460 » comment_arg[comment_length-1] = '\0'; /* zap terminating quote */ | 454 } |
461 » break; | 455 strcpy(comment_arg, argv[argn]+1); |
462 » } | 456 for (;;) { |
463 » if (++argn >= argc) | 457 comment_length = (unsigned int) strlen(comment_arg); |
464 » ERREXIT("Missing ending quote mark"); | 458 if (comment_length > 0 && comment_arg[comment_length-1] == '"') { |
465 » strcat(comment_arg, " "); | 459 comment_arg[comment_length-1] = '\0'; /* zap terminating quote */ |
466 » strcat(comment_arg, argv[argn]); | 460 break; |
467 » } | 461 } |
| 462 if (++argn >= argc) |
| 463 ERREXIT("Missing ending quote mark"); |
| 464 if (strlen(comment_arg) + strlen(argv[argn]) + 2 >= |
| 465 (size_t) MAX_COM_LENGTH) { |
| 466 fprintf(stderr, "Comment text may not exceed %u bytes\n", |
| 467 (unsigned int) MAX_COM_LENGTH); |
| 468 exit(EXIT_FAILURE); |
| 469 } |
| 470 strcat(comment_arg, " "); |
| 471 strcat(comment_arg, argv[argn]); |
| 472 } |
| 473 } else if (strlen(argv[argn]) >= (size_t) MAX_COM_LENGTH) { |
| 474 fprintf(stderr, "Comment text may not exceed %u bytes\n", |
| 475 (unsigned int) MAX_COM_LENGTH); |
| 476 exit(EXIT_FAILURE); |
468 } | 477 } |
469 comment_length = (unsigned int) strlen(comment_arg); | 478 comment_length = (unsigned int) strlen(comment_arg); |
470 } else | 479 } else |
471 usage(); | 480 usage(); |
472 } | 481 } |
473 | 482 |
474 /* Cannot use both -comment and -cfile. */ | 483 /* Cannot use both -comment and -cfile. */ |
475 if (comment_arg != NULL && comment_file != NULL) | 484 if (comment_arg != NULL && comment_file != NULL) |
476 usage(); | 485 usage(); |
477 /* If there is neither -comment nor -cfile, we will read the comment text | 486 /* If there is neither -comment nor -cfile, we will read the comment text |
478 * from stdin; in this case there MUST be an input JPEG file name. | 487 * from stdin; in this case there MUST be an input JPEG file name. |
479 */ | 488 */ |
480 if (comment_arg == NULL && comment_file == NULL && argn >= argc) | 489 if (comment_arg == NULL && comment_file == NULL && argn >= argc) |
481 usage(); | 490 usage(); |
482 | 491 |
483 /* Open the input file. */ | 492 /* Open the input file. */ |
484 if (argn < argc) { | 493 if (argn < argc) { |
485 if ((infile = fopen(argv[argn], READ_BINARY)) == NULL) { | 494 if ((infile = fopen(argv[argn], READ_BINARY)) == NULL) { |
486 fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]); | 495 fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]); |
487 exit(EXIT_FAILURE); | 496 exit(EXIT_FAILURE); |
488 } | 497 } |
489 } else { | 498 } else { |
490 /* default input file is stdin */ | 499 /* default input file is stdin */ |
491 #ifdef USE_SETMODE» » /* need to hack file mode? */ | 500 #ifdef USE_SETMODE /* need to hack file mode? */ |
492 setmode(fileno(stdin), O_BINARY); | 501 setmode(fileno(stdin), O_BINARY); |
493 #endif | 502 #endif |
494 #ifdef USE_FDOPEN» » /* need to re-open in binary mode? */ | 503 #ifdef USE_FDOPEN /* need to re-open in binary mode? */ |
495 if ((infile = fdopen(fileno(stdin), READ_BINARY)) == NULL) { | 504 if ((infile = fdopen(fileno(stdin), READ_BINARY)) == NULL) { |
496 fprintf(stderr, "%s: can't open stdin\n", progname); | 505 fprintf(stderr, "%s: can't open stdin\n", progname); |
497 exit(EXIT_FAILURE); | 506 exit(EXIT_FAILURE); |
498 } | 507 } |
499 #else | 508 #else |
500 infile = stdin; | 509 infile = stdin; |
501 #endif | 510 #endif |
502 } | 511 } |
503 | 512 |
504 /* Open the output file. */ | 513 /* Open the output file. */ |
505 #ifdef TWO_FILE_COMMANDLINE | 514 #ifdef TWO_FILE_COMMANDLINE |
506 /* Must have explicit output file name */ | 515 /* Must have explicit output file name */ |
507 if (argn != argc-2) { | 516 if (argn != argc-2) { |
508 fprintf(stderr, "%s: must name one input and one output file\n", | 517 fprintf(stderr, "%s: must name one input and one output file\n", |
509 » progname); | 518 progname); |
510 usage(); | 519 usage(); |
511 } | 520 } |
512 if ((outfile = fopen(argv[argn+1], WRITE_BINARY)) == NULL) { | 521 if ((outfile = fopen(argv[argn+1], WRITE_BINARY)) == NULL) { |
513 fprintf(stderr, "%s: can't open %s\n", progname, argv[argn+1]); | 522 fprintf(stderr, "%s: can't open %s\n", progname, argv[argn+1]); |
514 exit(EXIT_FAILURE); | 523 exit(EXIT_FAILURE); |
515 } | 524 } |
516 #else | 525 #else |
517 /* Unix style: expect zero or one file name */ | 526 /* Unix style: expect zero or one file name */ |
518 if (argn < argc-1) { | 527 if (argn < argc-1) { |
519 fprintf(stderr, "%s: only one input file\n", progname); | 528 fprintf(stderr, "%s: only one input file\n", progname); |
520 usage(); | 529 usage(); |
521 } | 530 } |
522 /* default output file is stdout */ | 531 /* default output file is stdout */ |
523 #ifdef USE_SETMODE» » /* need to hack file mode? */ | 532 #ifdef USE_SETMODE /* need to hack file mode? */ |
524 setmode(fileno(stdout), O_BINARY); | 533 setmode(fileno(stdout), O_BINARY); |
525 #endif | 534 #endif |
526 #ifdef USE_FDOPEN» » /* need to re-open in binary mode? */ | 535 #ifdef USE_FDOPEN /* need to re-open in binary mode? */ |
527 if ((outfile = fdopen(fileno(stdout), WRITE_BINARY)) == NULL) { | 536 if ((outfile = fdopen(fileno(stdout), WRITE_BINARY)) == NULL) { |
528 fprintf(stderr, "%s: can't open stdout\n", progname); | 537 fprintf(stderr, "%s: can't open stdout\n", progname); |
529 exit(EXIT_FAILURE); | 538 exit(EXIT_FAILURE); |
530 } | 539 } |
531 #else | 540 #else |
532 outfile = stdout; | 541 outfile = stdout; |
533 #endif | 542 #endif |
534 #endif /* TWO_FILE_COMMANDLINE */ | 543 #endif /* TWO_FILE_COMMANDLINE */ |
535 | 544 |
536 /* Collect comment text from comment_file or stdin, if necessary */ | 545 /* Collect comment text from comment_file or stdin, if necessary */ |
537 if (comment_arg == NULL) { | 546 if (comment_arg == NULL) { |
538 FILE * src_file; | 547 FILE *src_file; |
539 int c; | 548 int c; |
540 | 549 |
541 comment_arg = (char *) malloc((size_t) MAX_COM_LENGTH); | 550 comment_arg = (char *) malloc((size_t) MAX_COM_LENGTH); |
542 if (comment_arg == NULL) | 551 if (comment_arg == NULL) |
543 ERREXIT("Insufficient memory"); | 552 ERREXIT("Insufficient memory"); |
544 comment_length = 0; | 553 comment_length = 0; |
545 src_file = (comment_file != NULL ? comment_file : stdin); | 554 src_file = (comment_file != NULL ? comment_file : stdin); |
546 while ((c = getc(src_file)) != EOF) { | 555 while ((c = getc(src_file)) != EOF) { |
547 if (comment_length >= (unsigned int) MAX_COM_LENGTH) { | 556 if (comment_length >= (unsigned int) MAX_COM_LENGTH) { |
548 » fprintf(stderr, "Comment text may not exceed %u bytes\n", | 557 fprintf(stderr, "Comment text may not exceed %u bytes\n", |
549 » » (unsigned int) MAX_COM_LENGTH); | 558 (unsigned int) MAX_COM_LENGTH); |
550 » exit(EXIT_FAILURE); | 559 exit(EXIT_FAILURE); |
551 } | 560 } |
552 comment_arg[comment_length++] = (char) c; | 561 comment_arg[comment_length++] = (char) c; |
553 } | 562 } |
554 if (comment_file != NULL) | 563 if (comment_file != NULL) |
555 fclose(comment_file); | 564 fclose(comment_file); |
556 } | 565 } |
557 | 566 |
558 /* Copy JPEG headers until SOFn marker; | 567 /* Copy JPEG headers until SOFn marker; |
559 * we will insert the new comment marker just before SOFn. | 568 * we will insert the new comment marker just before SOFn. |
560 * This (a) causes the new comment to appear after, rather than before, | 569 * This (a) causes the new comment to appear after, rather than before, |
(...skipping 11 matching lines...) Expand all Loading... |
572 } | 581 } |
573 } | 582 } |
574 /* Duplicate the remainder of the source file. | 583 /* Duplicate the remainder of the source file. |
575 * Note that any COM markers occuring after SOF will not be touched. | 584 * Note that any COM markers occuring after SOF will not be touched. |
576 */ | 585 */ |
577 write_marker(marker); | 586 write_marker(marker); |
578 copy_rest_of_file(); | 587 copy_rest_of_file(); |
579 | 588 |
580 /* All done. */ | 589 /* All done. */ |
581 exit(EXIT_SUCCESS); | 590 exit(EXIT_SUCCESS); |
582 return 0;» » » /* suppress no-return-value warnings */ | 591 return 0; /* suppress no-return-value warnings */ |
583 } | 592 } |
OLD | NEW |