"Fossies" - the Fresh Open Source Software Archive 
Member "littleutils-1.2.5/imageutils/jpgcom.c" (29 Oct 2021, 10795 Bytes) of package /linux/privat/littleutils-1.2.5.tar.lz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "jpgcom.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
1.2.4_vs_1.2.5.
1 /* jpgcom.c: print any comments present in the specified JPEG image files
2 *
3 * This program is a heavily-stripped version of the "rdjpgcom" program
4 * distributed with version 9 of the Indendent JPEG Group's software. The
5 * original version (along with a copy of the Indendent JPEG Group's README
6 * file) can be found in the directory orig/.
7 *
8 * Copyright (C) 1994-1997, Thomas G. Lane.
9 * Modified 2009 by Bill Allombert, Guido Vollbeding.
10 * This file is part of the Independent JPEG Group's software.
11 * For conditions of distribution and use, see the accompanying README file.
12 *
13 * This file contains a very simple stand-alone application that displays
14 * the text in COM (comment) markers in a JFIF file.
15 * This may be useful as an example of the minimum logic needed to parse
16 * JPEG markers.
17 *
18 * Modifications Copyright (C) 2004-2021 by Brian Lindholm. All rights
19 * reserved except as specified above.
20 */
21
22 #include <config.h>
23
24 #include <ctype.h> /* to declare isupper(), tolower() */
25 #include <limits.h> /* to determine PATH_MAX */
26 #ifdef HAVE_LOCALE_H
27 # include <locale.h> /* Bill Allombert: use locale for isprint */
28 #endif
29 #ifdef HAVE_STDIO_H
30 # include <stdio.h> /* other I/O functions */
31 #endif
32 #ifdef HAVE_STDLIB_H
33 # include <stdlib.h> /* other I/O functions */
34 #endif
35 #ifdef HAVE_STRING_H
36 # include <string.h> /* other I/O functions */
37 #endif
38
39 #ifdef HAVE_UNISTD_H
40 # include <unistd.h>
41 # define OPTEND -1
42 #else
43 # define OPTEND EOF
44 #endif
45 #ifdef HAVE_GETOPT_H
46 # include <getopt.h>
47 #endif
48
49 #ifdef __MINGW32__
50 extern int getopt (int argc, char * const *argv, const char *optstring);
51 extern char *optarg;
52 extern int optind;
53 #endif
54
55 #ifndef PATH_MAX
56 # define PATH_MAX 256
57 #endif
58
59 /*
60 * These macros are used to read the input file.
61 * To reuse this code in another application, you might need to change these.
62 */
63
64 static FILE * infile; /* input JPEG file */
65
66 /* Return next input byte, or EOF if no more */
67 #define NEXTBYTE() getc(infile)
68
69 /* Error handler */
70 #define ERREXIT(msg) { fprintf(stderr, "jpgcom error: %s\n", msg); return(EOF); }
71
72
73 /* Read one byte, testing for EOF */
74 static int
75 read_1_byte (void)
76 {
77 int c;
78
79 c = NEXTBYTE();
80 if (c == EOF)
81 ERREXIT("Premature EOF in JPEG file");
82 return c;
83 }
84
85 /* Read 2 bytes, convert to unsigned int */
86 /* All 2-byte quantities in JPEG markers are MSB first */
87 static unsigned int
88 read_2_bytes (void)
89 {
90 int c1, c2;
91
92 c1 = NEXTBYTE();
93 if (c1 == EOF)
94 ERREXIT("Premature EOF in JPEG file");
95 c2 = NEXTBYTE();
96 if (c2 == EOF)
97 ERREXIT("Premature EOF in JPEG file");
98 return (((unsigned int) c1) << 8) + ((unsigned int) c2);
99 }
100
101
102 /*
103 * JPEG markers consist of one or more 0xFF bytes, followed by a marker
104 * code byte (which is not an FF). Here are the marker codes of interest
105 * in this program. (See jdmarker.c for a more complete list.)
106 */
107
108 #define M_SOF0 0xC0 /* Start Of Frame N */
109 #define M_SOF1 0xC1 /* N indicates which compression process */
110 #define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */
111 #define M_SOF3 0xC3
112 #define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */
113 #define M_SOF6 0xC6
114 #define M_SOF7 0xC7
115 #define M_SOF9 0xC9
116 #define M_SOF10 0xCA
117 #define M_SOF11 0xCB
118 #define M_SOF13 0xCD
119 #define M_SOF14 0xCE
120 #define M_SOF15 0xCF
121 #define M_SOI 0xD8 /* Start Of Image (beginning of datastream) */
122 #define M_EOI 0xD9 /* End Of Image (end of datastream) */
123 #define M_SOS 0xDA /* Start Of Scan (begins compressed data) */
124 #define M_APP0 0xE0 /* Application-specific marker, type N */
125 #define M_APP12 0xEC /* (we don't bother to list all 16 APPn's) */
126 #define M_COM 0xFE /* COMment */
127
128
129 /*
130 * Find the next JPEG marker and return its marker code.
131 * We expect at least one FF byte, possibly more if the compressor used FFs
132 * to pad the file.
133 * There could also be non-FF garbage between markers. The treatment of such
134 * garbage is unspecified; we choose to skip over it but emit a warning msg.
135 * NB: this routine must not be used after seeing SOS marker, since it will
136 * not deal correctly with FF/00 sequences in the compressed image data...
137 */
138
139 static int
140 next_marker (void)
141 {
142 int c;
143 int discarded_bytes = 0;
144
145 /* Find 0xFF byte; count and skip any non-FFs. */
146 c = read_1_byte();
147 if (c == EOF)
148 return EOF;
149 while (c != 0xFF) {
150 discarded_bytes++;
151 c = read_1_byte();
152 if (c == EOF)
153 return EOF;
154 }
155 /* Get marker code byte, swallowing any duplicate FF bytes. Extra FFs
156 * are legal as pad bytes, so don't count them in discarded_bytes.
157 */
158 do {
159 c = read_1_byte();
160 if (c == EOF)
161 return EOF;
162 } while (c == 0xFF);
163
164 if (discarded_bytes != 0) {
165 fprintf(stderr, "jpgcom warning: garbage data found in JPEG file\n");
166 }
167
168 return c;
169 }
170
171
172 /*
173 * Read the initial marker, which should be SOI.
174 * For a JFIF file, the first two bytes of the file should be literally
175 * 0xFF M_SOI. To be more general, we could use next_marker, but if the
176 * input file weren't actually JPEG at all, next_marker might read the whole
177 * file and then return a misleading error message...
178 */
179
180 static int
181 first_marker (void)
182 {
183 int c1, c2;
184
185 c1 = NEXTBYTE();
186 if (c1 == EOF)
187 ERREXIT("Not a JPEG file");
188 c2 = NEXTBYTE();
189 if (c2 == EOF)
190 ERREXIT("Not a JPEG file");
191 if (c1 != 0xFF || c2 != M_SOI)
192 ERREXIT("Not a JPEG file");
193 return c2;
194 }
195
196
197 /*
198 * Most types of marker are followed by a variable-length parameter segment.
199 * This routine skips over the parameters for any marker we don't otherwise
200 * want to process.
201 * Note that we MUST skip the parameter segment explicitly in order not to
202 * be fooled by 0xFF bytes that might appear within the parameter segment;
203 * such bytes do NOT introduce new markers.
204 */
205
206 static int
207 skip_variable (void)
208 /* Skip over an unknown or uninteresting variable-length marker */
209 {
210 unsigned int length;
211 int rc;
212
213 /* Get the marker parameter length count */
214 length = read_2_bytes();
215 /* Length includes itself, so must be at least 2 */
216 if (length < 2)
217 ERREXIT("Erroneous JPEG marker length");
218 length -= 2;
219 /* Skip over the remaining bytes */
220 rc = fseek(infile, (long) length, 1);
221 if (rc < 0)
222 ERREXIT("Erroneous JPEG marker length");
223 return 0;
224 }
225
226
227 /*
228 * Process a COM marker.
229 * We want to print out the marker contents as legible text;
230 * we must guard against non-text junk and varying newline representations.
231 */
232
233 static int
234 process_COM (int raw)
235 {
236 unsigned int length;
237 int ch;
238
239 /* Bill Allombert: set locale properly for isprint */
240 #ifdef HAVE_LOCALE_H
241 setlocale(LC_CTYPE, "");
242 #endif
243
244 /* Get the marker parameter length count */
245 length = read_2_bytes();
246 /* Length includes itself, so must be at least 2 */
247 if (length < 2)
248 ERREXIT("Erroneous JPEG marker length");
249 length -= 2;
250
251 fprintf (stdout, "\t");
252 while (length > 0) {
253 ch = read_1_byte();
254 if (raw) {
255 putc(ch, stdout);
256 /* Emit the character in a readable form.
257 * Nonprintables are converted to hexidecimal form */
258 } else if (isprint(ch)) {
259 putc(ch, stdout);
260 } else if (ch != 0) {
261 fprintf(stdout, "[%02x]", (unsigned int) ch);
262 }
263 length--;
264 }
265
266 /* Bill Allombert: revert to C locale */
267 #ifdef HAVE_LOCALE_H
268 setlocale(LC_CTYPE, "C");
269 #endif
270 return 0;
271 }
272
273
274 /*
275 * Parse the marker stream until SOS or EOI is seen;
276 * display any COM markers.
277 * While the companion program wrjpgcom will always insert COM markers before
278 * SOFn, other implementations might not, so we scan to SOS before stopping.
279 */
280
281 static int
282 scan_JPEG_header (int raw)
283 {
284 int marker;
285 int rc = 0;
286
287 /* Expect SOI at start of file */
288 if (first_marker() != M_SOI)
289 ERREXIT("Expected SOI marker first");
290
291 /* Scan miscellaneous markers until we reach SOS. */
292 for (;;) {
293 marker = next_marker();
294 switch (marker) {
295 case M_SOS: /* stop before hitting compressed data */
296 return marker;
297
298 case M_EOI: /* in case it's a tables-only JPEG stream */
299 return marker;
300
301 case M_COM:
302 rc = process_COM(raw);
303 if (rc == EOF)
304 return EOF;
305 break;
306
307 case M_APP12:
308 fprintf (stdout, "APP12: ");
309 rc = process_COM(raw);
310 if (rc == EOF)
311 return EOF;
312 break;
313
314 default: /* Anything else just gets skipped */
315 rc = skip_variable(); /* we assume it has a parameter count... */
316 if (rc == EOF)
317 return EOF;
318 break;
319 }
320 } /* end loop */
321 return 0;
322 }
323
324
325 /*
326 * A simple help function.
327 */
328
329 static void
330 help (FILE *where)
331 {
332 fprintf (where,
333 "jpgcom " PACKAGE_VERSION "\n"
334 "usage: jpgcom [-f file_list] [-h(elp)] [-p(ipe)] [-r(aw)] infile...\n");
335 }
336
337 /*
338 * Print the filename along with any comments.
339 */
340
341 static void
342 print_com (char *filename, int raw)
343 {
344 if ((infile = fopen(filename, "rb")) == NULL)
345 fprintf(stderr, "jpgcom error: can't open %s\n", filename);
346 else {
347 fprintf(stdout, "%s", filename);
348 scan_JPEG_header(raw);
349 fprintf(stdout, "\n");
350 (void) fclose(infile);
351 }
352 }
353
354
355 /*
356 * The main program.
357 */
358
359 int
360 main (int argc, char **argv)
361 {
362 FILE *infile;
363 char filename[PATH_MAX], *listname, *newline, *rc;
364 int argn, opt, raw, use_file, use_pipe;
365
366 /* parse options */
367
368 listname = "";
369 use_file = 0;
370 use_pipe = 0;
371 raw = 0;
372 while ((opt = getopt(argc, argv, "f:hpr")) != OPTEND)
373 switch (opt) {
374 case 'f':
375 use_file = 1;
376 listname = optarg;
377 break;
378 case 'h':
379 help(stdout);
380 return 0;
381 case 'p':
382 use_pipe = 1;
383 break;
384 case 'r':
385 raw = 1;
386 break;
387 case '?':
388 help(stderr);
389 return 1;
390 }
391 if ((optind == argc) && (use_file == 0) && (use_pipe == 0)) {
392 help(stdout);
393 return 0;
394 }
395
396 /* process files in listed in file specified by -f option */
397
398 if (use_file) {
399 infile = fopen(listname, "r");
400 if (infile == NULL)
401 fprintf(stderr, "jpgcom error: can't open %s!\n", listname);
402 else {
403 while (!feof(infile)) {
404 rc = fgets(filename, PATH_MAX - 1, infile);
405 if (rc != NULL) {
406 newline = strchr (filename, '\n');
407 if (newline != NULL)
408 *newline = '\0';
409 if (strlen(filename) != 0)
410 print_com(filename, raw);
411 }
412 }
413 fclose(infile);
414 }
415 }
416
417 /* process files listed on stdin (i.e., the -p option) */
418
419 if (use_pipe)
420 while (!feof(stdin)) {
421 rc = fgets(filename, PATH_MAX - 1, stdin);
422 if (rc != NULL) {
423 newline = strchr (filename, '\n');
424 if (newline != NULL)
425 *newline = '\0';
426 if (strlen(filename) != 0)
427 print_com(filename, raw);
428 }
429 }
430
431 /* process files given in the argument list */
432
433 for (argn = 1; argn < argc; argn++)
434 print_com(argv[argn], raw);
435
436 /* All done. */
437
438 return 0;
439 }