1 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
2 /*          EXIFPROBE - TIFF/JPEG/EXIF image file probe               */
3 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
4 /* Copyright (C) 2002,2005 by Duane H. Hesser. All rights reserved.   */
5 /*                                                                    */
6 /* See the file LICENSE.EXIFPROBE for terms of use.                   */
7 /* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
8 
9 #ifndef lint
10 static char *ModuleId = "@(#) $Id: readfile.c,v 1.30 2005/07/24 18:15:28 alex Exp $";
11 #endif
12 
13 /* This file contains routines for reading specific value types with  */
14 /* byte-swapping for integer values, specialized routines for         */
15 /* strings, a file header decoder for various imagefile types, and a  */
16 /* general IFD entry reader.                                          */
17 
18 /* The code needs to know the native byteorder of the machine, which  */
19 /* is currently not autoconfigured. If not sure, look for a file like */
20 /* <sys/endian.h>. "MOTOROLA" byteorder is "big-endian", "INTEL"      */
21 /* byteorder is "little-endian". The code does not currently handle   */
22 /* "pdp11" byteorder.                                                 */
23 
24 
25 #include <stdio.h>
26 #include <sys/types.h>
27 #include <string.h>
28 #include <ctype.h>
29 #include <errno.h>
30 #include "byteorder.h"
31 
32 #include "defs.h"
33 #include "datadefs.h"
34 #include "summary.h"
35 #include "misc.h"
36 #include "tags.h"
37 #include "extern.h"
38 #include "ciff.h"
39 #include "x3f.h"
40 
41 /* Read a short integer value in the expectation that it is a TIFF or */
42 /* JPEG header marker/tag. If a valid JPEG_SOI is found, we're done.  */
43 /* If the value is a TIFF indicator, but the TIFF magic marker is not */
44 /* found, the magic number is then checked for a valid ORF or CIFF    */
45 /* header. If the marker is not a recognized magic number/string,     */
46 /* start over and check for a JP2 header box, or MRW, RAF, or X3F     */
47 /* header.                                                            */
48 
49 /* When appropriage, ciff, mrw, x3f or jp2 header structures are      */
50 /* filled in and the fileheader magic set to indictate which is       */
51 /* valid.                                                             */
52 
53 /* The return is a fileheader structure containing an exifprobe       */
54 /* private "magic number" and appropriate information about the file  */
55 /* structure, if any.                                                 */
56 
57 
58 struct fileheader *
read_imageheader(FILE * inptr,unsigned long offset)59 read_imageheader(FILE *inptr,unsigned long offset)
60 {
61     static struct fileheader fileheader;
62     struct ciff_header *ciffheader;
63     struct jp2_header jp2header;
64     struct mrw_header mrwheader;
65     struct x3f_header *x3fheader;
66     unsigned short marker,magic;
67     unsigned char *type;
68     unsigned long umagic,length;
69     char *string;
70 
71     marker = 0;
72     fileheader.probe_magic = PROBE_NOMAGIC;
73     fileheader.file_marker = 0;
74     fileheader.ciff_header = NULL;
75     fileheader.x3f_header = NULL;
76     memset(&fileheader.jp2_header,'\0',sizeof(struct jp2_header));
77     memset(&fileheader.mrw_header,'\0',sizeof(struct mrw_header));
78     if(inptr && !feof(inptr) && !ferror(inptr))
79     {
80         /* The order of bytes for this read does not matter for TIFF, */
81         /* but must be high-byte first for JPEG.                      */
82         marker = read_ushort(inptr,TIFF_MOTOROLA,offset);
83         switch(marker)
84         {
85             case TIFF_MOTOROLA:
86             case TIFF_INTEL:
87                 if((magic = read_ushort(inptr,marker,HERE)) == TIFF_MAGIC)
88                 {
89                     fileheader.probe_magic = TIFF_MAGIC;
90                     fileheader.file_marker = marker;
91                 }
92                 else if(magic == ORF1_MAGIC)
93                 {
94                     fileheader.probe_magic = ORF1_MAGIC;
95                     fileheader.file_marker = marker;
96                 }
97                 else if(magic == ORF2_MAGIC)
98                 {
99                     fileheader.probe_magic = ORF2_MAGIC;
100                     fileheader.file_marker = marker;
101                 }
102                 else if((ciffheader = read_ciffheader(inptr,marker,offset)))
103                 {
104                     fileheader.file_marker = ciffheader->byteorder;
105                     fileheader.probe_magic = PROBE_CIFFMAGIC;
106                     fileheader.ciff_header = ciffheader;
107                 }
108                 else
109                 {
110                     fileheader.probe_magic = PROBE_NOMAGIC;
111                     fileheader.file_marker = 0;
112                     printf(" invalid TIFF magic (%#06x)",magic);
113                     printf(", apparent TIFF byteorder is ");
114                     print_byteorder(marker,1);
115                     (void)newline(0);
116                 }
117                 break;
118             case JPEG_SOI:
119                 fileheader.probe_magic = JPEG_SOI;
120                 fileheader.file_marker = marker;
121                 break;
122             default:
123                 fileheader.probe_magic = PROBE_NOMAGIC;
124                 fileheader.file_marker = 0;
125                 if(marker == 0)
126                 {
127                     /* check for jpeg2000                             */
128                     length = read_ulong(inptr,TIFF_MOTOROLA,offset);
129                     if(length == 12)
130                     {
131                         type = read_bytes(inptr,4,HERE);
132                         if((strncmp((char *)type,"jP\040\040  ",4) == 0) ||
133                             (strncmp((char *)type,"jP\032\032  ",4) == 0))
134                         {
135                             umagic = read_ulong(inptr,TIFF_MOTOROLA,HERE);
136                             if(umagic == 0x0d0a870a)
137                             {
138                                 fileheader.probe_magic = PROBE_JP2MAGIC;
139                                 fileheader.file_marker = 0;
140                                 jp2header.length = length;
141                                 jp2header.type = to_ulong(type,TIFF_MOTOROLA);
142                                 if(!ferror(inptr) && !feof(inptr))
143                                 {
144                                     jp2header.magic = umagic;
145                                     fileheader.jp2_header = jp2header;
146                                 }
147                             }
148                         }
149                     }
150                 }
151                 else if(marker == 0x004d)
152                 {
153                     umagic = read_ulong(inptr,TIFF_MOTOROLA,offset);
154                     if(umagic == 0x004d524d)
155                     {
156                         /* Minolta MRW */
157                         mrwheader.mrw_magic = umagic;
158                         mrwheader.mrw_dataoffset = read_ulong(inptr,TIFF_MOTOROLA,HERE);
159                         if(!ferror(inptr) && !feof(inptr))
160                         {
161                             fileheader.probe_magic = PROBE_MRWMAGIC;
162                             fileheader.mrw_header = mrwheader;
163                         }
164                     }
165                 }
166                 else if((marker == 0x5546) || (marker == 0x4655))
167                 {
168                     /* Fujifile RAF */
169                     string = read_string(inptr,offset,16);
170                     if(string && (strncmp(string,"FUJIFILMCCD-RAW ",16) == 0))
171                         fileheader.probe_magic = PROBE_RAFMAGIC;
172                 }
173                 else if(marker == 0x464f) /* "FO" */
174                 {
175                     /* Sigma/Foveon X3F */
176                     umagic = read_ulong(inptr,TIFF_INTEL,offset);
177                     if(umagic == PROBE_X3FMAGIC)
178                     {
179                         x3fheader = read_x3fheader(inptr,offset);
180                         if(x3fheader)
181                         {   fileheader.x3f_header = x3fheader;
182                             fileheader.probe_magic = PROBE_X3FMAGIC;
183                         }
184                     }
185                 }
186                 else
187                 {
188                     /* Unknown format                                 */
189                     fileheader.probe_magic = PROBE_NOMAGIC;
190                     fileheader.file_marker = 0;
191                     fileheader.ciff_header = NULL;
192                     fileheader.x3f_header = NULL;
193                 }
194                 break;
195         }
196     }
197     return(&fileheader);
198 }
199 
200 /* Read a generic TIFF IFD entry at the given offset, swapping        */
201 /* byteorder of entry values as required.                             */
202 
203 /* The return is a pointer to a static structure representing the     */
204 /* entry.                                                             */
205 
206 struct ifd_entry *
read_ifd_entry(FILE * inptr,unsigned short byteorder,unsigned long offset)207 read_ifd_entry(FILE *inptr,unsigned short byteorder,unsigned long offset)
208 {
209     static struct ifd_entry entry;
210     unsigned char *value;
211 
212     memset(&entry,0,sizeof(struct ifd_entry));
213     if(inptr && !feof(inptr) && !ferror(inptr))
214     {
215         entry.tag = read_ushort(inptr,byteorder,offset);
216         entry.value_type = read_ushort(inptr,byteorder,HERE);
217         entry.count = read_ulong(inptr,byteorder,HERE);
218         value = read_bytes(inptr,4,HERE);
219         if(value)
220         {
221             if((value_type_size(entry.value_type) * entry.count) > 4)
222                 entry.value = to_ulong(value,byteorder);    /* offset */
223             else    /* actual value(s)                                */
224             {
225                 entry.value = 0L;
226                 switch(entry.value_type)
227                 {
228                     case SSHORT:
229                     case SHORT:
230                         if(entry.count == 1)
231                             entry.value = to_ushort(value,byteorder);
232                         else
233                         {
234                             entry.value = to_ushort(value,byteorder);
235                             if(byteorder == TIFF_MOTOROLA)
236                                 entry.value |= (((unsigned long)to_ushort(value + 2,byteorder) & 0xffff) << 16);
237                             else
238                                 entry.value = (to_ushort(value + 2,byteorder) & 0xffff) |
239                                     ((entry.value & 0xffff) << 16);
240                         }
241                         break;
242                     case BYTE:
243                     case SBYTE:
244                     case UNDEFINED:
245                     case ASCII:
246                         entry.value = *(unsigned long *)value;
247                         break;
248                     case LONG:
249                     case SLONG:
250                     default:
251                         entry.value = to_ulong(value,byteorder);
252                         break;
253                 }
254             }
255         }
256         else
257             entry.value = 0L;
258     }
259     return(&entry);
260 }
261 
262 /* Read 2 bytes at the given offset and interpret them as an unsigned */
263 /* short integer value, swapping bytes as necessary.                  */
264 
265 unsigned short
read_ushort(FILE * inptr,unsigned short byteorder,unsigned long offset)266 read_ushort(FILE *inptr,unsigned short byteorder,unsigned long offset)
267 {
268     unsigned char rbuf[2];
269     unsigned long curoffset;
270     unsigned short value = 0;
271     int chpr = 0;
272 
273     if(inptr)
274     {
275         clearerr(inptr);
276         curoffset = ftell(inptr);
277         if((offset != HERE) && (fseek(inptr,offset,0) == -1))
278         {
279             printred(" SEEK FAILED to read unsigned short at offset ");
280             printf("%lu",offset);
281         }
282         else if(fread(rbuf,1,sizeof(unsigned short),inptr) == sizeof(unsigned short))
283             value = to_ushort(rbuf,byteorder);
284         else
285         {
286             printred(" FAILED to read unsigned short value at offset ");
287             if(offset == HERE)
288                 offset = curoffset;
289             chpr += printf("%lu",offset);
290         }
291         if(ferror(inptr))
292         {
293             chpr += printf(" (");
294             setcharsprinted(chpr);
295             chpr = 0;
296             printred(strerror(errno));
297             chpr += printf(")");
298             chpr = newline(chpr);
299         }
300         else if(feof(inptr))
301         {
302             printred(" (EOF)");
303             chpr = newline(chpr);
304         }
305     }
306     setcharsprinted(chpr);
307     return(value);
308 }
309 
310 /* read a single byte at the given offset and return it as an         */
311 /* unsigned short value                                               */
312 
313 unsigned short
read_ubyte(FILE * inptr,unsigned long offset)314 read_ubyte(FILE *inptr,unsigned long offset)
315 {
316     unsigned char rbuf[1];
317     unsigned long curoffset;
318     unsigned short value = 0;
319     int chpr = 0;
320 
321     if(inptr)
322     {
323         clearerr(inptr);
324         curoffset = ftell(inptr);
325         if((offset != HERE) && (fseek(inptr,offset,0) == -1))
326         {
327             printred(" SEEK FAILED to read unsigned byte at offset ");
328             chpr += printf("%lu",offset);
329         }
330         else if(fread(rbuf,1,1,inptr) == 1)
331             value = rbuf[0] & 0xff;
332         else
333         {
334             if(offset == HERE)
335                 offset = curoffset;
336             printred(" FAILED to read unsigned byte at offset ");
337             chpr += printf("%lu",offset);
338         }
339         if(ferror(inptr))
340         {
341             chpr += printf(" (");
342             setcharsprinted(chpr);
343             chpr = 0;
344             printred(strerror(errno));
345             chpr += printf(")");
346             chpr = newline(chpr);
347         }
348         else if(feof(inptr))
349         {
350             printred(" (EOF)");
351             chpr = newline(chpr);
352         }
353     }
354     setcharsprinted(chpr);
355     return(value);
356 }
357 
358 /* Read 4 bytes at the given offset and interpret as an unsigned long */
359 /* integer, swapping bytes as necessary                               */
360 
361 /* NOTE: the routine *reads* a 4 byte number, but returns it as an    */
362 /* unsigned long in the native machine size.                          */
363 
364 unsigned long
read_ulong(FILE * inptr,unsigned short byteorder,unsigned long offset)365 read_ulong(FILE *inptr,unsigned short byteorder,unsigned long offset)
366 {
367     unsigned char rbuf[4];
368     unsigned long curoffset;
369     unsigned long value = 0;
370     int chpr = 0;
371 
372     if(inptr)
373     {
374         clearerr(inptr);
375         curoffset = ftell(inptr);
376         if((offset != HERE) && (fseek(inptr,offset,0) == -1))
377         {
378             printred(" SEEK FAILED to read unsigned 32bit integer at offset ");
379             printf("%lu",offset);
380         }
381         else if(fread(rbuf,1,4,inptr) == 4)
382             value = to_ulong(rbuf,byteorder);
383         else
384         {
385             printred(" FAILED to read unsigned 32bit integer at offset ");
386             if(offset == HERE)
387                 offset = curoffset;
388             chpr += printf("%lu",offset);
389         }
390         if(ferror(inptr))
391         {
392             chpr += printf(" (");
393             setcharsprinted(chpr);
394             chpr = 0;
395             printred(strerror(errno));
396             chpr += printf(")");
397             chpr = newline(chpr);
398         }
399         else if(feof(inptr))
400         {
401             printred(" (EOF)");
402             chpr = newline(chpr);
403         }
404     }
405     setcharsprinted(chpr);
406     return(value);
407 }
408 
409 
410 float
read_float(FILE * inptr,unsigned short byteorder,unsigned long offset)411 read_float(FILE *inptr,unsigned short byteorder,unsigned long offset)
412 {
413     float value = 0.0;
414     unsigned long ulval;
415 
416     ulval = read_ulong(inptr,byteorder,offset);
417     value = to_float(ulval);
418     return(value);
419 }
420 
421 /* Read 8 bytes at the given offset and interpret as a long long,     */
422 /* swapping bytes as necessary.                                       */
423 
424 unsigned long long
read_ulong64(FILE * inptr,unsigned short byteorder,unsigned long offset)425 read_ulong64(FILE *inptr,unsigned short byteorder,unsigned long offset)
426 {
427     unsigned char rbuf[sizeof(double)];
428     unsigned long curoffset;
429     unsigned long long value = 0;
430     int chpr = 0;
431 
432     if(inptr)
433     {
434         clearerr(inptr);
435         curoffset = ftell(inptr);
436         if((offset != HERE) && (fseek(inptr,offset,0) == -1))
437             chpr += printf(" seek failed to offset %lu to read unsigned long\n",
438                     offset);
439         else if(fread(rbuf,1,sizeof(long long),inptr) == sizeof(long long))
440             value = to_ulong64(rbuf,byteorder);
441         else
442         {
443             printred(" FAILED to read unsigned 64bit integer at offset ");
444             if(offset == HERE)
445                 offset = curoffset;
446             chpr += printf("%lu\n",offset);
447         }
448     }
449     setcharsprinted(chpr);
450     return(value);
451 }
452 
453 unsigned long long
to_ulong64(unsigned char * buf,unsigned short byteorder)454 to_ulong64(unsigned char *buf,unsigned short byteorder)
455 {
456     unsigned long long value = 0;
457     unsigned char swap[sizeof(long long)];
458     unsigned char *p;
459     int i,size;
460 
461     if(buf)
462     {
463         p = buf;
464 #ifdef NATIVE_BYTEORDER_BIGENDIAN
465         if(byteorder == TIFF_INTEL)
466 #else
467         if(byteorder == TIFF_MOTOROLA)
468 #endif
469         {
470             size = sizeof(long long);
471             for(i = 0; i < size; ++i)
472                 swap[i] = buf[size - 1 - i];
473             p = swap;
474         }
475         value = *(long long *)p;
476     }
477     return(value);
478 }
479 
480 
481 
482 /* Read 8 bytes at the given offset and interpret as a double,        */
483 /* swapping bytes as necessary.                                       */
484 
485 double
read_double(FILE * inptr,unsigned short byteorder,unsigned long offset)486 read_double(FILE *inptr,unsigned short byteorder,unsigned long offset)
487 {
488     unsigned char rbuf[sizeof(double)];
489     unsigned long curoffset;
490     double value = 0.0;
491     int chpr = 0;
492 
493     if(inptr)
494     {
495         clearerr(inptr);
496         curoffset = ftell(inptr);
497         if((offset != HERE) && (fseek(inptr,offset,0) == -1))
498             chpr += printf(" seek failed to offset %lu to read unsigned long\n",
499                     offset);
500         else if(fread(rbuf,1,sizeof(double),inptr) == sizeof(double))
501             value = to_double(rbuf,byteorder);
502         else
503         {
504             if(offset == HERE)
505                 offset = curoffset;
506             PUSHCOLOR(RED);
507             chpr += printf(" failed to read double value at offset %lu\n",offset);
508             POPCOLOR();
509         }
510     }
511     setcharsprinted(chpr);
512     return(value);
513 }
514 
515 /* Read 'nbytes' of bytes at the given offset; no byte swapping.      */
516 /* The result is a chunk of bytes...not a string.                     */
517 
518 unsigned char *
read_bytes(FILE * inptr,unsigned long nbytes,unsigned long offset)519 read_bytes(FILE *inptr,unsigned long nbytes,unsigned long offset)
520 {
521     static unsigned char rbuf[MAXBUFLEN];
522     unsigned long curoffset;
523     unsigned char *value = (unsigned char *)NULLSTRING;
524     int chpr = 0;
525 
526     memset(rbuf,0,MAXBUFLEN);
527     if(inptr)
528     {
529         if(nbytes > MAXBUFLEN)
530         {
531             chpr += printf(" read %lu bytes would overrun buffer; truncating to %d\n",
532                                                                 nbytes,MAXBUFLEN);
533             nbytes = MAXBUFLEN;
534         }
535         if(nbytes)
536         {
537             if(inptr) /* ###%%% redundant; FIXME                      */
538             {
539                 clearerr(inptr);
540                 curoffset = ftell(inptr);
541                 if((offset != HERE) && (fseek(inptr,offset,0) == -1))
542                 {
543                     printred(" SEEK FAILED to read unsigned bytes at offset ");
544                     chpr += printf("%lu",offset);
545                 }
546                 else
547                 {
548                     if(fread(rbuf,1,nbytes,inptr) == nbytes)
549                         value = rbuf;
550                     else
551                     {
552                         if(offset == HERE)
553                             offset = curoffset;
554                         PUSHCOLOR(RED);
555                         chpr += printf(" FAILED to read %lu unsigned bytes at offset ",nbytes);
556                         chpr += printf("%lu",offset);
557                         POPCOLOR();
558                     }
559                 }
560                 if(ferror(inptr))
561                 {
562                     chpr += printf(" (");
563                     setcharsprinted(chpr);
564                     chpr = 0;
565                     printred(strerror(errno));
566                     chpr += printf(")");
567                     chpr = newline(chpr);
568                 }
569                 else if(feof(inptr))
570                 {
571                     printred(" (EOF)");
572                     chpr = newline(chpr);
573                 }
574             }
575         }
576     }
577     return(value);
578 }
579 
580 /* convert a couple of bytes to an unsigned short integer in native   */
581 /* byte order, swapping bytes if file byteorder differs.              */
582 /* If byteorder is not TIFF_INTEL or TIFF_MOTOROLA, the native byte   */
583 /* order is used.                                                     */
584 
585 unsigned short
to_ushort(unsigned char * buf,unsigned short byteorder)586 to_ushort(unsigned char *buf,unsigned short byteorder)
587 {
588     unsigned short value = 0;
589 
590     if(buf)
591     {
592         value = *(unsigned short *)buf;
593 #ifdef NATIVE_BYTEORDER_BIGENDIAN
594         if(byteorder == TIFF_INTEL)
595             value = (buf[1] << 8) | buf[0];
596 #else
597         if(byteorder == TIFF_MOTOROLA)
598             value = (buf[0] << 8) | buf[1];
599 #endif
600     }
601     return(value);
602 }
603 
604 /* convert a bunch of bytes to an unsigned long integer in native     */
605 /* byte order, swapping bytes if file byteorder differs.              */
606 /* If byteorder is not TIFF_INTEL or TIFF_MOTOROLA, the native byte   */
607 /* order is used.                                                     */
608 
609 unsigned long
to_ulong(unsigned char * buf,unsigned short byteorder)610 to_ulong(unsigned char *buf,unsigned short byteorder)
611 {
612     u_int32_t value = 0;
613 
614     if(buf)
615     {
616         value = *(u_int32_t *)buf;
617 #ifdef NATIVE_BYTEORDER_BIGENDIAN
618         if(byteorder == TIFF_INTEL)
619 #else
620         if(byteorder == TIFF_MOTOROLA)
621 #endif
622             value = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
623     }
624     return((unsigned long)value);
625 }
626 
627 /* convert a bunch of bytes to a 'float' value in native byte order,  */
628 /* swapping bytes if file byteorder differs. If byteorder is not      */
629 /* TIFF_INTEL or TIFF_MOTOROLA, the native byte order is used.        */
630 
631 /* This is pretty primitive; it assumes that the native floating      */
632 /* point format is the same as the floating point format written to   */
633 /* the image file, probably IEEE as required by the TIFF6             */
634 /* specification. See 'libtiff' for some conversion routines.         */
635 
636 float
to_float(unsigned long uval)637 to_float(unsigned long uval)
638 {
639     float value = 0.0;
640     unsigned long *uval_ptr = &uval;
641 
642     value = *(float *)uval_ptr;
643     return(value);
644 }
645 
646 /* convert a bunch of bytes to a 'double' value in native byte order, */
647 /* swapping bytes if file byteorder differs. If byteorder is not      */
648 /* TIFF_INTEL or TIFF_MOTOROLA, the native byte order is used.        */
649 
650 /* This is pretty primitive; it assumes that the native floating      */
651 /* point format is the same as the floating point format written to   */
652 /* the image file, probably IEEE as required by the TIFF6             */
653 /* specification. See 'libtiff' for some conversion routines.         */
654 
655 double
to_double(unsigned char * buf,unsigned short byteorder)656 to_double(unsigned char *buf,unsigned short byteorder)
657 {
658     double value = 0.0;
659     unsigned char swap[sizeof(double)];
660     unsigned char *p;
661     int i,size;
662 
663     if(buf)
664     {
665         p = buf;
666 #ifdef NATIVE_BYTEORDER_BIGENDIAN
667         if(byteorder == TIFF_INTEL)
668 #else
669         if(byteorder == TIFF_MOTOROLA)
670 #endif
671         {
672             size = sizeof(double);
673             for(i = 0; i < size; ++i)
674                 swap[i] = buf[size - 1 - i];
675             p = swap;
676         }
677         value = *(double *)p;
678     }
679     return(value);
680 }
681 
682 /* Read a few bytes at 'offset' which are expected to be a JPEG APPn  */
683 /* id string, where 'n' is given as an argument.                      */
684 
685 char *
read_appstring(FILE * inptr,unsigned short apptype,unsigned long offset)686 read_appstring(FILE *inptr,unsigned short apptype,unsigned long offset)
687 {
688     unsigned long length;
689     char *appstring = NULLSTRING;
690 
691 
692     if(inptr)
693     {
694         switch(apptype)
695         {
696             case JPEG_APP0:
697                 length = 32;    /* should be 5; allow for garbage     */
698                 break;
699             case JPEG_APP1:
700             case JPEG_APP2:
701                 length = 32;    /* should be 5; allow for garbage     */
702                 break;
703             default:
704                 length = 32;
705                 break;
706         }
707         if(length)
708             appstring = read_string(inptr,offset,length);
709     }
710     return(appstring);
711 }
712 
713 /* Read an ascii string, up to a null byte or 'max_bytes', at         */
714 /* 'offset' relative to the beginning of the file.                    */
715 /* Returns the string in static storage.  Use it or lose it.          */
716 
717 char *
read_string(FILE * inptr,unsigned long offset,unsigned long max_bytes)718 read_string(FILE *inptr,unsigned long offset,unsigned long max_bytes)
719 {
720     static char stringbuf[MAXBUFLEN];
721     unsigned long curoffset;
722     char *bufp;
723     int nread = 0;
724     int chpr = 0;
725 
726     bufp = stringbuf;
727     *bufp = '\0';
728 
729     if(inptr)
730     {
731         clearerr(inptr);
732         curoffset = ftell(inptr);
733         if((offset != HERE) && (fseek(inptr,offset,0) == -1))
734         {
735             printred(" SEEK FAILED to read ascii string at offset ");
736             chpr += printf("%lu",offset);
737         }
738         else if(max_bytes > 0)
739         {
740             if(max_bytes > MAXBUFLEN)
741                 max_bytes = MAXBUFLEN - 2;
742             while((nread < max_bytes) &&
743                     (*bufp = fgetc(inptr)) &&
744                         !feof(inptr) &&
745                             !ferror(inptr) &&
746                                     isascii(*bufp++))
747             {
748                     ++nread;
749             }
750             *bufp = '\0';
751             if(feof(inptr) || ferror(inptr))
752             {
753                 if(offset == HERE)
754                     offset = curoffset;
755                 PUSHCOLOR(RED);
756                 chpr += printf(" FAILED to read character at offset ");
757                 chpr += printf("%lu",offset);
758                 POPCOLOR();
759                 if(ferror(inptr))
760                 {
761                     chpr += printf(" (");
762                     setcharsprinted(chpr);
763                     chpr = 0;
764                     printred(strerror(errno));
765                     chpr += printf(")");
766                     chpr = newline(chpr);
767                 }
768                 else if(feof(inptr))
769                 {
770                     printred(" (EOF)");
771                     chpr = newline(chpr);
772                 }
773             }
774         }
775     }
776     setcharsprinted(chpr);
777     return(stringbuf);
778 }
779 
780 int
ateof(FILE * inptr)781 ateof(FILE *inptr)
782 {
783     int atend = 0;
784     if(feof(inptr))
785         atend++;
786     else if(fgetc(inptr) == -1)
787         atend++;
788     return(atend);
789 }
790 
791 /* Get the size of the file open on the argument stream, by seeking   */
792 /* to the end and enquiring of the resulting offset. Return the file  */
793 /* offset to its original location. If anything goes wrong, return 0, */
794 /* indicating failure (or a zero length file).                        */
795 
796 unsigned long
get_filesize(FILE * inptr)797 get_filesize(FILE *inptr)
798 {
799     unsigned long size = 0L;
800     long current_offset;
801 
802     if(inptr)
803     {
804         clearerr(inptr);
805         /* move back here after getting the size                      */
806         current_offset = ftell(inptr);
807         if(fseek(inptr,0L,2) == 0)
808         {
809             size = ftell(inptr);
810             if(fseek(inptr,current_offset,0) != 0)
811                 clearerr(inptr);    /* silently                       */
812         }
813         else
814             size = 0L;
815     }
816     return(size);
817 }
818