170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/*
270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * rdjpgcom.c
370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine *
470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * Copyright (C) 1994-1997, Thomas G. Lane.
570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * This file is part of the Independent JPEG Group's software.
670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * For conditions of distribution and use, see the accompanying README file.
770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine *
870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * This file contains a very simple stand-alone application that displays
970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * the text in COM (comment) markers in a JFIF file.
1070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * This may be useful as an example of the minimum logic needed to parse
1170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * JPEG markers.
1270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine */
1370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
1470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define JPEG_CJPEG_DJPEG	/* to get the command-line config symbols */
1570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#include "jinclude.h"		/* get auto-config symbols, <stdio.h> */
1670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
1770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#include <ctype.h>		/* to declare isupper(), tolower() */
1870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#ifdef USE_SETMODE
1970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#include <fcntl.h>		/* to declare setmode()'s parameter macros */
2070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* If you have setmode() but not <io.h>, just delete this line: */
2170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#include <io.h>			/* to declare setmode() */
2270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#endif
2370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
2470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#ifdef USE_CCOMMAND		/* command-line reader for Macintosh */
2570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#ifdef __MWERKS__
2670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#include <SIOUX.h>              /* Metrowerks needs this */
2770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#include <console.h>		/* ... and this */
2870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#endif
2970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#ifdef THINK_C
3070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#include <console.h>		/* Think declares it here */
3170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#endif
3270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#endif
3370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
3470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#ifdef DONT_USE_B_MODE		/* define mode parameters for fopen() */
3570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define READ_BINARY	"r"
3670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#else
3770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#ifdef VMS			/* VMS is very nonstandard */
3870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define READ_BINARY	"rb", "ctx=stm"
3970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#else				/* standard ANSI-compliant case */
4070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define READ_BINARY	"rb"
4170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#endif
4270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#endif
4370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
4470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#ifndef EXIT_FAILURE		/* define exit() codes if not provided */
4570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define EXIT_FAILURE  1
4670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#endif
4770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#ifndef EXIT_SUCCESS
4870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#ifdef VMS
4970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define EXIT_SUCCESS  1		/* VMS is very nonstandard */
5070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#else
5170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define EXIT_SUCCESS  0
5270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#endif
5370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#endif
5470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
5570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
5670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/*
5770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * These macros are used to read the input file.
5870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * To reuse this code in another application, you might need to change these.
5970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine */
6070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
6170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinestatic FILE * infile;		/* input JPEG file */
6270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
6370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* Return next input byte, or EOF if no more */
6470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define NEXTBYTE()  getc(infile)
6570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
6670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
6770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* Error exit handler */
6870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define ERREXIT(msg)  (fprintf(stderr, "%s\n", msg), exit(EXIT_FAILURE))
6970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
7070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
7170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* Read one byte, testing for EOF */
7270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinestatic int
7370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkineread_1_byte (void)
7470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine{
7570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  int c;
7670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
7770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  c = NEXTBYTE();
7870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  if (c == EOF)
7970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    ERREXIT("Premature EOF in JPEG file");
8070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  return c;
8170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine}
8270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
8370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* Read 2 bytes, convert to unsigned int */
8470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* All 2-byte quantities in JPEG markers are MSB first */
8570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinestatic unsigned int
8670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkineread_2_bytes (void)
8770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine{
8870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  int c1, c2;
8970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
9070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  c1 = NEXTBYTE();
9170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  if (c1 == EOF)
9270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    ERREXIT("Premature EOF in JPEG file");
9370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  c2 = NEXTBYTE();
9470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  if (c2 == EOF)
9570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    ERREXIT("Premature EOF in JPEG file");
9670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  return (((unsigned int) c1) << 8) + ((unsigned int) c2);
9770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine}
9870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
9970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
10070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/*
10170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * JPEG markers consist of one or more 0xFF bytes, followed by a marker
10270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * code byte (which is not an FF).  Here are the marker codes of interest
10370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * in this program.  (See jdmarker.c for a more complete list.)
10470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine */
10570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
10670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_SOF0  0xC0		/* Start Of Frame N */
10770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_SOF1  0xC1		/* N indicates which compression process */
10870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_SOF2  0xC2		/* Only SOF0-SOF2 are now in common use */
10970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_SOF3  0xC3
11070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_SOF5  0xC5		/* NB: codes C4 and CC are NOT SOF markers */
11170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_SOF6  0xC6
11270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_SOF7  0xC7
11370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_SOF9  0xC9
11470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_SOF10 0xCA
11570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_SOF11 0xCB
11670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_SOF13 0xCD
11770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_SOF14 0xCE
11870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_SOF15 0xCF
11970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_SOI   0xD8		/* Start Of Image (beginning of datastream) */
12070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_EOI   0xD9		/* End Of Image (end of datastream) */
12170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_SOS   0xDA		/* Start Of Scan (begins compressed data) */
12270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_APP0	0xE0		/* Application-specific marker, type N */
12370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_APP12	0xEC		/* (we don't bother to list all 16 APPn's) */
12470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_COM   0xFE		/* COMment */
12570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
12670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
12770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/*
12870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * Find the next JPEG marker and return its marker code.
12970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * We expect at least one FF byte, possibly more if the compressor used FFs
13070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * to pad the file.
13170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * There could also be non-FF garbage between markers.  The treatment of such
13270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * garbage is unspecified; we choose to skip over it but emit a warning msg.
13370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * NB: this routine must not be used after seeing SOS marker, since it will
13470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * not deal correctly with FF/00 sequences in the compressed image data...
13570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine */
13670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
13770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinestatic int
13870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinenext_marker (void)
13970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine{
14070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  int c;
14170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  int discarded_bytes = 0;
14270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
14370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  /* Find 0xFF byte; count and skip any non-FFs. */
14470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  c = read_1_byte();
14570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  while (c != 0xFF) {
14670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    discarded_bytes++;
14770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    c = read_1_byte();
14870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  }
14970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  /* Get marker code byte, swallowing any duplicate FF bytes.  Extra FFs
15070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine   * are legal as pad bytes, so don't count them in discarded_bytes.
15170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine   */
15270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  do {
15370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    c = read_1_byte();
15470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  } while (c == 0xFF);
15570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
15670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  if (discarded_bytes != 0) {
15770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    fprintf(stderr, "Warning: garbage data found in JPEG file\n");
15870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  }
15970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
16070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  return c;
16170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine}
16270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
16370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
16470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/*
16570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * Read the initial marker, which should be SOI.
16670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * For a JFIF file, the first two bytes of the file should be literally
16770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * 0xFF M_SOI.  To be more general, we could use next_marker, but if the
16870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * input file weren't actually JPEG at all, next_marker might read the whole
16970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * file and then return a misleading error message...
17070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine */
17170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
17270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinestatic int
17370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinefirst_marker (void)
17470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine{
17570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  int c1, c2;
17670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
17770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  c1 = NEXTBYTE();
17870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  c2 = NEXTBYTE();
17970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  if (c1 != 0xFF || c2 != M_SOI)
18070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    ERREXIT("Not a JPEG file");
18170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  return c2;
18270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine}
18370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
18470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
18570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/*
18670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * Most types of marker are followed by a variable-length parameter segment.
18770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * This routine skips over the parameters for any marker we don't otherwise
18870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * want to process.
18970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * Note that we MUST skip the parameter segment explicitly in order not to
19070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * be fooled by 0xFF bytes that might appear within the parameter segment;
19170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * such bytes do NOT introduce new markers.
19270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine */
19370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
19470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinestatic void
19570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkineskip_variable (void)
19670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* Skip over an unknown or uninteresting variable-length marker */
19770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine{
19870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  unsigned int length;
19970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
20070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  /* Get the marker parameter length count */
20170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  length = read_2_bytes();
20270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  /* Length includes itself, so must be at least 2 */
20370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  if (length < 2)
20470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    ERREXIT("Erroneous JPEG marker length");
20570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  length -= 2;
20670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  /* Skip over the remaining bytes */
20770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  while (length > 0) {
20870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    (void) read_1_byte();
20970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    length--;
21070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  }
21170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine}
21270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
21370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
21470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/*
21570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * Process a COM marker.
21670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * We want to print out the marker contents as legible text;
21770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * we must guard against non-text junk and varying newline representations.
21870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine */
21970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
22070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinestatic void
22170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkineprocess_COM (void)
22270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine{
22370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  unsigned int length;
22470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  int ch;
22570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  int lastch = 0;
22670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
22770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  /* Get the marker parameter length count */
22870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  length = read_2_bytes();
22970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  /* Length includes itself, so must be at least 2 */
23070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  if (length < 2)
23170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    ERREXIT("Erroneous JPEG marker length");
23270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  length -= 2;
23370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
23470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  while (length > 0) {
23570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    ch = read_1_byte();
23670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    /* Emit the character in a readable form.
23770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine     * Nonprintables are converted to \nnn form,
23870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine     * while \ is converted to \\.
23970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine     * Newlines in CR, CR/LF, or LF form will be printed as one newline.
24070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine     */
24170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    if (ch == '\r') {
24270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine      printf("\n");
24370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    } else if (ch == '\n') {
24470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine      if (lastch != '\r')
24570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine	printf("\n");
24670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    } else if (ch == '\\') {
24770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine      printf("\\\\");
24870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    } else if (isprint(ch)) {
24970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine      putc(ch, stdout);
25070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    } else {
25170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine      printf("\\%03o", ch);
25270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    }
25370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    lastch = ch;
25470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    length--;
25570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  }
25670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  printf("\n");
25770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine}
25870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
25970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
26070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/*
26170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * Process a SOFn marker.
26270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * This code is only needed if you want to know the image dimensions...
26370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine */
26470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
26570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinestatic void
26670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkineprocess_SOFn (int marker)
26770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine{
26870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  unsigned int length;
26970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  unsigned int image_height, image_width;
27070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  int data_precision, num_components;
27170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  const char * process;
27270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  int ci;
27370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
27470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  length = read_2_bytes();	/* usual parameter length count */
27570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
27670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  data_precision = read_1_byte();
27770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  image_height = read_2_bytes();
27870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  image_width = read_2_bytes();
27970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  num_components = read_1_byte();
28070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
28170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  switch (marker) {
28270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  case M_SOF0:	process = "Baseline";  break;
28370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  case M_SOF1:	process = "Extended sequential";  break;
28470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  case M_SOF2:	process = "Progressive";  break;
28570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  case M_SOF3:	process = "Lossless";  break;
28670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  case M_SOF5:	process = "Differential sequential";  break;
28770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  case M_SOF6:	process = "Differential progressive";  break;
28870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  case M_SOF7:	process = "Differential lossless";  break;
28970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  case M_SOF9:	process = "Extended sequential, arithmetic coding";  break;
29070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  case M_SOF10:	process = "Progressive, arithmetic coding";  break;
29170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  case M_SOF11:	process = "Lossless, arithmetic coding";  break;
29270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  case M_SOF13:	process = "Differential sequential, arithmetic coding";  break;
29370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  case M_SOF14:	process = "Differential progressive, arithmetic coding"; break;
29470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  case M_SOF15:	process = "Differential lossless, arithmetic coding";  break;
29570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  default:	process = "Unknown";  break;
29670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  }
29770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
29870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  printf("JPEG image is %uw * %uh, %d color components, %d bits per sample\n",
29970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine	 image_width, image_height, num_components, data_precision);
30070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  printf("JPEG process: %s\n", process);
30170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
30270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  if (length != (unsigned int) (8 + num_components * 3))
30370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    ERREXIT("Bogus SOF marker length");
30470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
30570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  for (ci = 0; ci < num_components; ci++) {
30670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    (void) read_1_byte();	/* Component ID code */
30770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    (void) read_1_byte();	/* H, V sampling factors */
30870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    (void) read_1_byte();	/* Quantization table number */
30970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  }
31070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine}
31170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
31270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
31370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/*
31470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * Parse the marker stream until SOS or EOI is seen;
31570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * display any COM markers.
31670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * While the companion program wrjpgcom will always insert COM markers before
31770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * SOFn, other implementations might not, so we scan to SOS before stopping.
31870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * If we were only interested in the image dimensions, we would stop at SOFn.
31970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * (Conversely, if we only cared about COM markers, there would be no need
32070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * for special code to handle SOFn; we could treat it like other markers.)
32170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine */
32270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
32370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinestatic int
32470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinescan_JPEG_header (int verbose)
32570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine{
32670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  int marker;
32770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
32870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  /* Expect SOI at start of file */
32970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  if (first_marker() != M_SOI)
33070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    ERREXIT("Expected SOI marker first");
33170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
33270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  /* Scan miscellaneous markers until we reach SOS. */
33370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  for (;;) {
33470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    marker = next_marker();
33570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    switch (marker) {
33670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine      /* Note that marker codes 0xC4, 0xC8, 0xCC are not, and must not be,
33770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine       * treated as SOFn.  C4 in particular is actually DHT.
33870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine       */
33970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    case M_SOF0:		/* Baseline */
34070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    case M_SOF1:		/* Extended sequential, Huffman */
34170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    case M_SOF2:		/* Progressive, Huffman */
34270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    case M_SOF3:		/* Lossless, Huffman */
34370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    case M_SOF5:		/* Differential sequential, Huffman */
34470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    case M_SOF6:		/* Differential progressive, Huffman */
34570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    case M_SOF7:		/* Differential lossless, Huffman */
34670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    case M_SOF9:		/* Extended sequential, arithmetic */
34770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    case M_SOF10:		/* Progressive, arithmetic */
34870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    case M_SOF11:		/* Lossless, arithmetic */
34970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    case M_SOF13:		/* Differential sequential, arithmetic */
35070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    case M_SOF14:		/* Differential progressive, arithmetic */
35170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    case M_SOF15:		/* Differential lossless, arithmetic */
35270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine      if (verbose)
35370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine	process_SOFn(marker);
35470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine      else
35570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine	skip_variable();
35670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine      break;
35770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
35870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    case M_SOS:			/* stop before hitting compressed data */
35970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine      return marker;
36070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
36170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    case M_EOI:			/* in case it's a tables-only JPEG stream */
36270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine      return marker;
36370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
36470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    case M_COM:
36570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine      process_COM();
36670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine      break;
36770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
36870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    case M_APP12:
36970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine      /* Some digital camera makers put useful textual information into
37070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine       * APP12 markers, so we print those out too when in -verbose mode.
37170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine       */
37270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine      if (verbose) {
37370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine	printf("APP12 contains:\n");
37470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine	process_COM();
37570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine      } else
37670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine	skip_variable();
37770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine      break;
37870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
37970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    default:			/* Anything else just gets skipped */
38070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine      skip_variable();		/* we assume it has a parameter count... */
38170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine      break;
38270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    }
38370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  } /* end loop */
38470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine}
38570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
38670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
38770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* Command line parsing code */
38870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
38970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinestatic const char * progname;	/* program name for error messages */
39070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
39170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
39270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinestatic void
39370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkineusage (void)
39470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* complain about bad command line */
39570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine{
39670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  fprintf(stderr, "rdjpgcom displays any textual comments in a JPEG file.\n");
39770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
39870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  fprintf(stderr, "Usage: %s [switches] [inputfile]\n", progname);
39970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
40070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  fprintf(stderr, "Switches (names may be abbreviated):\n");
40170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  fprintf(stderr, "  -verbose    Also display dimensions of JPEG image\n");
40270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
40370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  exit(EXIT_FAILURE);
40470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine}
40570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
40670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
40770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinestatic int
40870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinekeymatch (char * arg, const char * keyword, int minchars)
40970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* Case-insensitive matching of (possibly abbreviated) keyword switches. */
41070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* keyword is the constant keyword (must be lower case already), */
41170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* minchars is length of minimum legal abbreviation. */
41270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine{
41370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  register int ca, ck;
41470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  register int nmatched = 0;
41570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
41670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  while ((ca = *arg++) != '\0') {
41770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    if ((ck = *keyword++) == '\0')
41870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine      return 0;			/* arg longer than keyword, no good */
41970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    if (isupper(ca))		/* force arg to lcase (assume ck is already) */
42070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine      ca = tolower(ca);
42170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    if (ca != ck)
42270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine      return 0;			/* no good */
42370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    nmatched++;			/* count matched characters */
42470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  }
42570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  /* reached end of argument; fail if it's too short for unique abbrev */
42670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  if (nmatched < minchars)
42770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    return 0;
42870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  return 1;			/* A-OK */
42970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine}
43070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
43170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
43270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/*
43370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * The main program.
43470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine */
43570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
43670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkineint
43770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinemain (int argc, char **argv)
43870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine{
43970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  int argn;
44070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  char * arg;
44170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  int verbose = 0;
44270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
44370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  /* On Mac, fetch a command line. */
44470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#ifdef USE_CCOMMAND
44570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  argc = ccommand(&argv);
44670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#endif
44770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
44870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  progname = argv[0];
44970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  if (progname == NULL || progname[0] == 0)
45070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    progname = "rdjpgcom";	/* in case C library doesn't provide it */
45170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
45270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  /* Parse switches, if any */
45370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  for (argn = 1; argn < argc; argn++) {
45470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    arg = argv[argn];
45570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    if (arg[0] != '-')
45670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine      break;			/* not switch, must be file name */
45770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    arg++;			/* advance over '-' */
45870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    if (keymatch(arg, "verbose", 1)) {
45970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine      verbose++;
46070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    } else
46170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine      usage();
46270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  }
46370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
46470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  /* Open the input file. */
46570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  /* Unix style: expect zero or one file name */
46670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  if (argn < argc-1) {
46770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    fprintf(stderr, "%s: only one input file\n", progname);
46870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    usage();
46970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  }
47070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  if (argn < argc) {
47170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    if ((infile = fopen(argv[argn], READ_BINARY)) == NULL) {
47270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine      fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]);
47370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine      exit(EXIT_FAILURE);
47470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    }
47570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  } else {
47670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    /* default input file is stdin */
47770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#ifdef USE_SETMODE		/* need to hack file mode? */
47870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    setmode(fileno(stdin), O_BINARY);
47970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#endif
48070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#ifdef USE_FDOPEN		/* need to re-open in binary mode? */
48170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    if ((infile = fdopen(fileno(stdin), READ_BINARY)) == NULL) {
48270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine      fprintf(stderr, "%s: can't open stdin\n", progname);
48370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine      exit(EXIT_FAILURE);
48470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    }
48570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#else
48670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine    infile = stdin;
48770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#endif
48870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  }
48970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
49070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  /* Scan the JPEG headers. */
49170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  (void) scan_JPEG_header(verbose);
49270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine
49370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  /* All done. */
49470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  exit(EXIT_SUCCESS);
49570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine  return 0;			/* suppress no-return-value warnings */
49670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine}
497