Doxygen Source Code Documentation
Main Page Alphabetical List Data Structures File List Data Fields Globals Search
wrjpgcom.c
Go to the documentation of this file.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 }