wrjpgcom.c revision 70a18cd874a22452aca9e39e22275ed4538ed20b
170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* 270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * wrjpgcom.c 370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * 470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * Copyright (C) 1994-1997, Thomas G. Lane. 570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * This file is part of the Independent JPEG Group's software. 670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * For conditions of distribution and use, see the accompanying README file. 770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * 870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * This file contains a very simple stand-alone application that inserts 970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * user-supplied text as a COM (comment) marker in a JFIF file. 1070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * This may be useful as an example of the minimum logic needed to parse 1170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * JPEG markers. 1270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine */ 1370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 1470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define JPEG_CJPEG_DJPEG /* to get the command-line config symbols */ 1570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#include "jinclude.h" /* get auto-config symbols, <stdio.h> */ 1670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 1770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare malloc() */ 1870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkineextern void * malloc (); 1970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#endif 2070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#include <ctype.h> /* to declare isupper(), tolower() */ 2170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#ifdef USE_SETMODE 2270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#include <fcntl.h> /* to declare setmode()'s parameter macros */ 2370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* If you have setmode() but not <io.h>, just delete this line: */ 2470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#include <io.h> /* to declare setmode() */ 2570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#endif 2670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 2770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#ifdef USE_CCOMMAND /* command-line reader for Macintosh */ 2870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#ifdef __MWERKS__ 2970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#include <SIOUX.h> /* Metrowerks needs this */ 3070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#include <console.h> /* ... and this */ 3170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#endif 3270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#ifdef THINK_C 3370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#include <console.h> /* Think declares it here */ 3470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#endif 3570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#endif 3670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 3770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */ 3870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define READ_BINARY "r" 3970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define WRITE_BINARY "w" 4070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#else 4170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#ifdef VMS /* VMS is very nonstandard */ 4270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define READ_BINARY "rb", "ctx=stm" 4370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define WRITE_BINARY "wb", "ctx=stm" 4470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#else /* standard ANSI-compliant case */ 4570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define READ_BINARY "rb" 4670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define WRITE_BINARY "wb" 4770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#endif 4870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#endif 4970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 5070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#ifndef EXIT_FAILURE /* define exit() codes if not provided */ 5170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define EXIT_FAILURE 1 5270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#endif 5370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#ifndef EXIT_SUCCESS 5470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#ifdef VMS 5570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define EXIT_SUCCESS 1 /* VMS is very nonstandard */ 5670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#else 5770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define EXIT_SUCCESS 0 5870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#endif 5970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#endif 6070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 6170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* Reduce this value if your malloc() can't allocate blocks up to 64K. 6270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * On DOS, compiling in large model is usually a better solution. 6370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine */ 6470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 6570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#ifndef MAX_COM_LENGTH 6670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define MAX_COM_LENGTH 65000L /* must be <= 65533 in any case */ 6770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#endif 6870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 6970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 7070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* 7170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * These macros are used to read the input file and write the output file. 7270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * To reuse this code in another application, you might need to change these. 7370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine */ 7470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 7570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinestatic FILE * infile; /* input JPEG file */ 7670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 7770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* Return next input byte, or EOF if no more */ 7870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define NEXTBYTE() getc(infile) 7970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 8070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinestatic FILE * outfile; /* output JPEG file */ 8170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 8270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* Emit an output byte */ 8370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define PUTBYTE(x) putc((x), outfile) 8470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 8570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 8670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* Error exit handler */ 8770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define ERREXIT(msg) (fprintf(stderr, "%s\n", msg), exit(EXIT_FAILURE)) 8870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 8970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 9070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* Read one byte, testing for EOF */ 9170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinestatic int 9270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkineread_1_byte (void) 9370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine{ 9470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine int c; 9570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 9670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine c = NEXTBYTE(); 9770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if (c == EOF) 9870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine ERREXIT("Premature EOF in JPEG file"); 9970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine return c; 10070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine} 10170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 10270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* Read 2 bytes, convert to unsigned int */ 10370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* All 2-byte quantities in JPEG markers are MSB first */ 10470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinestatic unsigned int 10570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkineread_2_bytes (void) 10670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine{ 10770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine int c1, c2; 10870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 10970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine c1 = NEXTBYTE(); 11070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if (c1 == EOF) 11170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine ERREXIT("Premature EOF in JPEG file"); 11270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine c2 = NEXTBYTE(); 11370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if (c2 == EOF) 11470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine ERREXIT("Premature EOF in JPEG file"); 11570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine return (((unsigned int) c1) << 8) + ((unsigned int) c2); 11670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine} 11770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 11870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 11970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* Routines to write data to output file */ 12070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 12170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinestatic void 12270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinewrite_1_byte (int c) 12370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine{ 12470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine PUTBYTE(c); 12570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine} 12670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 12770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinestatic void 12870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinewrite_2_bytes (unsigned int val) 12970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine{ 13070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine PUTBYTE((val >> 8) & 0xFF); 13170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine PUTBYTE(val & 0xFF); 13270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine} 13370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 13470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinestatic void 13570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinewrite_marker (int marker) 13670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine{ 13770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine PUTBYTE(0xFF); 13870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine PUTBYTE(marker); 13970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine} 14070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 14170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinestatic void 14270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinecopy_rest_of_file (void) 14370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine{ 14470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine int c; 14570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 14670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine while ((c = NEXTBYTE()) != EOF) 14770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine PUTBYTE(c); 14870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine} 14970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 15070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 15170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* 15270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * JPEG markers consist of one or more 0xFF bytes, followed by a marker 15370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * code byte (which is not an FF). Here are the marker codes of interest 15470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * in this program. (See jdmarker.c for a more complete list.) 15570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine */ 15670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 15770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_SOF0 0xC0 /* Start Of Frame N */ 15870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_SOF1 0xC1 /* N indicates which compression process */ 15970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */ 16070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_SOF3 0xC3 16170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */ 16270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_SOF6 0xC6 16370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_SOF7 0xC7 16470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_SOF9 0xC9 16570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_SOF10 0xCA 16670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_SOF11 0xCB 16770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_SOF13 0xCD 16870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_SOF14 0xCE 16970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_SOF15 0xCF 17070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_SOI 0xD8 /* Start Of Image (beginning of datastream) */ 17170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_EOI 0xD9 /* End Of Image (end of datastream) */ 17270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_SOS 0xDA /* Start Of Scan (begins compressed data) */ 17370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#define M_COM 0xFE /* COMment */ 17470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 17570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 17670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* 17770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * Find the next JPEG marker and return its marker code. 17870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * We expect at least one FF byte, possibly more if the compressor used FFs 17970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * to pad the file. (Padding FFs will NOT be replicated in the output file.) 18070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * There could also be non-FF garbage between markers. The treatment of such 18170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * garbage is unspecified; we choose to skip over it but emit a warning msg. 18270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * NB: this routine must not be used after seeing SOS marker, since it will 18370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * not deal correctly with FF/00 sequences in the compressed image data... 18470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine */ 18570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 18670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinestatic int 18770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinenext_marker (void) 18870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine{ 18970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine int c; 19070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine int discarded_bytes = 0; 19170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 19270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine /* Find 0xFF byte; count and skip any non-FFs. */ 19370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine c = read_1_byte(); 19470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine while (c != 0xFF) { 19570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine discarded_bytes++; 19670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine c = read_1_byte(); 19770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine } 19870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine /* Get marker code byte, swallowing any duplicate FF bytes. Extra FFs 19970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * are legal as pad bytes, so don't count them in discarded_bytes. 20070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine */ 20170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine do { 20270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine c = read_1_byte(); 20370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine } while (c == 0xFF); 20470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 20570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if (discarded_bytes != 0) { 20670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine fprintf(stderr, "Warning: garbage data found in JPEG file\n"); 20770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine } 20870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 20970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine return c; 21070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine} 21170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 21270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 21370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* 21470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * Read the initial marker, which should be SOI. 21570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * For a JFIF file, the first two bytes of the file should be literally 21670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * 0xFF M_SOI. To be more general, we could use next_marker, but if the 21770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * input file weren't actually JPEG at all, next_marker might read the whole 21870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * file and then return a misleading error message... 21970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine */ 22070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 22170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinestatic int 22270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinefirst_marker (void) 22370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine{ 22470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine int c1, c2; 22570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 22670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine c1 = NEXTBYTE(); 22770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine c2 = NEXTBYTE(); 22870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if (c1 != 0xFF || c2 != M_SOI) 22970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine ERREXIT("Not a JPEG file"); 23070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine return c2; 23170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine} 23270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 23370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 23470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* 23570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * Most types of marker are followed by a variable-length parameter segment. 23670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * This routine skips over the parameters for any marker we don't otherwise 23770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * want to process. 23870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * Note that we MUST skip the parameter segment explicitly in order not to 23970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * be fooled by 0xFF bytes that might appear within the parameter segment; 24070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * such bytes do NOT introduce new markers. 24170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine */ 24270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 24370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinestatic void 24470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinecopy_variable (void) 24570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* Copy an unknown or uninteresting variable-length marker */ 24670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine{ 24770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine unsigned int length; 24870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 24970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine /* Get the marker parameter length count */ 25070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine length = read_2_bytes(); 25170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine write_2_bytes(length); 25270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine /* Length includes itself, so must be at least 2 */ 25370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if (length < 2) 25470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine ERREXIT("Erroneous JPEG marker length"); 25570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine length -= 2; 25670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine /* Skip over the remaining bytes */ 25770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine while (length > 0) { 25870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine write_1_byte(read_1_byte()); 25970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine length--; 26070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine } 26170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine} 26270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 26370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinestatic void 26470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkineskip_variable (void) 26570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* Skip over an unknown or uninteresting variable-length marker */ 26670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine{ 26770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine unsigned int length; 26870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 26970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine /* Get the marker parameter length count */ 27070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine length = read_2_bytes(); 27170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine /* Length includes itself, so must be at least 2 */ 27270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if (length < 2) 27370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine ERREXIT("Erroneous JPEG marker length"); 27470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine length -= 2; 27570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine /* Skip over the remaining bytes */ 27670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine while (length > 0) { 27770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine (void) read_1_byte(); 27870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine length--; 27970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine } 28070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine} 28170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 28270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 28370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* 28470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * Parse the marker stream until SOFn or EOI is seen; 28570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * copy data to output, but discard COM markers unless keep_COM is true. 28670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine */ 28770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 28870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinestatic int 28970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinescan_JPEG_header (int keep_COM) 29070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine{ 29170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine int marker; 29270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 29370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine /* Expect SOI at start of file */ 29470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if (first_marker() != M_SOI) 29570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine ERREXIT("Expected SOI marker first"); 29670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine write_marker(M_SOI); 29770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 29870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine /* Scan miscellaneous markers until we reach SOFn. */ 29970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine for (;;) { 30070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine marker = next_marker(); 30170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine switch (marker) { 30270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine /* Note that marker codes 0xC4, 0xC8, 0xCC are not, and must not be, 30370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * treated as SOFn. C4 in particular is actually DHT. 30470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine */ 30570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine case M_SOF0: /* Baseline */ 30670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine case M_SOF1: /* Extended sequential, Huffman */ 30770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine case M_SOF2: /* Progressive, Huffman */ 30870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine case M_SOF3: /* Lossless, Huffman */ 30970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine case M_SOF5: /* Differential sequential, Huffman */ 31070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine case M_SOF6: /* Differential progressive, Huffman */ 31170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine case M_SOF7: /* Differential lossless, Huffman */ 31270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine case M_SOF9: /* Extended sequential, arithmetic */ 31370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine case M_SOF10: /* Progressive, arithmetic */ 31470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine case M_SOF11: /* Lossless, arithmetic */ 31570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine case M_SOF13: /* Differential sequential, arithmetic */ 31670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine case M_SOF14: /* Differential progressive, arithmetic */ 31770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine case M_SOF15: /* Differential lossless, arithmetic */ 31870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine return marker; 31970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 32070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine case M_SOS: /* should not see compressed data before SOF */ 32170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine ERREXIT("SOS without prior SOFn"); 32270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine break; 32370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 32470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine case M_EOI: /* in case it's a tables-only JPEG stream */ 32570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine return marker; 32670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 32770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine case M_COM: /* Existing COM: conditionally discard */ 32870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if (keep_COM) { 32970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine write_marker(marker); 33070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine copy_variable(); 33170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine } else { 33270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine skip_variable(); 33370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine } 33470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine break; 33570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 33670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine default: /* Anything else just gets copied */ 33770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine write_marker(marker); 33870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine copy_variable(); /* we assume it has a parameter count... */ 33970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine break; 34070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine } 34170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine } /* end loop */ 34270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine} 34370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 34470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 34570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* Command line parsing code */ 34670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 34770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinestatic const char * progname; /* program name for error messages */ 34870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 34970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 35070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinestatic void 35170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkineusage (void) 35270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* complain about bad command line */ 35370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine{ 35470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine fprintf(stderr, "wrjpgcom inserts a textual comment in a JPEG file.\n"); 35570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine fprintf(stderr, "You can add to or replace any existing comment(s).\n"); 35670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 35770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine fprintf(stderr, "Usage: %s [switches] ", progname); 35870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#ifdef TWO_FILE_COMMANDLINE 35970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine fprintf(stderr, "inputfile outputfile\n"); 36070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#else 36170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine fprintf(stderr, "[inputfile]\n"); 36270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#endif 36370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 36470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine fprintf(stderr, "Switches (names may be abbreviated):\n"); 36570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine fprintf(stderr, " -replace Delete any existing comments\n"); 36670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine fprintf(stderr, " -comment \"text\" Insert comment with given text\n"); 36770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine fprintf(stderr, " -cfile name Read comment from named file\n"); 36870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine fprintf(stderr, "Notice that you must put quotes around the comment text\n"); 36970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine fprintf(stderr, "when you use -comment.\n"); 37070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine fprintf(stderr, "If you do not give either -comment or -cfile on the command line,\n"); 37170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine fprintf(stderr, "then the comment text is read from standard input.\n"); 37270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine fprintf(stderr, "It can be multiple lines, up to %u characters total.\n", 37370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine (unsigned int) MAX_COM_LENGTH); 37470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#ifndef TWO_FILE_COMMANDLINE 37570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine fprintf(stderr, "You must specify an input JPEG file name when supplying\n"); 37670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine fprintf(stderr, "comment text from standard input.\n"); 37770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#endif 37870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 37970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine exit(EXIT_FAILURE); 38070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine} 38170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 38270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 38370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinestatic int 38470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinekeymatch (char * arg, const char * keyword, int minchars) 38570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* Case-insensitive matching of (possibly abbreviated) keyword switches. */ 38670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* keyword is the constant keyword (must be lower case already), */ 38770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* minchars is length of minimum legal abbreviation. */ 38870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine{ 38970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine register int ca, ck; 39070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine register int nmatched = 0; 39170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 39270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine while ((ca = *arg++) != '\0') { 39370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if ((ck = *keyword++) == '\0') 39470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine return 0; /* arg longer than keyword, no good */ 39570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if (isupper(ca)) /* force arg to lcase (assume ck is already) */ 39670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine ca = tolower(ca); 39770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if (ca != ck) 39870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine return 0; /* no good */ 39970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine nmatched++; /* count matched characters */ 40070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine } 40170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine /* reached end of argument; fail if it's too short for unique abbrev */ 40270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if (nmatched < minchars) 40370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine return 0; 40470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine return 1; /* A-OK */ 40570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine} 40670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 40770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 40870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine/* 40970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * The main program. 41070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine */ 41170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 41270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkineint 41370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkinemain (int argc, char **argv) 41470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine{ 41570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine int argn; 41670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine char * arg; 41770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine int keep_COM = 1; 41870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine char * comment_arg = NULL; 41970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine FILE * comment_file = NULL; 42070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine unsigned int comment_length = 0; 42170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine int marker; 42270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 42370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine /* On Mac, fetch a command line. */ 42470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#ifdef USE_CCOMMAND 42570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine argc = ccommand(&argv); 42670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#endif 42770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 42870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine progname = argv[0]; 42970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if (progname == NULL || progname[0] == 0) 43070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine progname = "wrjpgcom"; /* in case C library doesn't provide it */ 43170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 43270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine /* Parse switches, if any */ 43370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine for (argn = 1; argn < argc; argn++) { 43470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine arg = argv[argn]; 43570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if (arg[0] != '-') 43670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine break; /* not switch, must be file name */ 43770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine arg++; /* advance over '-' */ 43870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if (keymatch(arg, "replace", 1)) { 43970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine keep_COM = 0; 44070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine } else if (keymatch(arg, "cfile", 2)) { 44170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if (++argn >= argc) usage(); 44270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if ((comment_file = fopen(argv[argn], "r")) == NULL) { 44370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]); 44470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine exit(EXIT_FAILURE); 44570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine } 44670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine } else if (keymatch(arg, "comment", 1)) { 44770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if (++argn >= argc) usage(); 44870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine comment_arg = argv[argn]; 44970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine /* If the comment text starts with '"', then we are probably running 45070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * under MS-DOG and must parse out the quoted string ourselves. Sigh. 45170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine */ 45270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if (comment_arg[0] == '"') { 45370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine comment_arg = (char *) malloc((size_t) MAX_COM_LENGTH); 45470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if (comment_arg == NULL) 45570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine ERREXIT("Insufficient memory"); 45670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine strcpy(comment_arg, argv[argn]+1); 45770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine for (;;) { 45870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine comment_length = (unsigned int) strlen(comment_arg); 45970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if (comment_length > 0 && comment_arg[comment_length-1] == '"') { 46070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine comment_arg[comment_length-1] = '\0'; /* zap terminating quote */ 46170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine break; 46270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine } 46370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if (++argn >= argc) 46470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine ERREXIT("Missing ending quote mark"); 46570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine strcat(comment_arg, " "); 46670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine strcat(comment_arg, argv[argn]); 46770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine } 46870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine } 46970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine comment_length = (unsigned int) strlen(comment_arg); 47070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine } else 47170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine usage(); 47270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine } 47370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 47470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine /* Cannot use both -comment and -cfile. */ 47570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if (comment_arg != NULL && comment_file != NULL) 47670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine usage(); 47770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine /* If there is neither -comment nor -cfile, we will read the comment text 47870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * from stdin; in this case there MUST be an input JPEG file name. 47970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine */ 48070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if (comment_arg == NULL && comment_file == NULL && argn >= argc) 48170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine usage(); 48270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 48370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine /* Open the input file. */ 48470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if (argn < argc) { 48570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if ((infile = fopen(argv[argn], READ_BINARY)) == NULL) { 48670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]); 48770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine exit(EXIT_FAILURE); 48870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine } 48970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine } else { 49070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine /* default input file is stdin */ 49170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#ifdef USE_SETMODE /* need to hack file mode? */ 49270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine setmode(fileno(stdin), O_BINARY); 49370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#endif 49470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#ifdef USE_FDOPEN /* need to re-open in binary mode? */ 49570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if ((infile = fdopen(fileno(stdin), READ_BINARY)) == NULL) { 49670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine fprintf(stderr, "%s: can't open stdin\n", progname); 49770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine exit(EXIT_FAILURE); 49870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine } 49970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#else 50070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine infile = stdin; 50170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#endif 50270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine } 50370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 50470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine /* Open the output file. */ 50570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#ifdef TWO_FILE_COMMANDLINE 50670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine /* Must have explicit output file name */ 50770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if (argn != argc-2) { 50870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine fprintf(stderr, "%s: must name one input and one output file\n", 50970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine progname); 51070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine usage(); 51170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine } 51270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if ((outfile = fopen(argv[argn+1], WRITE_BINARY)) == NULL) { 51370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine fprintf(stderr, "%s: can't open %s\n", progname, argv[argn+1]); 51470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine exit(EXIT_FAILURE); 51570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine } 51670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#else 51770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine /* Unix style: expect zero or one file name */ 51870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if (argn < argc-1) { 51970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine fprintf(stderr, "%s: only one input file\n", progname); 52070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine usage(); 52170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine } 52270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine /* default output file is stdout */ 52370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#ifdef USE_SETMODE /* need to hack file mode? */ 52470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine setmode(fileno(stdout), O_BINARY); 52570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#endif 52670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#ifdef USE_FDOPEN /* need to re-open in binary mode? */ 52770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if ((outfile = fdopen(fileno(stdout), WRITE_BINARY)) == NULL) { 52870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine fprintf(stderr, "%s: can't open stdout\n", progname); 52970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine exit(EXIT_FAILURE); 53070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine } 53170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#else 53270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine outfile = stdout; 53370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#endif 53470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine#endif /* TWO_FILE_COMMANDLINE */ 53570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 53670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine /* Collect comment text from comment_file or stdin, if necessary */ 53770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if (comment_arg == NULL) { 53870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine FILE * src_file; 53970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine int c; 54070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 54170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine comment_arg = (char *) malloc((size_t) MAX_COM_LENGTH); 54270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if (comment_arg == NULL) 54370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine ERREXIT("Insufficient memory"); 54470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine comment_length = 0; 54570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine src_file = (comment_file != NULL ? comment_file : stdin); 54670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine while ((c = getc(src_file)) != EOF) { 54770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if (comment_length >= (unsigned int) MAX_COM_LENGTH) { 54870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine fprintf(stderr, "Comment text may not exceed %u bytes\n", 54970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine (unsigned int) MAX_COM_LENGTH); 55070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine exit(EXIT_FAILURE); 55170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine } 55270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine comment_arg[comment_length++] = (char) c; 55370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine } 55470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if (comment_file != NULL) 55570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine fclose(comment_file); 55670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine } 55770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 55870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine /* Copy JPEG headers until SOFn marker; 55970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * we will insert the new comment marker just before SOFn. 56070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * This (a) causes the new comment to appear after, rather than before, 56170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * existing comments; and (b) ensures that comments come after any JFIF 56270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * or JFXX markers, as required by the JFIF specification. 56370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine */ 56470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine marker = scan_JPEG_header(keep_COM); 56570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine /* Insert the new COM marker, but only if nonempty text has been supplied */ 56670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine if (comment_length > 0) { 56770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine write_marker(M_COM); 56870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine write_2_bytes(comment_length + 2); 56970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine while (comment_length > 0) { 57070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine write_1_byte(*comment_arg++); 57170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine comment_length--; 57270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine } 57370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine } 57470a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine /* Duplicate the remainder of the source file. 57570a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine * Note that any COM markers occuring after SOF will not be touched. 57670a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine */ 57770a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine write_marker(marker); 57870a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine copy_rest_of_file(); 57970a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine 58070a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine /* All done. */ 58170a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine exit(EXIT_SUCCESS); 58270a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine return 0; /* suppress no-return-value warnings */ 58370a18cd874a22452aca9e39e22275ed4538ed20bVladimir Chtchetkine} 584