00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #define JPEG_CJPEG_DJPEG
00016 #include "jinclude.h"
00017
00018 #ifdef HAVE_LOCALE_H
00019 #include <locale.h>
00020 #endif
00021 #include <ctype.h>
00022 #ifdef USE_SETMODE
00023 #include <fcntl.h>
00024
00025 #include <io.h>
00026 #endif
00027
00028 #ifdef USE_CCOMMAND
00029 #ifdef __MWERKS__
00030 #include <SIOUX.h>
00031 #include <console.h>
00032 #endif
00033 #ifdef THINK_C
00034 #include <console.h>
00035 #endif
00036 #endif
00037
00038 #ifdef DONT_USE_B_MODE
00039 #define READ_BINARY "r"
00040 #else
00041 #ifdef VMS
00042 #define READ_BINARY "rb", "ctx=stm"
00043 #else
00044 #define READ_BINARY "rb"
00045 #endif
00046 #endif
00047
00048 #ifndef EXIT_FAILURE
00049 #define EXIT_FAILURE 1
00050 #endif
00051 #ifndef EXIT_SUCCESS
00052 #ifdef VMS
00053 #define EXIT_SUCCESS 1
00054 #else
00055 #define EXIT_SUCCESS 0
00056 #endif
00057 #endif
00058
00059
00060
00061
00062
00063
00064
00065 static FILE * infile;
00066
00067
00068 #define NEXTBYTE() getc(infile)
00069
00070
00071
00072 #define ERREXIT(msg) (fprintf(stderr, "%s\n", msg), exit(EXIT_FAILURE))
00073
00074
00075
00076 static int
00077 read_1_byte (void)
00078 {
00079 int c;
00080
00081 c = NEXTBYTE();
00082 if (c == EOF)
00083 ERREXIT("Premature EOF in JPEG file");
00084 return c;
00085 }
00086
00087
00088
00089 static unsigned int
00090 read_2_bytes (void)
00091 {
00092 int c1, c2;
00093
00094 c1 = NEXTBYTE();
00095 if (c1 == EOF)
00096 ERREXIT("Premature EOF in JPEG file");
00097 c2 = NEXTBYTE();
00098 if (c2 == EOF)
00099 ERREXIT("Premature EOF in JPEG file");
00100 return (((unsigned int) c1) << 8) + ((unsigned int) c2);
00101 }
00102
00103
00104
00105
00106
00107
00108
00109
00110 #define M_SOF0 0xC0
00111 #define M_SOF1 0xC1
00112 #define M_SOF2 0xC2
00113 #define M_SOF3 0xC3
00114 #define M_SOF5 0xC5
00115 #define M_SOF6 0xC6
00116 #define M_SOF7 0xC7
00117 #define M_SOF9 0xC9
00118 #define M_SOF10 0xCA
00119 #define M_SOF11 0xCB
00120 #define M_SOF13 0xCD
00121 #define M_SOF14 0xCE
00122 #define M_SOF15 0xCF
00123 #define M_SOI 0xD8
00124 #define M_EOI 0xD9
00125 #define M_SOS 0xDA
00126 #define M_APP0 0xE0
00127 #define M_APP12 0xEC
00128 #define M_COM 0xFE
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141 static int
00142 next_marker (void)
00143 {
00144 int c;
00145 int discarded_bytes = 0;
00146
00147
00148 c = read_1_byte();
00149 while (c != 0xFF) {
00150 discarded_bytes++;
00151 c = read_1_byte();
00152 }
00153
00154
00155
00156 do {
00157 c = read_1_byte();
00158 } while (c == 0xFF);
00159
00160 if (discarded_bytes != 0) {
00161 fprintf(stderr, "Warning: garbage data found in JPEG file\n");
00162 }
00163
00164 return c;
00165 }
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176 static int
00177 first_marker (void)
00178 {
00179 int c1, c2;
00180
00181 c1 = NEXTBYTE();
00182 c2 = NEXTBYTE();
00183 if (c1 != 0xFF || c2 != M_SOI)
00184 ERREXIT("Not a JPEG file");
00185 return c2;
00186 }
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198 static void
00199 skip_variable (void)
00200
00201 {
00202 unsigned int length;
00203
00204
00205 length = read_2_bytes();
00206
00207 if (length < 2)
00208 ERREXIT("Erroneous JPEG marker length");
00209 length -= 2;
00210
00211 while (length > 0) {
00212 (void) read_1_byte();
00213 length--;
00214 }
00215 }
00216
00217
00218
00219
00220
00221
00222
00223
00224 static void
00225 process_COM (int raw)
00226 {
00227 unsigned int length;
00228 int ch;
00229 int lastch = 0;
00230
00231
00232 #ifdef HAVE_LOCALE_H
00233 setlocale(LC_CTYPE, "");
00234 #endif
00235
00236
00237 length = read_2_bytes();
00238
00239 if (length < 2)
00240 ERREXIT("Erroneous JPEG marker length");
00241 length -= 2;
00242
00243 while (length > 0) {
00244 ch = read_1_byte();
00245 if (raw) {
00246 putc(ch, stdout);
00247
00248
00249
00250
00251
00252 } else if (ch == '\r') {
00253 printf("\n");
00254 } else if (ch == '\n') {
00255 if (lastch != '\r')
00256 printf("\n");
00257 } else if (ch == '\\') {
00258 printf("\\\\");
00259 } else if (isprint(ch)) {
00260 putc(ch, stdout);
00261 } else {
00262 printf("\\%03o", ch);
00263 }
00264 lastch = ch;
00265 length--;
00266 }
00267 printf("\n");
00268
00269
00270 #ifdef HAVE_LOCALE_H
00271 setlocale(LC_CTYPE, "C");
00272 #endif
00273 }
00274
00275
00276
00277
00278
00279
00280
00281 static void
00282 process_SOFn (int marker)
00283 {
00284 unsigned int length;
00285 unsigned int image_height, image_width;
00286 int data_precision, num_components;
00287 const char * process;
00288 int ci;
00289
00290 length = read_2_bytes();
00291
00292 data_precision = read_1_byte();
00293 image_height = read_2_bytes();
00294 image_width = read_2_bytes();
00295 num_components = read_1_byte();
00296
00297 switch (marker) {
00298 case M_SOF0: process = "Baseline"; break;
00299 case M_SOF1: process = "Extended sequential"; break;
00300 case M_SOF2: process = "Progressive"; break;
00301 case M_SOF3: process = "Lossless"; break;
00302 case M_SOF5: process = "Differential sequential"; break;
00303 case M_SOF6: process = "Differential progressive"; break;
00304 case M_SOF7: process = "Differential lossless"; break;
00305 case M_SOF9: process = "Extended sequential, arithmetic coding"; break;
00306 case M_SOF10: process = "Progressive, arithmetic coding"; break;
00307 case M_SOF11: process = "Lossless, arithmetic coding"; break;
00308 case M_SOF13: process = "Differential sequential, arithmetic coding"; break;
00309 case M_SOF14: process = "Differential progressive, arithmetic coding"; break;
00310 case M_SOF15: process = "Differential lossless, arithmetic coding"; break;
00311 default: process = "Unknown"; break;
00312 }
00313
00314 printf("JPEG image is %uw * %uh, %d color components, %d bits per sample\n",
00315 image_width, image_height, num_components, data_precision);
00316 printf("JPEG process: %s\n", process);
00317
00318 if (length != (unsigned int) (8 + num_components * 3))
00319 ERREXIT("Bogus SOF marker length");
00320
00321 for (ci = 0; ci < num_components; ci++) {
00322 (void) read_1_byte();
00323 (void) read_1_byte();
00324 (void) read_1_byte();
00325 }
00326 }
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339 static int
00340 scan_JPEG_header (int verbose, int raw)
00341 {
00342 int marker;
00343
00344
00345 if (first_marker() != M_SOI)
00346 ERREXIT("Expected SOI marker first");
00347
00348
00349 for (;;) {
00350 marker = next_marker();
00351 switch (marker) {
00352
00353
00354
00355 case M_SOF0:
00356 case M_SOF1:
00357 case M_SOF2:
00358 case M_SOF3:
00359 case M_SOF5:
00360 case M_SOF6:
00361 case M_SOF7:
00362 case M_SOF9:
00363 case M_SOF10:
00364 case M_SOF11:
00365 case M_SOF13:
00366 case M_SOF14:
00367 case M_SOF15:
00368 if (verbose)
00369 process_SOFn(marker);
00370 else
00371 skip_variable();
00372 break;
00373
00374 case M_SOS:
00375 return marker;
00376
00377 case M_EOI:
00378 return marker;
00379
00380 case M_COM:
00381 process_COM(raw);
00382 break;
00383
00384 case M_APP12:
00385
00386
00387
00388 if (verbose) {
00389 printf("APP12 contains:\n");
00390 process_COM(raw);
00391 } else
00392 skip_variable();
00393 break;
00394
00395 default:
00396 skip_variable();
00397 break;
00398 }
00399 }
00400 }
00401
00402
00403
00404
00405 static const char * progname;
00406
00407
00408 static void
00409 usage (void)
00410
00411 {
00412 fprintf(stderr, "rdjpgcom displays any textual comments in a JPEG file.\n");
00413
00414 fprintf(stderr, "Usage: %s [switches] [inputfile]\n", progname);
00415
00416 fprintf(stderr, "Switches (names may be abbreviated):\n");
00417 fprintf(stderr, " -raw Display non-printable characters in comments (unsafe)\n");
00418 fprintf(stderr, " -verbose Also display dimensions of JPEG image\n");
00419
00420 exit(EXIT_FAILURE);
00421 }
00422
00423
00424 static int
00425 keymatch (char * arg, const char * keyword, int minchars)
00426
00427
00428
00429 {
00430 register int ca, ck;
00431 register int nmatched = 0;
00432
00433 while ((ca = *arg++) != '\0') {
00434 if ((ck = *keyword++) == '\0')
00435 return 0;
00436 if (isupper(ca))
00437 ca = tolower(ca);
00438 if (ca != ck)
00439 return 0;
00440 nmatched++;
00441 }
00442
00443 if (nmatched < minchars)
00444 return 0;
00445 return 1;
00446 }
00447
00448
00449
00450
00451
00452
00453 int
00454 main (int argc, char **argv)
00455 {
00456 int argn;
00457 char * arg;
00458 int verbose = 0, raw = 0;
00459
00460
00461 #ifdef USE_CCOMMAND
00462 argc = ccommand(&argv);
00463 #endif
00464
00465 progname = argv[0];
00466 if (progname == NULL || progname[0] == 0)
00467 progname = "rdjpgcom";
00468
00469
00470 for (argn = 1; argn < argc; argn++) {
00471 arg = argv[argn];
00472 if (arg[0] != '-')
00473 break;
00474 arg++;
00475 if (keymatch(arg, "verbose", 1)) {
00476 verbose++;
00477 } else if (keymatch(arg, "raw", 1)) {
00478 raw = 1;
00479 } else
00480 usage();
00481 }
00482
00483
00484
00485 if (argn < argc-1) {
00486 fprintf(stderr, "%s: only one input file\n", progname);
00487 usage();
00488 }
00489 if (argn < argc) {
00490 if ((infile = fopen(argv[argn], READ_BINARY)) == NULL) {
00491 fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]);
00492 exit(EXIT_FAILURE);
00493 }
00494 } else {
00495
00496 #ifdef USE_SETMODE
00497 setmode(fileno(stdin), O_BINARY);
00498 #endif
00499 #ifdef USE_FDOPEN
00500 if ((infile = fdopen(fileno(stdin), READ_BINARY)) == NULL) {
00501 fprintf(stderr, "%s: can't open stdin\n", progname);
00502 exit(EXIT_FAILURE);
00503 }
00504 #else
00505 infile = stdin;
00506 #endif
00507 }
00508
00509
00510 (void) scan_JPEG_header(verbose, raw);
00511
00512
00513 exit(EXIT_SUCCESS);
00514 return 0;
00515 }