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