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