1f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org/*
2f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * wrjpgcom.c
3f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org *
4f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * Copyright (C) 1994-1997, Thomas G. Lane.
5f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * This file is part of the Independent JPEG Group's software.
6f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * For conditions of distribution and use, see the accompanying README file.
7f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org *
8f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * This file contains a very simple stand-alone application that inserts
9f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * user-supplied text as a COM (comment) marker in a JFIF file.
10f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * This may be useful as an example of the minimum logic needed to parse
11f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * JPEG markers.
12f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org */
13f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
14f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#define JPEG_CJPEG_DJPEG	/* to get the command-line config symbols */
15f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#include "jinclude.h"		/* get auto-config symbols, <stdio.h> */
16f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
17f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#ifndef HAVE_STDLIB_H		/* <stdlib.h> should declare malloc() */
18f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgextern void * malloc ();
19f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#endif
20f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#include <ctype.h>		/* to declare isupper(), tolower() */
21f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#ifdef USE_SETMODE
22f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#include <fcntl.h>		/* to declare setmode()'s parameter macros */
23f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org/* If you have setmode() but not <io.h>, just delete this line: */
24f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#include <io.h>			/* to declare setmode() */
25f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#endif
26f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
27f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#ifdef USE_CCOMMAND		/* command-line reader for Macintosh */
28f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#ifdef __MWERKS__
29f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#include <SIOUX.h>              /* Metrowerks needs this */
30f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#include <console.h>		/* ... and this */
31f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#endif
32f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#ifdef THINK_C
33f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#include <console.h>		/* Think declares it here */
34f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#endif
35f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#endif
36f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
37f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#ifdef DONT_USE_B_MODE		/* define mode parameters for fopen() */
38f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#define READ_BINARY	"r"
39f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#define WRITE_BINARY	"w"
40f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#else
41f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#ifdef VMS			/* VMS is very nonstandard */
42f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#define READ_BINARY	"rb", "ctx=stm"
43f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#define WRITE_BINARY	"wb", "ctx=stm"
44f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#else				/* standard ANSI-compliant case */
45f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#define READ_BINARY	"rb"
46f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#define WRITE_BINARY	"wb"
47f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#endif
48f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#endif
49f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
50f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#ifndef EXIT_FAILURE		/* define exit() codes if not provided */
51f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#define EXIT_FAILURE  1
52f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#endif
53f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#ifndef EXIT_SUCCESS
54f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#ifdef VMS
55f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#define EXIT_SUCCESS  1		/* VMS is very nonstandard */
56f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#else
57f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#define EXIT_SUCCESS  0
58f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#endif
59f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#endif
60f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
61f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org/* Reduce this value if your malloc() can't allocate blocks up to 64K.
62f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * On DOS, compiling in large model is usually a better solution.
63f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org */
64f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
65f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#ifndef MAX_COM_LENGTH
66f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#define MAX_COM_LENGTH 65000L	/* must be <= 65533 in any case */
67f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#endif
68f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
69f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
70f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org/*
71f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * These macros are used to read the input file and write the output file.
72f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * To reuse this code in another application, you might need to change these.
73f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org */
74f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
75f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgstatic FILE * infile;		/* input JPEG file */
76f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
77f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org/* Return next input byte, or EOF if no more */
78f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#define NEXTBYTE()  getc(infile)
79f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
80f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgstatic FILE * outfile;		/* output JPEG file */
81f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
82f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org/* Emit an output byte */
83f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#define PUTBYTE(x)  putc((x), outfile)
84f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
85f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
86f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org/* Error exit handler */
87f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#define ERREXIT(msg)  (fprintf(stderr, "%s\n", msg), exit(EXIT_FAILURE))
88f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
89f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
90f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org/* Read one byte, testing for EOF */
91f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgstatic int
92f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgread_1_byte (void)
93f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org{
94f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  int c;
95f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
96f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  c = NEXTBYTE();
97f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  if (c == EOF)
98f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    ERREXIT("Premature EOF in JPEG file");
99f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  return c;
100f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org}
101f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
102f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org/* Read 2 bytes, convert to unsigned int */
103f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org/* All 2-byte quantities in JPEG markers are MSB first */
104f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgstatic unsigned int
105f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgread_2_bytes (void)
106f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org{
107f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  int c1, c2;
108f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
109f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  c1 = NEXTBYTE();
110f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  if (c1 == EOF)
111f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    ERREXIT("Premature EOF in JPEG file");
112f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  c2 = NEXTBYTE();
113f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  if (c2 == EOF)
114f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    ERREXIT("Premature EOF in JPEG file");
115f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  return (((unsigned int) c1) << 8) + ((unsigned int) c2);
116f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org}
117f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
118f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
119f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org/* Routines to write data to output file */
120f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
121f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgstatic void
122f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgwrite_1_byte (int c)
123f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org{
124f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  PUTBYTE(c);
125f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org}
126f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
127f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgstatic void
128f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgwrite_2_bytes (unsigned int val)
129f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org{
130f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  PUTBYTE((val >> 8) & 0xFF);
131f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  PUTBYTE(val & 0xFF);
132f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org}
133f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
134f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgstatic void
135f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgwrite_marker (int marker)
136f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org{
137f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  PUTBYTE(0xFF);
138f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  PUTBYTE(marker);
139f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org}
140f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
141f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgstatic void
142f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgcopy_rest_of_file (void)
143f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org{
144f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  int c;
145f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
146f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  while ((c = NEXTBYTE()) != EOF)
147f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    PUTBYTE(c);
148f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org}
149f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
150f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
151f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org/*
152f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * JPEG markers consist of one or more 0xFF bytes, followed by a marker
153f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * code byte (which is not an FF).  Here are the marker codes of interest
154f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * in this program.  (See jdmarker.c for a more complete list.)
155f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org */
156f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
157f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#define M_SOF0  0xC0		/* Start Of Frame N */
158f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#define M_SOF1  0xC1		/* N indicates which compression process */
159f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#define M_SOF2  0xC2		/* Only SOF0-SOF2 are now in common use */
160f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#define M_SOF3  0xC3
161f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#define M_SOF5  0xC5		/* NB: codes C4 and CC are NOT SOF markers */
162f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#define M_SOF6  0xC6
163f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#define M_SOF7  0xC7
164f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#define M_SOF9  0xC9
165f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#define M_SOF10 0xCA
166f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#define M_SOF11 0xCB
167f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#define M_SOF13 0xCD
168f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#define M_SOF14 0xCE
169f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#define M_SOF15 0xCF
170f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#define M_SOI   0xD8		/* Start Of Image (beginning of datastream) */
171f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#define M_EOI   0xD9		/* End Of Image (end of datastream) */
172f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#define M_SOS   0xDA		/* Start Of Scan (begins compressed data) */
173f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#define M_COM   0xFE		/* COMment */
174f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
175f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
176f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org/*
177f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * Find the next JPEG marker and return its marker code.
178f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * We expect at least one FF byte, possibly more if the compressor used FFs
179f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * to pad the file.  (Padding FFs will NOT be replicated in the output file.)
180f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * There could also be non-FF garbage between markers.  The treatment of such
181f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * garbage is unspecified; we choose to skip over it but emit a warning msg.
182f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * NB: this routine must not be used after seeing SOS marker, since it will
183f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * not deal correctly with FF/00 sequences in the compressed image data...
184f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org */
185f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
186f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgstatic int
187f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgnext_marker (void)
188f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org{
189f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  int c;
190f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  int discarded_bytes = 0;
191f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
192f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  /* Find 0xFF byte; count and skip any non-FFs. */
193f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  c = read_1_byte();
194f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  while (c != 0xFF) {
195f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    discarded_bytes++;
196f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    c = read_1_byte();
197f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  }
198f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  /* Get marker code byte, swallowing any duplicate FF bytes.  Extra FFs
199f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org   * are legal as pad bytes, so don't count them in discarded_bytes.
200f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org   */
201f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  do {
202f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    c = read_1_byte();
203f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  } while (c == 0xFF);
204f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
205f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  if (discarded_bytes != 0) {
206f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    fprintf(stderr, "Warning: garbage data found in JPEG file\n");
207f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  }
208f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
209f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  return c;
210f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org}
211f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
212f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
213f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org/*
214f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * Read the initial marker, which should be SOI.
215f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * For a JFIF file, the first two bytes of the file should be literally
216f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * 0xFF M_SOI.  To be more general, we could use next_marker, but if the
217f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * input file weren't actually JPEG at all, next_marker might read the whole
218f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * file and then return a misleading error message...
219f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org */
220f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
221f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgstatic int
222f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgfirst_marker (void)
223f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org{
224f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  int c1, c2;
225f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
226f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  c1 = NEXTBYTE();
227f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  c2 = NEXTBYTE();
228f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  if (c1 != 0xFF || c2 != M_SOI)
229f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    ERREXIT("Not a JPEG file");
230f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  return c2;
231f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org}
232f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
233f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
234f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org/*
235f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * Most types of marker are followed by a variable-length parameter segment.
236f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * This routine skips over the parameters for any marker we don't otherwise
237f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * want to process.
238f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * Note that we MUST skip the parameter segment explicitly in order not to
239f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * be fooled by 0xFF bytes that might appear within the parameter segment;
240f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * such bytes do NOT introduce new markers.
241f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org */
242f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
243f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgstatic void
244f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgcopy_variable (void)
245f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org/* Copy an unknown or uninteresting variable-length marker */
246f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org{
247f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  unsigned int length;
248f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
249f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  /* Get the marker parameter length count */
250f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  length = read_2_bytes();
251f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  write_2_bytes(length);
252f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  /* Length includes itself, so must be at least 2 */
253f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  if (length < 2)
254f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    ERREXIT("Erroneous JPEG marker length");
255f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  length -= 2;
256f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  /* Skip over the remaining bytes */
257f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  while (length > 0) {
258f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    write_1_byte(read_1_byte());
259f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    length--;
260f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  }
261f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org}
262f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
263f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgstatic void
264f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgskip_variable (void)
265f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org/* Skip over an unknown or uninteresting variable-length marker */
266f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org{
267f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  unsigned int length;
268f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
269f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  /* Get the marker parameter length count */
270f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  length = read_2_bytes();
271f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  /* Length includes itself, so must be at least 2 */
272f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  if (length < 2)
273f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    ERREXIT("Erroneous JPEG marker length");
274f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  length -= 2;
275f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  /* Skip over the remaining bytes */
276f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  while (length > 0) {
277f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    (void) read_1_byte();
278f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    length--;
279f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  }
280f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org}
281f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
282f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
283f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org/*
284f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * Parse the marker stream until SOFn or EOI is seen;
285f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * copy data to output, but discard COM markers unless keep_COM is true.
286f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org */
287f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
288f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgstatic int
289f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgscan_JPEG_header (int keep_COM)
290f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org{
291f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  int marker;
292f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
293f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  /* Expect SOI at start of file */
294f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  if (first_marker() != M_SOI)
295f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    ERREXIT("Expected SOI marker first");
296f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  write_marker(M_SOI);
297f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
298f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  /* Scan miscellaneous markers until we reach SOFn. */
299f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  for (;;) {
300f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    marker = next_marker();
301f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    switch (marker) {
302f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      /* Note that marker codes 0xC4, 0xC8, 0xCC are not, and must not be,
303f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org       * treated as SOFn.  C4 in particular is actually DHT.
304f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org       */
305f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    case M_SOF0:		/* Baseline */
306f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    case M_SOF1:		/* Extended sequential, Huffman */
307f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    case M_SOF2:		/* Progressive, Huffman */
308f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    case M_SOF3:		/* Lossless, Huffman */
309f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    case M_SOF5:		/* Differential sequential, Huffman */
310f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    case M_SOF6:		/* Differential progressive, Huffman */
311f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    case M_SOF7:		/* Differential lossless, Huffman */
312f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    case M_SOF9:		/* Extended sequential, arithmetic */
313f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    case M_SOF10:		/* Progressive, arithmetic */
314f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    case M_SOF11:		/* Lossless, arithmetic */
315f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    case M_SOF13:		/* Differential sequential, arithmetic */
316f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    case M_SOF14:		/* Differential progressive, arithmetic */
317f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    case M_SOF15:		/* Differential lossless, arithmetic */
318f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      return marker;
319f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
320f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    case M_SOS:			/* should not see compressed data before SOF */
321f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      ERREXIT("SOS without prior SOFn");
322f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      break;
323f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
324f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    case M_EOI:			/* in case it's a tables-only JPEG stream */
325f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      return marker;
326f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
327f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    case M_COM:			/* Existing COM: conditionally discard */
328f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      if (keep_COM) {
329f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org	write_marker(marker);
330f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org	copy_variable();
331f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      } else {
332f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org	skip_variable();
333f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      }
334f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      break;
335f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
336f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    default:			/* Anything else just gets copied */
337f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      write_marker(marker);
338f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      copy_variable();		/* we assume it has a parameter count... */
339f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      break;
340f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    }
341f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  } /* end loop */
342f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org}
343f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
344f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
345f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org/* Command line parsing code */
346f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
347f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgstatic const char * progname;	/* program name for error messages */
348f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
349f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
350f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgstatic void
351f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgusage (void)
352f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org/* complain about bad command line */
353f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org{
354f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  fprintf(stderr, "wrjpgcom inserts a textual comment in a JPEG file.\n");
355f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  fprintf(stderr, "You can add to or replace any existing comment(s).\n");
356f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
357f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  fprintf(stderr, "Usage: %s [switches] ", progname);
358f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#ifdef TWO_FILE_COMMANDLINE
359f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  fprintf(stderr, "inputfile outputfile\n");
360f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#else
361f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  fprintf(stderr, "[inputfile]\n");
362f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#endif
363f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
364f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  fprintf(stderr, "Switches (names may be abbreviated):\n");
365f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  fprintf(stderr, "  -replace         Delete any existing comments\n");
366f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  fprintf(stderr, "  -comment \"text\"  Insert comment with given text\n");
367f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  fprintf(stderr, "  -cfile name      Read comment from named file\n");
368f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  fprintf(stderr, "Notice that you must put quotes around the comment text\n");
369f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  fprintf(stderr, "when you use -comment.\n");
370f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  fprintf(stderr, "If you do not give either -comment or -cfile on the command line,\n");
371f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  fprintf(stderr, "then the comment text is read from standard input.\n");
372f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  fprintf(stderr, "It can be multiple lines, up to %u characters total.\n",
373f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org	  (unsigned int) MAX_COM_LENGTH);
374f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#ifndef TWO_FILE_COMMANDLINE
375f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  fprintf(stderr, "You must specify an input JPEG file name when supplying\n");
376f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  fprintf(stderr, "comment text from standard input.\n");
377f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#endif
378f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
379f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  exit(EXIT_FAILURE);
380f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org}
381f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
382f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
383f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgstatic int
384f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgkeymatch (char * arg, const char * keyword, int minchars)
385f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org/* Case-insensitive matching of (possibly abbreviated) keyword switches. */
386f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org/* keyword is the constant keyword (must be lower case already), */
387f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org/* minchars is length of minimum legal abbreviation. */
388f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org{
389f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  register int ca, ck;
390f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  register int nmatched = 0;
391f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
392f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  while ((ca = *arg++) != '\0') {
393f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    if ((ck = *keyword++) == '\0')
394f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      return 0;			/* arg longer than keyword, no good */
395f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    if (isupper(ca))		/* force arg to lcase (assume ck is already) */
396f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      ca = tolower(ca);
397f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    if (ca != ck)
398f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      return 0;			/* no good */
399f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    nmatched++;			/* count matched characters */
400f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  }
401f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  /* reached end of argument; fail if it's too short for unique abbrev */
402f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  if (nmatched < minchars)
403f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    return 0;
404f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  return 1;			/* A-OK */
405f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org}
406f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
407f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
408f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org/*
409f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org * The main program.
410f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org */
411f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
412f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgint
413f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.orgmain (int argc, char **argv)
414f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org{
415f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  int argn;
416f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  char * arg;
417f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  int keep_COM = 1;
418f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  char * comment_arg = NULL;
419f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  FILE * comment_file = NULL;
420f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  unsigned int comment_length = 0;
421f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  int marker;
422f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
423f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  /* On Mac, fetch a command line. */
424f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#ifdef USE_CCOMMAND
425f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  argc = ccommand(&argv);
426f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#endif
427f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
428f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  progname = argv[0];
429f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  if (progname == NULL || progname[0] == 0)
430f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    progname = "wrjpgcom";	/* in case C library doesn't provide it */
431f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
432f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  /* Parse switches, if any */
433f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  for (argn = 1; argn < argc; argn++) {
434f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    arg = argv[argn];
435f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    if (arg[0] != '-')
436f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      break;			/* not switch, must be file name */
437f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    arg++;			/* advance over '-' */
438f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    if (keymatch(arg, "replace", 1)) {
439f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      keep_COM = 0;
440f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    } else if (keymatch(arg, "cfile", 2)) {
441f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      if (++argn >= argc) usage();
442f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      if ((comment_file = fopen(argv[argn], "r")) == NULL) {
443f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org	fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]);
444f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org	exit(EXIT_FAILURE);
445f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      }
446f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    } else if (keymatch(arg, "comment", 1)) {
447f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      if (++argn >= argc) usage();
448f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      comment_arg = argv[argn];
449f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      /* If the comment text starts with '"', then we are probably running
450f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org       * under MS-DOG and must parse out the quoted string ourselves.  Sigh.
451f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org       */
452f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      if (comment_arg[0] == '"') {
453f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org	comment_arg = (char *) malloc((size_t) MAX_COM_LENGTH);
454f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org	if (comment_arg == NULL)
455f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org	  ERREXIT("Insufficient memory");
456f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org	strcpy(comment_arg, argv[argn]+1);
457f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org	for (;;) {
458f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org	  comment_length = (unsigned int) strlen(comment_arg);
459f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org	  if (comment_length > 0 && comment_arg[comment_length-1] == '"') {
460f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org	    comment_arg[comment_length-1] = '\0'; /* zap terminating quote */
461f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org	    break;
462f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org	  }
463f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org	  if (++argn >= argc)
464f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org	    ERREXIT("Missing ending quote mark");
465f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org	  strcat(comment_arg, " ");
466f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org	  strcat(comment_arg, argv[argn]);
467f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org	}
468f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      }
469f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      comment_length = (unsigned int) strlen(comment_arg);
470f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    } else
471f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      usage();
472f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  }
473f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
474f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  /* Cannot use both -comment and -cfile. */
475f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  if (comment_arg != NULL && comment_file != NULL)
476f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    usage();
477f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  /* If there is neither -comment nor -cfile, we will read the comment text
478f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org   * from stdin; in this case there MUST be an input JPEG file name.
479f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org   */
480f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  if (comment_arg == NULL && comment_file == NULL && argn >= argc)
481f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    usage();
482f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
483f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  /* Open the input file. */
484f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  if (argn < argc) {
485f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    if ((infile = fopen(argv[argn], READ_BINARY)) == NULL) {
486f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]);
487f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      exit(EXIT_FAILURE);
488f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    }
489f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  } else {
490f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    /* default input file is stdin */
491f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#ifdef USE_SETMODE		/* need to hack file mode? */
492f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    setmode(fileno(stdin), O_BINARY);
493f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#endif
494f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#ifdef USE_FDOPEN		/* need to re-open in binary mode? */
495f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    if ((infile = fdopen(fileno(stdin), READ_BINARY)) == NULL) {
496f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      fprintf(stderr, "%s: can't open stdin\n", progname);
497f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      exit(EXIT_FAILURE);
498f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    }
499f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#else
500f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    infile = stdin;
501f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#endif
502f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  }
503f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
504f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  /* Open the output file. */
505f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#ifdef TWO_FILE_COMMANDLINE
506f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  /* Must have explicit output file name */
507f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  if (argn != argc-2) {
508f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    fprintf(stderr, "%s: must name one input and one output file\n",
509f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org	    progname);
510f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    usage();
511f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  }
512f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  if ((outfile = fopen(argv[argn+1], WRITE_BINARY)) == NULL) {
513f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    fprintf(stderr, "%s: can't open %s\n", progname, argv[argn+1]);
514f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    exit(EXIT_FAILURE);
515f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  }
516f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#else
517f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  /* Unix style: expect zero or one file name */
518f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  if (argn < argc-1) {
519f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    fprintf(stderr, "%s: only one input file\n", progname);
520f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    usage();
521f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  }
522f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  /* default output file is stdout */
523f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#ifdef USE_SETMODE		/* need to hack file mode? */
524f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  setmode(fileno(stdout), O_BINARY);
525f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#endif
526f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#ifdef USE_FDOPEN		/* need to re-open in binary mode? */
527f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  if ((outfile = fdopen(fileno(stdout), WRITE_BINARY)) == NULL) {
528f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    fprintf(stderr, "%s: can't open stdout\n", progname);
529f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    exit(EXIT_FAILURE);
530f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  }
531f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#else
532f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  outfile = stdout;
533f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#endif
534f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org#endif /* TWO_FILE_COMMANDLINE */
535f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
536f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  /* Collect comment text from comment_file or stdin, if necessary */
537f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  if (comment_arg == NULL) {
538f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    FILE * src_file;
539f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    int c;
540f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
541f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    comment_arg = (char *) malloc((size_t) MAX_COM_LENGTH);
542f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    if (comment_arg == NULL)
543f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      ERREXIT("Insufficient memory");
544f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    comment_length = 0;
545f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    src_file = (comment_file != NULL ? comment_file : stdin);
546f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    while ((c = getc(src_file)) != EOF) {
547f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      if (comment_length >= (unsigned int) MAX_COM_LENGTH) {
548f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org	fprintf(stderr, "Comment text may not exceed %u bytes\n",
549f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org		(unsigned int) MAX_COM_LENGTH);
550f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org	exit(EXIT_FAILURE);
551f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      }
552f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      comment_arg[comment_length++] = (char) c;
553f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    }
554f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    if (comment_file != NULL)
555f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      fclose(comment_file);
556f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  }
557f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
558f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  /* Copy JPEG headers until SOFn marker;
559f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org   * we will insert the new comment marker just before SOFn.
560f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org   * This (a) causes the new comment to appear after, rather than before,
561f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org   * existing comments; and (b) ensures that comments come after any JFIF
562f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org   * or JFXX markers, as required by the JFIF specification.
563f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org   */
564f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  marker = scan_JPEG_header(keep_COM);
565f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  /* Insert the new COM marker, but only if nonempty text has been supplied */
566f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  if (comment_length > 0) {
567f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    write_marker(M_COM);
568f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    write_2_bytes(comment_length + 2);
569f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    while (comment_length > 0) {
570f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      write_1_byte(*comment_arg++);
571f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org      comment_length--;
572f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org    }
573f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  }
574f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  /* Duplicate the remainder of the source file.
575f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org   * Note that any COM markers occuring after SOF will not be touched.
576f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org   */
577f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  write_marker(marker);
578f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  copy_rest_of_file();
579f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org
580f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  /* All done. */
581f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  exit(EXIT_SUCCESS);
582f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org  return 0;			/* suppress no-return-value warnings */
583f0c4f33a4aa0760ba0e12a254b69d996442c9c5hbono@chromium.org}
584