1 /**************************************************************************
2 pmfileio.c
3 ***************************************************************************
4 This file contains fundamental file I/O stuff for libnetpbm.
5 These are external functions, unlike 'fileio.c', but are not
6 particular to any Netpbm format.
7 **************************************************************************/
8 #define _DEFAULT_SOURCE /* New name for SVID & BSD source defines */
9 #define _SVID_SOURCE
10 /* Make sure P_tmpdir is defined in GNU libc 2.0.7 (_XOPEN_SOURCE 500
11 does it in other libc's). pm_config.h defines TMPDIR as P_tmpdir
12 in some environments.
13 */
14 #define _BSD_SOURCE /* Make sure strdup is defined */
15 #define _XOPEN_SOURCE 500 /* Make sure ftello, fseeko, strdup are defined */
16 #define _LARGEFILE_SOURCE 1 /* Make sure ftello, fseeko are defined */
17 #define _LARGEFILE64_SOURCE 1
18 #define _FILE_OFFSET_BITS 64
19 /* This means ftello() is really ftello64() and returns a 64 bit file
20 position. Unless the C library doesn't have ftello64(), in which
21 case ftello() is still just ftello().
22
23 Likewise for all the other C library file functions.
24
25 And off_t and fpos_t are 64 bit types instead of 32. Consequently,
26 pm_filepos_t might be 64 bits instead of 32.
27 */
28 #define _LARGE_FILES
29 /* This does for AIX what _FILE_OFFSET_BITS=64 does for GNU */
30 #define _LARGE_FILE_API
31 /* This makes the the x64() functions available on AIX */
32
33 #include "netpbm/pm_config.h"
34 #include <unistd.h>
35 #include <assert.h>
36 #include <stdio.h>
37 #include <fcntl.h>
38 #include <stdarg.h>
39 #include <string.h>
40 #include <errno.h>
41 #if HAVE_IO_H
42 #include <io.h> /* For mktemp */
43 #endif
44
45 #include "netpbm/pm_c_util.h"
46 #include "netpbm/mallocvar.h"
47 #include "netpbm/nstring.h"
48
49 #include "pm.h"
50
51
52
53 /* File open/close that handles "-" as stdin/stdout and checks errors. */
54
55 FILE *
pm_openr(const char * const name)56 pm_openr(const char * const name) {
57 FILE * f;
58
59 if (streq(name, "-"))
60 f = stdin;
61 else {
62 f = fopen(name, "rb");
63 if (f == NULL)
64 pm_error("Unable to open file '%s' for reading. "
65 "fopen() returns errno %d (%s)",
66 name, errno, strerror(errno));
67 }
68 return f;
69 }
70
71
72
73 FILE *
pm_openw(const char * const name)74 pm_openw(const char * const name) {
75 FILE * f;
76
77 if (streq(name, "-"))
78 f = stdout;
79 else {
80 f = fopen(name, "wb");
81 if (f == NULL)
82 pm_error("Unable to open file '%s' for writing. "
83 "fopen() returns errno %d (%s)",
84 name, errno, strerror(errno));
85 }
86 return f;
87 }
88
89
90
91 static const char *
tmpDir(void)92 tmpDir(void) {
93 /*----------------------------------------------------------------------------
94 Return the name of the directory in which we should create temporary
95 files.
96
97 The name is a constant in static storage.
98 -----------------------------------------------------------------------------*/
99 const char * tmpdir;
100 /* running approximation of the result */
101
102 tmpdir = getenv("TMPDIR"); /* Unix convention */
103
104 if (!tmpdir || strlen(tmpdir) == 0)
105 tmpdir = getenv("TMP"); /* Windows convention */
106
107 if (!tmpdir || strlen(tmpdir) == 0)
108 tmpdir = getenv("TEMP"); /* Windows convention */
109
110 if (!tmpdir || strlen(tmpdir) == 0)
111 tmpdir = TMPDIR;
112
113 return tmpdir;
114 }
115
116
117
118 static int
tempFileOpenFlags(void)119 tempFileOpenFlags(void) {
120 /*----------------------------------------------------------------------------
121 Open flags (argument to open()) suitable for a new temporary file
122 -----------------------------------------------------------------------------*/
123 int retval;
124
125 retval = 0
126 | O_CREAT
127 | O_RDWR
128 #if !MSVCRT
129 | O_EXCL
130 #endif
131 #if MSVCRT
132 | O_BINARY
133 #endif
134 ;
135
136 return retval;
137 }
138
139
140
141
142 static int
mkstempx(char * const filenameBuffer)143 mkstempx(char * const filenameBuffer) {
144 /*----------------------------------------------------------------------------
145 This is meant to be equivalent to POSIX mkstemp().
146
147 On some old systems, mktemp() is a security hazard that allows a hacker
148 to read or write our temporary file or cause us to read or write some
149 unintended file. On other systems, mkstemp() does not exist.
150
151 A Windows/mingw environment is one which doesn't have mkstemp()
152 (2006.06.15).
153
154 We assume that if a system doesn't have mkstemp() that its mktemp()
155 is safe, or that the total situation is such that the problems of
156 mktemp() are not a problem for the user.
157 -----------------------------------------------------------------------------*/
158 int retval;
159 int fd;
160 unsigned int attempts;
161 bool gotFile;
162 bool error;
163
164 for (attempts = 0, gotFile = FALSE, error = FALSE;
165 !gotFile && !error && attempts < 100;
166 ++attempts) {
167
168 char * rc;
169 rc = mktemp(filenameBuffer);
170
171 if (rc == NULL)
172 error = TRUE;
173 else {
174 int rc;
175
176 rc = open(filenameBuffer, tempFileOpenFlags(),
177 PM_S_IWUSR | PM_S_IRUSR);
178
179 if (rc >= 0) {
180 fd = rc;
181 gotFile = TRUE;
182 } else {
183 if (errno == EEXIST) {
184 /* We'll just have to keep trying */
185 } else
186 error = TRUE;
187 }
188 }
189 }
190 if (gotFile)
191 retval = fd;
192 else
193 retval = -1;
194
195 return retval;
196 }
197
198
199
200 static int
mkstemp2(char * const filenameBuffer)201 mkstemp2(char * const filenameBuffer) {
202
203 #if HAVE_MKSTEMP
204 if (0)
205 mkstempx(NULL); /* defeat compiler unused function warning */
206 return mkstemp(filenameBuffer);
207 #else
208 return mkstempx(filenameBuffer);
209 #endif
210 }
211
212
213
214 static void
makeTmpfileWithTemplate(const char * const filenameTemplate,int * const fdP,const char ** const filenameP,const char ** const errorP)215 makeTmpfileWithTemplate(const char * const filenameTemplate,
216 int * const fdP,
217 const char ** const filenameP,
218 const char ** const errorP) {
219
220 char * filenameBuffer; /* malloc'ed */
221
222 filenameBuffer = strdup(filenameTemplate);
223
224 if (filenameBuffer == NULL)
225 pm_asprintf(errorP, "Unable to allocate storage for temporary "
226 "file name");
227 else {
228 int rc;
229
230 rc = mkstemp2(filenameBuffer);
231
232 if (rc < 0)
233 pm_asprintf(errorP,
234 "Unable to create temporary file according to name "
235 "pattern '%s'. mkstemp() failed with errno %d (%s)",
236 filenameTemplate, errno, strerror(errno));
237 else {
238 *fdP = rc;
239 *filenameP = filenameBuffer;
240 *errorP = NULL;
241 }
242 if (*errorP)
243 pm_strfree(filenameBuffer);
244 }
245 }
246
247
248
249 void
pm_make_tmpfile_fd(int * const fdP,const char ** const filenameP)250 pm_make_tmpfile_fd(int * const fdP,
251 const char ** const filenameP) {
252
253 const char * filenameTemplate;
254 const char * tmpdir;
255 const char * dirseparator;
256 const char * error;
257
258 tmpdir = tmpDir();
259
260 if (tmpdir[strlen(tmpdir) - 1] == '/')
261 dirseparator = "";
262 else
263 dirseparator = "/";
264
265 pm_asprintf(&filenameTemplate, "%s%s%s%s",
266 tmpdir, dirseparator, pm_progname, "_XXXXXX");
267
268 if (filenameTemplate == pm_strsol)
269 pm_asprintf(&error,
270 "Unable to allocate storage for temporary file name");
271 else {
272 makeTmpfileWithTemplate(filenameTemplate, fdP, filenameP, &error);
273
274 pm_strfree(filenameTemplate);
275 }
276 if (error) {
277 pm_errormsg("%s", error);
278 pm_strfree(error);
279 pm_longjmp();
280 }
281 }
282
283
284
285 void
pm_make_tmpfile(FILE ** const filePP,const char ** const filenameP)286 pm_make_tmpfile(FILE ** const filePP,
287 const char ** const filenameP) {
288
289 int fd;
290
291 pm_make_tmpfile_fd(&fd, filenameP);
292
293 *filePP = fdopen(fd, "w+b");
294
295 if (*filePP == NULL) {
296 close(fd);
297 unlink(*filenameP);
298 pm_strfree(*filenameP);
299
300 pm_error("Unable to create temporary file. "
301 "fdopen() failed with errno %d (%s)",
302 errno, strerror(errno));
303 }
304 }
305
306
307
308 bool const canUnlinkOpen =
309 #if CAN_UNLINK_OPEN
310 1
311 #else
312 0
313 #endif
314 ;
315
316
317
318 typedef struct UnlinkListEntry {
319 /*----------------------------------------------------------------------------
320 This is an entry in the linked list of files to close and unlink as the
321 program exits.
322 -----------------------------------------------------------------------------*/
323 struct UnlinkListEntry * next;
324 int fd;
325 char fileName[1]; /* Actually variable length */
326 } UnlinkListEntry;
327
328 static UnlinkListEntry * unlinkListP;
329
330
331
332 static void
unlinkTempFiles(void)333 unlinkTempFiles(void) {
334 /*----------------------------------------------------------------------------
335 Close and unlink (so presumably delete) the files in the list
336 *unlinkListP.
337
338 This is an atexit function.
339 -----------------------------------------------------------------------------*/
340 while (unlinkListP) {
341 UnlinkListEntry * const firstEntryP = unlinkListP;
342
343 unlinkListP = unlinkListP->next;
344
345 close(firstEntryP->fd);
346 unlink(firstEntryP->fileName);
347
348 free(firstEntryP);
349 }
350 }
351
352
353
354 static UnlinkListEntry *
newUnlinkListEntry(const char * const fileName,int const fd)355 newUnlinkListEntry(const char * const fileName,
356 int const fd) {
357
358 UnlinkListEntry * const unlinkListEntryP =
359 malloc(sizeof(*unlinkListEntryP) + strlen(fileName) + 1);
360
361 if (unlinkListEntryP) {
362 strcpy(unlinkListEntryP->fileName, fileName);
363 unlinkListEntryP->fd = fd;
364 unlinkListEntryP->next = NULL;
365 }
366 return unlinkListEntryP;
367 }
368
369
370
371 static void
addUnlinkListEntry(const char * const fileName,int const fd)372 addUnlinkListEntry(const char * const fileName,
373 int const fd) {
374
375 UnlinkListEntry * const unlinkListEntryP =
376 newUnlinkListEntry(fileName, fd);
377
378 if (unlinkListEntryP) {
379 unlinkListEntryP->next = unlinkListP;
380 unlinkListP = unlinkListEntryP;
381 }
382 }
383
384
385
386 static void
scheduleUnlinkAtExit(const char * const fileName,int const fd)387 scheduleUnlinkAtExit(const char * const fileName,
388 int const fd) {
389 /*----------------------------------------------------------------------------
390 Set things up to have the file unlinked as the program exits.
391
392 This is messy and probably doesn't work in all situations; it is a hack
393 to get Unix code essentially working on Windows, without messing up the
394 code too badly for Unix.
395 -----------------------------------------------------------------------------*/
396 static bool unlinkListEstablished = false;
397
398 if (!unlinkListEstablished) {
399 atexit(unlinkTempFiles);
400 unlinkListP = NULL;
401 unlinkListEstablished = true;
402 }
403
404 addUnlinkListEntry(fileName, fd);
405 }
406
407
408
409 static void
arrangeUnlink(const char * const fileName,int const fd)410 arrangeUnlink(const char * const fileName,
411 int const fd) {
412
413 if (canUnlinkOpen)
414 unlink(fileName);
415 else
416 scheduleUnlinkAtExit(fileName, fd);
417 }
418
419
420
421 FILE *
pm_tmpfile(void)422 pm_tmpfile(void) {
423
424 FILE * fileP;
425 const char * tmpfileNm;
426
427 pm_make_tmpfile(&fileP, &tmpfileNm);
428
429 arrangeUnlink(tmpfileNm, fileno(fileP));
430
431 pm_strfree(tmpfileNm);
432
433 return fileP;
434 }
435
436
437
438 int
pm_tmpfile_fd(void)439 pm_tmpfile_fd(void) {
440
441 int fd;
442 const char * tmpfileNm;
443
444 pm_make_tmpfile_fd(&fd, &tmpfileNm);
445
446 arrangeUnlink(tmpfileNm, fd);
447
448 pm_strfree(tmpfileNm);
449
450 return fd;
451 }
452
453
454
455 FILE *
pm_openr_seekable(const char name[])456 pm_openr_seekable(const char name[]) {
457 /*----------------------------------------------------------------------------
458 Open the file named by name[] such that it is seekable (i.e. it can be
459 rewound and read in multiple passes with fseek()).
460
461 If the file is actually seekable, this reduces to the same as
462 pm_openr(). If not, we copy the named file to a temporary file
463 and return that file's stream descriptor.
464
465 We use a file that the operating system recognizes as temporary, so
466 it picks the filename and deletes the file when Caller closes it.
467 -----------------------------------------------------------------------------*/
468 int stat_rc;
469 int seekable; /* logical: file is seekable */
470 struct stat statbuf;
471 FILE * original_file;
472 FILE * seekable_file;
473
474 original_file = pm_openr((char *) name);
475
476 /* I would use fseek() to determine if the file is seekable and
477 be a little more general than checking the type of file, but I
478 don't have reliable information on how to do that. I have seen
479 streams be partially seekable -- you can, for example seek to
480 0 if the file is positioned at 0 but you can't actually back up
481 to 0. I have seen documentation that says the errno for an
482 unseekable stream is EBADF and in practice seen ESPIPE.
483
484 On the other hand, regular files are always seekable and even if
485 some other file is, it doesn't hurt much to assume it isn't.
486 */
487
488 stat_rc = fstat(fileno(original_file), &statbuf);
489 if (stat_rc == 0 && S_ISREG(statbuf.st_mode))
490 seekable = TRUE;
491 else
492 seekable = FALSE;
493
494 if (seekable) {
495 seekable_file = original_file;
496 } else {
497 seekable_file = pm_tmpfile();
498
499 /* Copy the input into the temporary seekable file */
500 while (!feof(original_file) && !ferror(original_file)
501 && !ferror(seekable_file)) {
502 char buffer[4096];
503 int bytes_read;
504 bytes_read = fread(buffer, 1, sizeof(buffer), original_file);
505 fwrite(buffer, 1, bytes_read, seekable_file);
506 }
507 if (ferror(original_file))
508 pm_error("Error reading input file into temporary file. "
509 "Errno = %s (%d)", strerror(errno), errno);
510 if (ferror(seekable_file))
511 pm_error("Error writing input into temporary file. "
512 "Errno = %s (%d)", strerror(errno), errno);
513 pm_close(original_file);
514 {
515 int seek_rc;
516 seek_rc = fseek(seekable_file, 0, SEEK_SET);
517 if (seek_rc != 0)
518 pm_error("fseek() failed to rewind temporary file. "
519 "Errno = %s (%d)", strerror(errno), errno);
520 }
521 }
522 return seekable_file;
523 }
524
525
526
527 void
pm_close(FILE * const f)528 pm_close(FILE * const f) {
529 fflush(f);
530 if (ferror(f))
531 pm_message("A file read or write error occurred at some point");
532 if (f != stdin)
533 if (fclose(f) != 0)
534 pm_error("close of file failed with errno %d (%s)",
535 errno, strerror(errno));
536 }
537
538
539
540 /* The pnmtopng package uses pm_closer() and pm_closew() instead of
541 pm_close(), apparently because the 1999 Pbmplus package has them.
542 I don't know what the difference is supposed to be.
543 */
544
545 void
pm_closer(FILE * const f)546 pm_closer(FILE * const f) {
547 pm_close(f);
548 }
549
550
551
552 void
pm_closew(FILE * const f)553 pm_closew(FILE * const f) {
554 pm_close(f);
555 }
556
557
558
559 /* Endian I/O.
560
561 Before Netpbm 10.27 (March 2005), these would return failure on EOF
562 or I/O failure. For backward compatibility, they still have the return
563 code, but it is always zero and the routines abort the program in case
564 of EOF or I/O failure. A program that wants to handle failure differently
565 must use lower level (C library) interfaces. But that level of detail
566 is uncharacteristic of a Netpbm program; the ease of programming that
567 comes with not checking a return code is more Netpbm.
568
569 It is also for historical reasons that these return signed values,
570 when clearly unsigned would make more sense.
571 */
572
573
574
575 static void
abortWithReadError(FILE * const ifP)576 abortWithReadError(FILE * const ifP) {
577
578 if (feof(ifP))
579 pm_error("Unexpected end of input file");
580 else
581 pm_error("Error (not EOF) reading file.");
582 }
583
584
585
586 static unsigned char
getcNofail(FILE * const ifP)587 getcNofail(FILE * const ifP) {
588
589 int c;
590
591 c = getc(ifP);
592
593 if (c == EOF)
594 abortWithReadError(ifP);
595
596 return (unsigned char)c;
597 }
598
599
600
601 void
pm_readchar(FILE * const ifP,char * const cP)602 pm_readchar(FILE * const ifP,
603 char * const cP) {
604
605 *cP = (char)getcNofail(ifP);
606 }
607
608
609
610 void
pm_writechar(FILE * const ofP,char const c)611 pm_writechar(FILE * const ofP,
612 char const c) {
613
614 putc(c, ofP);
615 }
616
617
618
619 int
pm_readbigshort(FILE * const ifP,short * const sP)620 pm_readbigshort(FILE * const ifP,
621 short * const sP) {
622
623 unsigned short s;
624
625 s = getcNofail(ifP) << 8;
626 s |= getcNofail(ifP) << 0;
627
628 *sP = s;
629
630 return 0;
631 }
632
633
634
635 int
pm_writebigshort(FILE * const ofP,short const s)636 pm_writebigshort(FILE * const ofP,
637 short const s) {
638
639 putc((s >> 8) & 0xff, ofP);
640 putc(s & 0xff, ofP);
641
642 return 0;
643 }
644
645
646
647 int
pm_readbiglong(FILE * const ifP,long * const lP)648 pm_readbiglong(FILE * const ifP,
649 long * const lP) {
650
651 unsigned long l;
652
653 l = getcNofail(ifP) << 24;
654 l |= getcNofail(ifP) << 16;
655 l |= getcNofail(ifP) << 8;
656 l |= getcNofail(ifP) << 0;
657
658 *lP = l;
659
660 return 0;
661 }
662
663
664
665 int
pm_readbiglong2(FILE * const ifP,int32_t * const lP)666 pm_readbiglong2(FILE * const ifP,
667 int32_t * const lP) {
668 int rc;
669 long l;
670
671 rc = pm_readbiglong(ifP, &l);
672
673 assert((int32_t)l == l);
674
675 *lP = (int32_t)l;
676
677 return rc;
678 }
679
680
681
682 int
pm_writebiglong(FILE * const ofP,long const l)683 pm_writebiglong(FILE * const ofP,
684 long const l) {
685
686 putc((l >> 24) & 0xff, ofP);
687 putc((l >> 16) & 0xff, ofP);
688 putc((l >> 8) & 0xff, ofP);
689 putc((l >> 0) & 0xff, ofP);
690
691 return 0;
692 }
693
694
695
696 int
pm_readlittleshort(FILE * const ifP,short * const sP)697 pm_readlittleshort(FILE * const ifP,
698 short * const sP) {
699 unsigned short s;
700
701 s = getcNofail(ifP) << 0;
702 s |= getcNofail(ifP) << 8;
703
704 *sP = s;
705
706 return 0;
707 }
708
709
710
711 int
pm_writelittleshort(FILE * const ofP,short const s)712 pm_writelittleshort(FILE * const ofP,
713 short const s) {
714
715 putc((s >> 0) & 0xff, ofP);
716 putc((s >> 8) & 0xff, ofP);
717
718 return 0;
719 }
720
721
722
723 int
pm_readlittlelong(FILE * const ifP,long * const lP)724 pm_readlittlelong(FILE * const ifP,
725 long * const lP) {
726 unsigned long l;
727
728 l = getcNofail(ifP) << 0;
729 l |= getcNofail(ifP) << 8;
730 l |= getcNofail(ifP) << 16;
731 l |= getcNofail(ifP) << 24;
732
733 *lP = l;
734
735 return 0;
736 }
737
738
739
740 int
pm_readlittlelong2(FILE * const ifP,int32_t * const lP)741 pm_readlittlelong2(FILE * const ifP,
742 int32_t * const lP) {
743 int rc;
744 long l;
745
746 rc = pm_readlittlelong(ifP, &l);
747
748 assert((int32_t)l == l);
749
750 *lP = (int32_t)l;
751
752 return rc;
753 }
754
755
756
757 int
pm_writelittlelong(FILE * const ofP,long const l)758 pm_writelittlelong(FILE * const ofP,
759 long const l) {
760
761 putc((l >> 0) & 0xff, ofP);
762 putc((l >> 8) & 0xff, ofP);
763 putc((l >> 16) & 0xff, ofP);
764 putc((l >> 24) & 0xff, ofP);
765
766 return 0;
767 }
768
769
770
771 int
pm_readmagicnumber(FILE * const ifP)772 pm_readmagicnumber(FILE * const ifP) {
773
774 int ich1, ich2;
775
776 ich1 = getc(ifP);
777
778 if (ich1 == EOF)
779 pm_error("Error reading first byte of what is expected to be "
780 "a Netpbm magic number. "
781 "Most often, this means your input file is empty");
782
783 ich2 = getc(ifP);
784
785 if (ich2 == EOF)
786 pm_error("Error reading second byte of what is expected to be "
787 "a Netpbm magic number (the first byte was successfully "
788 "read as 0x%02x)", ich1);
789
790 return ich1 * 256 + ich2;
791 }
792
793
794
795 /* Read a file of unknown size to a buffer. Return the number of bytes
796 read. Allocate more memory as we need it. The calling routine has
797 to free() the buffer.
798
799 Oliver Trepte, oliver@fysik4.kth.se, 930613
800 */
801
802 #define PM_BUF_SIZE 16384 /* First try this size of the buffer, then
803 double this until we reach PM_MAX_BUF_INC */
804 #define PM_MAX_BUF_INC 65536 /* Don't allocate more memory in larger blocks
805 than this. */
806
807 char *
pm_read_unknown_size(FILE * const file,long * const nread)808 pm_read_unknown_size(FILE * const file,
809 long * const nread) {
810 long nalloc;
811 char * buf;
812 bool eof;
813
814 *nread = 0;
815 nalloc = PM_BUF_SIZE;
816 MALLOCARRAY(buf, nalloc);
817
818 if (!buf)
819 pm_error("Failed to allocate %lu bytes for read buffer",
820 (unsigned long) nalloc);
821
822 eof = FALSE; /* initial value */
823
824 while(!eof) {
825 int val;
826
827 if (*nread >= nalloc) { /* We need a larger buffer */
828 if (nalloc > PM_MAX_BUF_INC)
829 nalloc += PM_MAX_BUF_INC;
830 else
831 nalloc += nalloc;
832 REALLOCARRAY(buf, nalloc);
833 if (!buf)
834 pm_error("Failed to allocate %lu bytes for read buffer",
835 (unsigned long) nalloc);
836 }
837
838 val = getc(file);
839 if (val == EOF)
840 eof = TRUE;
841 else
842 buf[(*nread)++] = val;
843 }
844 return buf;
845 }
846
847
848
849 void
pm_getline(FILE * const ifP,char ** const bufferP,size_t * const bufferSzP,int * const eofP,size_t * const lineLenP)850 pm_getline(FILE * const ifP,
851 char ** const bufferP,
852 size_t * const bufferSzP,
853 int * const eofP,
854 size_t * const lineLenP) {
855 /*----------------------------------------------------------------------------
856 This is like POSIX 'getline'.
857
858 But we don't include the newline in the returned line.
859 -----------------------------------------------------------------------------*/
860 char * buffer;
861 size_t bufferSz;
862 bool gotLine;
863 bool eof;
864 size_t nReadSoFar;
865
866 buffer = *bufferP; /* initial value */
867 bufferSz = *bufferSzP; /* initial value */
868
869 for (nReadSoFar = 0, gotLine = false, eof = false;
870 !gotLine && !eof; ) {
871
872 int rc;
873
874 rc = fgetc(ifP);
875
876 if (rc == EOF) {
877 if (ferror(ifP))
878 pm_error("Error reading input file. fgets() failed with "
879 "errno %d (%s)", errno, strerror(errno));
880
881 if (nReadSoFar == 0) {
882 /* Didn't get anything before EOF, so return EOF */
883 eof = true;
884 } else {
885 /* End of file ends the line */
886 gotLine = true;
887 }
888 } else {
889 char const c = (char)rc;
890
891 if (c == '\n') {
892 /* Newline ends the line, and is not part of it */
893 gotLine = true;
894 } else {
895 if (nReadSoFar + 2 > bufferSz) {
896 /* + 2 = 1 for 'c', one for terminating NUL */
897 bufferSz += 128;
898 REALLOCARRAY(buffer, bufferSz);
899 if (!buffer) {
900 pm_error("Failed to allocate %lu bytes for buffer "
901 "to assemble a line of input",
902 (unsigned long) bufferSz);
903 }
904 }
905 buffer[nReadSoFar++] = c;
906 }
907 }
908 }
909
910 if (gotLine) {
911 bufferSz = nReadSoFar + 1;
912 REALLOCARRAY(buffer, bufferSz);
913 if (!buffer) {
914 pm_error("Failed to allocate %lu bytes for buffer "
915 "to assemble a line of input",
916 (unsigned long) bufferSz);
917 }
918 buffer[nReadSoFar] = '\0';
919 }
920
921 *eofP = eof;
922 *bufferP = buffer;
923 *bufferSzP = bufferSz;
924 *lineLenP = nReadSoFar;
925 }
926
927
928
929 union cheat {
930 uint32_t l;
931 short s;
932 unsigned char c[4];
933 };
934
935
936
937 short
pm_bs_short(short const s)938 pm_bs_short(short const s) {
939 union cheat u;
940 unsigned char t;
941
942 u.s = s;
943 t = u.c[0];
944 u.c[0] = u.c[1];
945 u.c[1] = t;
946 return u.s;
947 }
948
949
950
951 long
pm_bs_long(long const l)952 pm_bs_long(long const l) {
953 union cheat u;
954 unsigned char t;
955
956 u.l = l;
957 t = u.c[0];
958 u.c[0] = u.c[3];
959 u.c[3] = t;
960 t = u.c[1];
961 u.c[1] = u.c[2];
962 u.c[2] = t;
963 return u.l;
964 }
965
966
967
968 void
pm_tell2(FILE * const fileP,void * const fileposP,unsigned int const fileposSize)969 pm_tell2(FILE * const fileP,
970 void * const fileposP,
971 unsigned int const fileposSize) {
972 /*----------------------------------------------------------------------------
973 Return the current file position as *filePosP, which is a buffer
974 'fileposSize' bytes long. Abort the program if error, including if
975 *fileP isn't a file that has a position.
976 -----------------------------------------------------------------------------*/
977 /* Note: FTELLO() is either ftello() or ftell(), depending on the
978 capabilities of the underlying C library. It is defined in
979 pm_config.h. ftello(), in turn, may be either ftell() or
980 ftello64(), as implemented by the C library.
981 */
982 pm_filepos const filepos = FTELLO(fileP);
983 if (filepos < 0)
984 pm_error("ftello() to get current file position failed. "
985 "Errno = %s (%d)\n", strerror(errno), errno);
986
987 if (fileposSize == sizeof(pm_filepos)) {
988 pm_filepos * const fileposP_filepos = fileposP;
989 *fileposP_filepos = filepos;
990 } else if (fileposSize == sizeof(long)) {
991 if (sizeof(pm_filepos) > sizeof(long) &&
992 filepos >= (pm_filepos) 1 << (sizeof(long)*8))
993 pm_error("File size is too large to represent in the %u bytes "
994 "that were provided to pm_tell2()", fileposSize);
995 else {
996 long * const fileposP_long = fileposP;
997 *fileposP_long = (long)filepos;
998 }
999 } else
1000 pm_error("File position size passed to pm_tell() is invalid: %u. "
1001 "Valid sizes are %u and %u",
1002 fileposSize, (unsigned int)sizeof(pm_filepos),
1003 (unsigned int) sizeof(long));
1004 }
1005
1006
1007
1008 unsigned int
pm_tell(FILE * const fileP)1009 pm_tell(FILE * const fileP) {
1010
1011 long filepos;
1012
1013 pm_tell2(fileP, &filepos, sizeof(filepos));
1014
1015 return filepos;
1016 }
1017
1018
1019
1020 void
pm_seek2(FILE * const fileP,const pm_filepos * const fileposP,unsigned int const fileposSize)1021 pm_seek2(FILE * const fileP,
1022 const pm_filepos * const fileposP,
1023 unsigned int const fileposSize) {
1024 /*----------------------------------------------------------------------------
1025 Position file *fileP to position *fileposP. Abort if error, including
1026 if *fileP isn't a seekable file.
1027 -----------------------------------------------------------------------------*/
1028 if (fileposSize == sizeof(pm_filepos))
1029 /* Note: FSEEKO() is either fseeko() or fseek(), depending on the
1030 capabilities of the underlying C library. It is defined in
1031 pm_config.h. fseeko(), in turn, may be either fseek() or
1032 fseeko64(), as implemented by the C library.
1033 */
1034 FSEEKO(fileP, *fileposP, SEEK_SET);
1035 else if (fileposSize == sizeof(long)) {
1036 long const fileposLong = *(long *)fileposP;
1037 fseek(fileP, fileposLong, SEEK_SET);
1038 } else
1039 pm_error("File position size passed to pm_seek() is invalid: %u. "
1040 "Valid sizes are %u and %u",
1041 fileposSize, (unsigned int)sizeof(pm_filepos),
1042 (unsigned int) sizeof(long));
1043 }
1044
1045
1046
1047 void
pm_seek(FILE * const fileP,unsigned long filepos)1048 pm_seek(FILE * const fileP, unsigned long filepos) {
1049 /*----------------------------------------------------------------------------
1050 -----------------------------------------------------------------------------*/
1051
1052 pm_filepos fileposBuff;
1053
1054 fileposBuff = filepos;
1055
1056 pm_seek2(fileP, &fileposBuff, sizeof(fileposBuff));
1057 }
1058
1059
1060
1061 void
pm_nextimage(FILE * const file,int * const eofP)1062 pm_nextimage(FILE * const file, int * const eofP) {
1063 /*----------------------------------------------------------------------------
1064 Position the file 'file' to the next image in the stream, assuming it is
1065 now positioned just after the current image. I.e. read off any white
1066 space at the end of the current image's raster. Note that the raw formats
1067 don't permit such white space, but this routine tolerates it anyway,
1068 because the plain formats do permit white space after the raster.
1069
1070 Iff there is no next image, return *eofP == TRUE.
1071
1072 Note that in practice, we will not normally see white space here in
1073 a plain PPM or plain PGM stream because the routine to read a
1074 sample from the image reads one character of white space after the
1075 sample in order to know where the sample ends. There is not
1076 normally more than one character of white space (a newline) after
1077 the last sample in the raster. But plain PBM is another story. No white
1078 space is required between samples of a plain PBM image. But the raster
1079 normally ends with a newline nonetheless. Since the sample reading code
1080 will not have read that newline, it is there for us to read now.
1081 -----------------------------------------------------------------------------*/
1082 bool eof;
1083 bool nonWhitespaceFound;
1084
1085 eof = FALSE;
1086 nonWhitespaceFound = FALSE;
1087
1088 while (!eof && !nonWhitespaceFound) {
1089 int c;
1090 c = getc(file);
1091 if (c == EOF) {
1092 if (feof(file))
1093 eof = TRUE;
1094 else
1095 pm_error("File error on getc() to position to image");
1096 } else {
1097 if (!isspace(c)) {
1098 int rc;
1099
1100 nonWhitespaceFound = TRUE;
1101
1102 /* Have to put the non-whitespace character back in
1103 the stream -- it's part of the next image.
1104 */
1105 rc = ungetc(c, file);
1106 if (rc == EOF)
1107 pm_error("File error doing ungetc() "
1108 "to position to image.");
1109 }
1110 }
1111 }
1112 *eofP = eof;
1113 }
1114
1115
1116
1117 void
pm_check(FILE * const file,enum pm_check_type const check_type,pm_filepos const need_raster_size,enum pm_check_code * const retval_p)1118 pm_check(FILE * const file,
1119 enum pm_check_type const check_type,
1120 pm_filepos const need_raster_size,
1121 enum pm_check_code * const retval_p) {
1122 /*----------------------------------------------------------------------------
1123 This is not defined for use outside of libnetpbm.
1124 -----------------------------------------------------------------------------*/
1125 struct stat statbuf;
1126 pm_filepos curpos; /* Current position of file; -1 if none */
1127 int rc;
1128
1129 /* Note: FTELLO() is either ftello() or ftell(), depending on the
1130 capabilities of the underlying C library. It is defined in
1131 pm_config.h. ftello(), in turn, may be either ftell() or
1132 ftello64(), as implemented by the C library.
1133 */
1134 curpos = FTELLO(file);
1135 if (curpos >= 0) {
1136 /* This type of file has a current position */
1137
1138 rc = fstat(fileno(file), &statbuf);
1139 if (rc != 0)
1140 pm_error("fstat() failed to get size of file, though ftello() "
1141 "successfully identified\n"
1142 "the current position. Errno=%s (%d)",
1143 strerror(errno), errno);
1144 else if (!S_ISREG(statbuf.st_mode)) {
1145 /* Not a regular file; we can't know its size */
1146 if (retval_p) *retval_p = PM_CHECK_UNCHECKABLE;
1147 } else {
1148 pm_filepos const have_raster_size = statbuf.st_size - curpos;
1149
1150 if (have_raster_size < need_raster_size)
1151 pm_error("File has invalid format. The raster should "
1152 "contain %u bytes, but\n"
1153 "the file ends after only %u bytes.",
1154 (unsigned int) need_raster_size,
1155 (unsigned int) have_raster_size);
1156 else if (have_raster_size > need_raster_size) {
1157 if (retval_p) *retval_p = PM_CHECK_TOO_LONG;
1158 } else {
1159 if (retval_p) *retval_p = PM_CHECK_OK;
1160 }
1161 }
1162 } else
1163 if (retval_p) *retval_p = PM_CHECK_UNCHECKABLE;
1164 }
1165
1166
1167
1168 void
pm_drain(FILE * const fileP,unsigned int const limit,unsigned int * const bytesReadP)1169 pm_drain(FILE * const fileP,
1170 unsigned int const limit,
1171 unsigned int * const bytesReadP) {
1172 /*----------------------------------------------------------------------------
1173 Read bytes from *fileP until EOF and return as *bytesReadP how many there
1174 were.
1175
1176 But don't read any more than 'limit'.
1177
1178 This is a good thing to call after reading an input file to be sure you
1179 didn't leave some input behind, which could mean you didn't properly
1180 interpret the file.
1181 -----------------------------------------------------------------------------*/
1182 unsigned int bytesRead;
1183 bool eof;
1184
1185 for (bytesRead = 0, eof = false; !eof && bytesRead < limit;) {
1186
1187 int rc;
1188
1189 rc = fgetc(fileP);
1190
1191 eof = (rc == EOF);
1192 if (!eof)
1193 ++bytesRead;
1194 }
1195 *bytesReadP = bytesRead;
1196 }
1197