00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #define JPEG_CJPEG_DJPEG
00015 #include "jinclude.h"
00016
00017 #ifndef HAVE_STDLIB_H
00018 extern void * malloc ();
00019 #endif
00020 #include <ctype.h>
00021 #ifdef USE_SETMODE
00022 #include <fcntl.h>
00023
00024 #include <io.h>
00025 #endif
00026
00027 #ifdef USE_CCOMMAND
00028 #ifdef __MWERKS__
00029 #include <SIOUX.h>
00030 #include <console.h>
00031 #endif
00032 #ifdef THINK_C
00033 #include <console.h>
00034 #endif
00035 #endif
00036
00037 #ifdef DONT_USE_B_MODE
00038 #define READ_BINARY "r"
00039 #define WRITE_BINARY "w"
00040 #else
00041 #ifdef VMS
00042 #define READ_BINARY "rb", "ctx=stm"
00043 #define WRITE_BINARY "wb", "ctx=stm"
00044 #else
00045 #define READ_BINARY "rb"
00046 #define WRITE_BINARY "wb"
00047 #endif
00048 #endif
00049
00050 #ifndef EXIT_FAILURE
00051 #define EXIT_FAILURE 1
00052 #endif
00053 #ifndef EXIT_SUCCESS
00054 #ifdef VMS
00055 #define EXIT_SUCCESS 1
00056 #else
00057 #define EXIT_SUCCESS 0
00058 #endif
00059 #endif
00060
00061
00062
00063
00064
00065 #ifndef MAX_COM_LENGTH
00066 #define MAX_COM_LENGTH 65000L
00067 #endif
00068
00069
00070
00071
00072
00073
00074
00075 static FILE * infile;
00076
00077
00078 #define NEXTBYTE() getc(infile)
00079
00080 static FILE * outfile;
00081
00082
00083 #define PUTBYTE(x) putc((x), outfile)
00084
00085
00086
00087 #define ERREXIT(msg) (fprintf(stderr, "%s\n", msg), exit(EXIT_FAILURE))
00088
00089
00090
00091 static int
00092 read_1_byte (void)
00093 {
00094 int c;
00095
00096 c = NEXTBYTE();
00097 if (c == EOF)
00098 ERREXIT("Premature EOF in JPEG file");
00099 return c;
00100 }
00101
00102
00103
00104 static unsigned int
00105 read_2_bytes (void)
00106 {
00107 int c1, c2;
00108
00109 c1 = NEXTBYTE();
00110 if (c1 == EOF)
00111 ERREXIT("Premature EOF in JPEG file");
00112 c2 = NEXTBYTE();
00113 if (c2 == EOF)
00114 ERREXIT("Premature EOF in JPEG file");
00115 return (((unsigned int) c1) << 8) + ((unsigned int) c2);
00116 }
00117
00118
00119
00120
00121 static void
00122 write_1_byte (int c)
00123 {
00124 PUTBYTE(c);
00125 }
00126
00127 static void
00128 write_2_bytes (unsigned int val)
00129 {
00130 PUTBYTE((val >> 8) & 0xFF);
00131 PUTBYTE(val & 0xFF);
00132 }
00133
00134 static void
00135 write_marker (int marker)
00136 {
00137 PUTBYTE(0xFF);
00138 PUTBYTE(marker);
00139 }
00140
00141 static void
00142 copy_rest_of_file (void)
00143 {
00144 int c;
00145
00146 while ((c = NEXTBYTE()) != EOF)
00147 PUTBYTE(c);
00148 }
00149
00150
00151
00152
00153
00154
00155
00156
00157 #define M_SOF0 0xC0
00158 #define M_SOF1 0xC1
00159 #define M_SOF2 0xC2
00160 #define M_SOF3 0xC3
00161 #define M_SOF5 0xC5
00162 #define M_SOF6 0xC6
00163 #define M_SOF7 0xC7
00164 #define M_SOF9 0xC9
00165 #define M_SOF10 0xCA
00166 #define M_SOF11 0xCB
00167 #define M_SOF13 0xCD
00168 #define M_SOF14 0xCE
00169 #define M_SOF15 0xCF
00170 #define M_SOI 0xD8
00171 #define M_EOI 0xD9
00172 #define M_SOS 0xDA
00173 #define M_COM 0xFE
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186 static int
00187 next_marker (void)
00188 {
00189 int c;
00190 int discarded_bytes = 0;
00191
00192
00193 c = read_1_byte();
00194 while (c != 0xFF) {
00195 discarded_bytes++;
00196 c = read_1_byte();
00197 }
00198
00199
00200
00201 do {
00202 c = read_1_byte();
00203 } while (c == 0xFF);
00204
00205 if (discarded_bytes != 0) {
00206 fprintf(stderr, "Warning: garbage data found in JPEG file\n");
00207 }
00208
00209 return c;
00210 }
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221 static int
00222 first_marker (void)
00223 {
00224 int c1, c2;
00225
00226 c1 = NEXTBYTE();
00227 c2 = NEXTBYTE();
00228 if (c1 != 0xFF || c2 != M_SOI)
00229 ERREXIT("Not a JPEG file");
00230 return c2;
00231 }
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243 static void
00244 copy_variable (void)
00245
00246 {
00247 unsigned int length;
00248
00249
00250 length = read_2_bytes();
00251 write_2_bytes(length);
00252
00253 if (length < 2)
00254 ERREXIT("Erroneous JPEG marker length");
00255 length -= 2;
00256
00257 while (length > 0) {
00258 write_1_byte(read_1_byte());
00259 length--;
00260 }
00261 }
00262
00263 static void
00264 skip_variable (void)
00265
00266 {
00267 unsigned int length;
00268
00269
00270 length = read_2_bytes();
00271
00272 if (length < 2)
00273 ERREXIT("Erroneous JPEG marker length");
00274 length -= 2;
00275
00276 while (length > 0) {
00277 (void) read_1_byte();
00278 length--;
00279 }
00280 }
00281
00282
00283
00284
00285
00286
00287
00288 static int
00289 scan_JPEG_header (int keep_COM)
00290 {
00291 int marker;
00292
00293
00294 if (first_marker() != M_SOI)
00295 ERREXIT("Expected SOI marker first");
00296 write_marker(M_SOI);
00297
00298
00299 for (;;) {
00300 marker = next_marker();
00301 switch (marker) {
00302
00303
00304
00305 case M_SOF0:
00306 case M_SOF1:
00307 case M_SOF2:
00308 case M_SOF3:
00309 case M_SOF5:
00310 case M_SOF6:
00311 case M_SOF7:
00312 case M_SOF9:
00313 case M_SOF10:
00314 case M_SOF11:
00315 case M_SOF13:
00316 case M_SOF14:
00317 case M_SOF15:
00318 return marker;
00319
00320 case M_SOS:
00321 ERREXIT("SOS without prior SOFn");
00322 break;
00323
00324 case M_EOI:
00325 return marker;
00326
00327 case M_COM:
00328 if (keep_COM) {
00329 write_marker(marker);
00330 copy_variable();
00331 } else {
00332 skip_variable();
00333 }
00334 break;
00335
00336 default:
00337 write_marker(marker);
00338 copy_variable();
00339 break;
00340 }
00341 }
00342 }
00343
00344
00345
00346
00347 static const char * progname;
00348
00349
00350 static void
00351 usage (void)
00352
00353 {
00354 fprintf(stderr, "wrjpgcom inserts a textual comment in a JPEG file.\n");
00355 fprintf(stderr, "You can add to or replace any existing comment(s).\n");
00356
00357 fprintf(stderr, "Usage: %s [switches] ", progname);
00358 #ifdef TWO_FILE_COMMANDLINE
00359 fprintf(stderr, "inputfile outputfile\n");
00360 #else
00361 fprintf(stderr, "[inputfile]\n");
00362 #endif
00363
00364 fprintf(stderr, "Switches (names may be abbreviated):\n");
00365 fprintf(stderr, " -replace Delete any existing comments\n");
00366 fprintf(stderr, " -comment \"text\" Insert comment with given text\n");
00367 fprintf(stderr, " -cfile name Read comment from named file\n");
00368 fprintf(stderr, "Notice that you must put quotes around the comment text\n");
00369 fprintf(stderr, "when you use -comment.\n");
00370 fprintf(stderr, "If you do not give either -comment or -cfile on the command line,\n");
00371 fprintf(stderr, "then the comment text is read from standard input.\n");
00372 fprintf(stderr, "It can be multiple lines, up to %u characters total.\n",
00373 (unsigned int) MAX_COM_LENGTH);
00374 #ifndef TWO_FILE_COMMANDLINE
00375 fprintf(stderr, "You must specify an input JPEG file name when supplying\n");
00376 fprintf(stderr, "comment text from standard input.\n");
00377 #endif
00378
00379 exit(EXIT_FAILURE);
00380 }
00381
00382
00383 static int
00384 keymatch (char * arg, const char * keyword, int minchars)
00385
00386
00387
00388 {
00389 register int ca, ck;
00390 register int nmatched = 0;
00391
00392 while ((ca = *arg++) != '\0') {
00393 if ((ck = *keyword++) == '\0')
00394 return 0;
00395 if (isupper(ca))
00396 ca = tolower(ca);
00397 if (ca != ck)
00398 return 0;
00399 nmatched++;
00400 }
00401
00402 if (nmatched < minchars)
00403 return 0;
00404 return 1;
00405 }
00406
00407
00408
00409
00410
00411
00412 int
00413 main (int argc, char **argv)
00414 {
00415 int argn;
00416 char * arg;
00417 int keep_COM = 1;
00418 char * comment_arg = NULL;
00419 FILE * comment_file = NULL;
00420 unsigned int comment_length = 0;
00421 int marker;
00422
00423
00424 #ifdef USE_CCOMMAND
00425 argc = ccommand(&argv);
00426 #endif
00427
00428 progname = argv[0];
00429 if (progname == NULL || progname[0] == 0)
00430 progname = "wrjpgcom";
00431
00432
00433 for (argn = 1; argn < argc; argn++) {
00434 arg = argv[argn];
00435 if (arg[0] != '-')
00436 break;
00437 arg++;
00438 if (keymatch(arg, "replace", 1)) {
00439 keep_COM = 0;
00440 } else if (keymatch(arg, "cfile", 2)) {
00441 if (++argn >= argc) usage();
00442 if ((comment_file = fopen(argv[argn], "r")) == NULL) {
00443 fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]);
00444 exit(EXIT_FAILURE);
00445 }
00446 } else if (keymatch(arg, "comment", 1)) {
00447 if (++argn >= argc) usage();
00448 comment_arg = argv[argn];
00449
00450
00451
00452 if (comment_arg[0] == '"') {
00453 comment_arg = (char *) malloc((size_t) MAX_COM_LENGTH);
00454 if (comment_arg == NULL)
00455 ERREXIT("Insufficient memory");
00456 strcpy(comment_arg, argv[argn]+1);
00457 for (;;) {
00458 comment_length = (unsigned int) strlen(comment_arg);
00459 if (comment_length > 0 && comment_arg[comment_length-1] == '"') {
00460 comment_arg[comment_length-1] = '\0';
00461 break;
00462 }
00463 if (++argn >= argc)
00464 ERREXIT("Missing ending quote mark");
00465 strcat(comment_arg, " ");
00466 strcat(comment_arg, argv[argn]);
00467 }
00468 }
00469 comment_length = (unsigned int) strlen(comment_arg);
00470 } else
00471 usage();
00472 }
00473
00474
00475 if (comment_arg != NULL && comment_file != NULL)
00476 usage();
00477
00478
00479
00480 if (comment_arg == NULL && comment_file == NULL && argn >= argc)
00481 usage();
00482
00483
00484 if (argn < argc) {
00485 if ((infile = fopen(argv[argn], READ_BINARY)) == NULL) {
00486 fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]);
00487 exit(EXIT_FAILURE);
00488 }
00489 } else {
00490
00491 #ifdef USE_SETMODE
00492 setmode(fileno(stdin), O_BINARY);
00493 #endif
00494 #ifdef USE_FDOPEN
00495 if ((infile = fdopen(fileno(stdin), READ_BINARY)) == NULL) {
00496 fprintf(stderr, "%s: can't open stdin\n", progname);
00497 exit(EXIT_FAILURE);
00498 }
00499 #else
00500 infile = stdin;
00501 #endif
00502 }
00503
00504
00505 #ifdef TWO_FILE_COMMANDLINE
00506
00507 if (argn != argc-2) {
00508 fprintf(stderr, "%s: must name one input and one output file\n",
00509 progname);
00510 usage();
00511 }
00512 if ((outfile = fopen(argv[argn+1], WRITE_BINARY)) == NULL) {
00513 fprintf(stderr, "%s: can't open %s\n", progname, argv[argn+1]);
00514 exit(EXIT_FAILURE);
00515 }
00516 #else
00517
00518 if (argn < argc-1) {
00519 fprintf(stderr, "%s: only one input file\n", progname);
00520 usage();
00521 }
00522
00523 #ifdef USE_SETMODE
00524 setmode(fileno(stdout), O_BINARY);
00525 #endif
00526 #ifdef USE_FDOPEN
00527 if ((outfile = fdopen(fileno(stdout), WRITE_BINARY)) == NULL) {
00528 fprintf(stderr, "%s: can't open stdout\n", progname);
00529 exit(EXIT_FAILURE);
00530 }
00531 #else
00532 outfile = stdout;
00533 #endif
00534 #endif
00535
00536
00537 if (comment_arg == NULL) {
00538 FILE * src_file;
00539 int c;
00540
00541 comment_arg = (char *) malloc((size_t) MAX_COM_LENGTH);
00542 if (comment_arg == NULL)
00543 ERREXIT("Insufficient memory");
00544 comment_length = 0;
00545 src_file = (comment_file != NULL ? comment_file : stdin);
00546 while ((c = getc(src_file)) != EOF) {
00547 if (comment_length >= (unsigned int) MAX_COM_LENGTH) {
00548 fprintf(stderr, "Comment text may not exceed %u bytes\n",
00549 (unsigned int) MAX_COM_LENGTH);
00550 exit(EXIT_FAILURE);
00551 }
00552 comment_arg[comment_length++] = (char) c;
00553 }
00554 if (comment_file != NULL)
00555 fclose(comment_file);
00556 }
00557
00558
00559
00560
00561
00562
00563
00564 marker = scan_JPEG_header(keep_COM);
00565
00566 if (comment_length > 0) {
00567 write_marker(M_COM);
00568 write_2_bytes(comment_length + 2);
00569 while (comment_length > 0) {
00570 write_1_byte(*comment_arg++);
00571 comment_length--;
00572 }
00573 }
00574
00575
00576
00577 write_marker(marker);
00578 copy_rest_of_file();
00579
00580
00581 exit(EXIT_SUCCESS);
00582 return 0;
00583 }