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 }