1 /*  This file, drvrmem.c, contains driver routines for memory files.        */
2 
3 /*  The FITSIO software was written by William Pence at the High Energy    */
4 /*  Astrophysic Science Archive Research Center (HEASARC) at the NASA      */
5 /*  Goddard Space Flight Center.                                           */
6 
7 #include <string.h>
8 #include <stdlib.h>
9 #include <stddef.h>  /* apparently needed to define size_t */
10 #include "fitsio2.h"
11 
12 /* prototype for .Z file uncompression function in zuncompress.c */
13 int zuncompress2mem(char *filename,
14              FILE *diskfile,
15              char **buffptr,
16              size_t *buffsize,
17              void *(*mem_realloc)(void *p, size_t newsize),
18              size_t *filesize,
19              int *status);
20 
21 #define RECBUFLEN 1000
22 
23 static char stdin_outfile[FLEN_FILENAME];
24 
25 typedef struct    /* structure containing mem file structure */
26 {
27     char **memaddrptr;   /* Pointer to memory address pointer; */
28                          /* This may or may not point to memaddr. */
29     char *memaddr;       /* Pointer to starting memory address; may */
30                          /* not always be used, so use *memaddrptr instead */
31     size_t *memsizeptr;  /* Pointer to the size of the memory allocation. */
32                          /* This may or may not point to memsize. */
33     size_t memsize;      /* Size of the memory allocation; this may not */
34                          /* always be used, so use *memsizeptr instead. */
35     size_t deltasize;    /* Suggested increment for reallocating memory */
36     void *(*mem_realloc)(void *p, size_t newsize);  /* realloc function */
37     LONGLONG currentpos;   /* current file position, relative to start */
38     LONGLONG fitsfilesize; /* size of the FITS file (always <= *memsizeptr) */
39     FILE *fileptr;      /* pointer to compressed output disk file */
40 } memdriver;
41 
42 static memdriver memTable[NMAXFILES];  /* allocate mem file handle tables */
43 
44 /*--------------------------------------------------------------------------*/
mem_init(void)45 int mem_init(void)
46 {
47     int ii;
48 
49     for (ii = 0; ii < NMAXFILES; ii++) /* initialize all empty slots in table */
50     {
51        memTable[ii].memaddrptr = 0;
52        memTable[ii].memaddr = 0;
53     }
54     return(0);
55 }
56 /*--------------------------------------------------------------------------*/
mem_setoptions(int options)57 int mem_setoptions(int options)
58 {
59   /* do something with the options argument, to stop compiler warning */
60   options = 0;
61   return(options);
62 }
63 /*--------------------------------------------------------------------------*/
mem_getoptions(int * options)64 int mem_getoptions(int *options)
65 {
66   *options = 0;
67   return(0);
68 }
69 /*--------------------------------------------------------------------------*/
mem_getversion(int * version)70 int mem_getversion(int *version)
71 {
72     *version = 10;
73     return(0);
74 }
75 /*--------------------------------------------------------------------------*/
mem_shutdown(void)76 int mem_shutdown(void)
77 {
78   return(0);
79 }
80 /*--------------------------------------------------------------------------*/
mem_create(char * filename,int * handle)81 int mem_create(char *filename, int *handle)
82 /*
83   Create a new empty memory file for subsequent writes.
84   The file name is ignored in this case.
85 */
86 {
87     int status;
88 
89     /* initially allocate 1 FITS block = 2880 bytes */
90     status = mem_createmem(2880L, handle);
91 
92     if (status)
93     {
94         ffpmsg("failed to create empty memory file (mem_create)");
95         return(status);
96     }
97 
98     return(0);
99 }
100 /*--------------------------------------------------------------------------*/
mem_create_comp(char * filename,int * handle)101 int mem_create_comp(char *filename, int *handle)
102 /*
103   Create a new empty memory file for subsequent writes.
104   Also create an empty compressed .gz file.  The memory file
105   will be compressed and written to the disk file when the file is closed.
106 */
107 {
108     FILE *diskfile;
109     char mode[4];
110     int  status;
111 
112     /* first, create disk file for the compressed output */
113 
114 
115     if ( !strcmp(filename, "-.gz") || !strcmp(filename, "stdout.gz") ||
116          !strcmp(filename, "STDOUT.gz") )
117     {
118        /* special case: create uncompressed FITS file in memory, then
119           compress it an write it out to 'stdout' when it is closed.  */
120 
121        diskfile = stdout;
122     }
123     else
124     {
125         /* normal case: create disk file for the compressed output */
126 
127         strcpy(mode, "w+b");    /* create file with read-write */
128 
129         diskfile = fopen(filename, "r"); /* does file already exist? */
130 
131         if (diskfile)
132         {
133             fclose(diskfile);         /* close file and exit with error */
134             return(FILE_NOT_CREATED);
135         }
136 
137 #if MACHINE == ALPHAVMS || MACHINE == VAXVMS
138         /* specify VMS record structure: fixed format, 2880 byte records */
139         /* but force stream mode access to enable random I/O access      */
140         diskfile = fopen(filename, mode, "rfm=fix", "mrs=2880", "ctx=stm");
141 #else
142         diskfile = fopen(filename, mode);
143 #endif
144 
145         if (!(diskfile))           /* couldn't create file */
146         {
147             return(FILE_NOT_CREATED);
148         }
149     }
150 
151     /* now create temporary memory file */
152 
153     /* initially allocate 1 FITS block = 2880 bytes */
154     status = mem_createmem(2880L, handle);
155 
156     if (status)
157     {
158         ffpmsg("failed to create empty memory file (mem_create_comp)");
159         return(status);
160     }
161 
162     memTable[*handle].fileptr = diskfile;
163 
164     return(0);
165 }
166 /*--------------------------------------------------------------------------*/
mem_openmem(void ** buffptr,size_t * buffsize,size_t deltasize,void * (* memrealloc)(void * p,size_t newsize),int * handle)167 int mem_openmem(void **buffptr,   /* I - address of memory pointer          */
168                 size_t *buffsize, /* I - size of buffer, in bytes           */
169                 size_t deltasize, /* I - increment for future realloc's     */
170                 void *(*memrealloc)(void *p, size_t newsize),  /* function  */
171                 int *handle)
172 /*
173   lowest level routine to open a pre-existing memory file.
174 */
175 {
176     int ii;
177 
178     *handle = -1;
179     for (ii = 0; ii < NMAXFILES; ii++)  /* find empty slot in handle table */
180     {
181         if (memTable[ii].memaddrptr == 0)
182         {
183             *handle = ii;
184             break;
185         }
186     }
187     if (*handle == -1)
188        return(TOO_MANY_FILES);    /* too many files opened */
189 
190     memTable[ii].memaddrptr = (char **) buffptr; /* pointer to start addres */
191     memTable[ii].memsizeptr = buffsize;     /* allocated size of memory */
192     memTable[ii].deltasize = deltasize;     /* suggested realloc increment */
193     memTable[ii].fitsfilesize = *buffsize;  /* size of FITS file (upper limit) */
194     memTable[ii].currentpos = 0;            /* at beginning of the file */
195     memTable[ii].mem_realloc = memrealloc;  /* memory realloc function */
196     return(0);
197 }
198 /*--------------------------------------------------------------------------*/
mem_createmem(size_t msize,int * handle)199 int mem_createmem(size_t msize, int *handle)
200 /*
201   lowest level routine to allocate a memory file.
202 */
203 {
204     int ii;
205 
206     *handle = -1;
207     for (ii = 0; ii < NMAXFILES; ii++)  /* find empty slot in handle table */
208     {
209         if (memTable[ii].memaddrptr == 0)
210         {
211             *handle = ii;
212             break;
213         }
214     }
215     if (*handle == -1)
216        return(TOO_MANY_FILES);    /* too many files opened */
217 
218     /* use the internally allocated memaddr and memsize variables */
219     memTable[ii].memaddrptr = &memTable[ii].memaddr;
220     memTable[ii].memsizeptr = &memTable[ii].memsize;
221 
222     /* allocate initial block of memory for the file */
223     if (msize > 0)
224     {
225         memTable[ii].memaddr = (char *) malloc(msize);
226         if ( !(memTable[ii].memaddr) )
227         {
228             ffpmsg("malloc of initial memory failed (mem_createmem)");
229             return(FILE_NOT_OPENED);
230         }
231     }
232 
233     /* set initial state of the file */
234     memTable[ii].memsize = msize;
235     memTable[ii].deltasize = 2880;
236     memTable[ii].fitsfilesize = 0;
237     memTable[ii].currentpos = 0;
238     memTable[ii].mem_realloc = realloc;
239     return(0);
240 }
241 /*--------------------------------------------------------------------------*/
mem_truncate(int handle,LONGLONG filesize)242 int mem_truncate(int handle, LONGLONG filesize)
243 /*
244   truncate the file to a new size
245 */
246 {
247     char *ptr;
248 
249     /* call the memory reallocation function, if defined */
250     if ( memTable[handle].mem_realloc )
251     {    /* explicit LONGLONG->size_t cast */
252         ptr = (memTable[handle].mem_realloc)(
253                                 *(memTable[handle].memaddrptr),
254                                  (size_t) filesize);
255         if (!ptr)
256         {
257             ffpmsg("Failed to reallocate memory (mem_truncate)");
258             return(MEMORY_ALLOCATION);
259         }
260 
261         /* if allocated more memory, initialize it to zero */
262         if ( filesize > *(memTable[handle].memsizeptr) )
263         {
264              memset(ptr + *(memTable[handle].memsizeptr),
265                     0,
266                 ((size_t) filesize) - *(memTable[handle].memsizeptr) );
267         }
268 
269         *(memTable[handle].memaddrptr) = ptr;
270         *(memTable[handle].memsizeptr) = (size_t) (filesize);
271     }
272 
273     memTable[handle].currentpos = filesize;
274     memTable[handle].fitsfilesize = filesize;
275     return(0);
276 }
277 /*--------------------------------------------------------------------------*/
stdin_checkfile(char * urltype,char * infile,char * outfile)278 int stdin_checkfile(char *urltype, char *infile, char *outfile)
279 /*
280    do any special case checking when opening a file on the stdin stream
281 */
282 {
283     if (strlen(outfile))
284     {
285         stdin_outfile[0] = '\0';
286         strncat(stdin_outfile,outfile,FLEN_FILENAME-1); /* an output file is specified */
287 	strcpy(urltype,"stdinfile://");
288     }
289     else
290         *stdin_outfile = '\0';  /* no output file was specified */
291 
292     return(0);
293 }
294 /*--------------------------------------------------------------------------*/
stdin_open(char * filename,int rwmode,int * handle)295 int stdin_open(char *filename, int rwmode, int *handle)
296 /*
297   open a FITS file from the stdin file stream by copying it into memory
298   The file name is ignored in this case.
299 */
300 {
301     int status;
302     char cbuff;
303 
304     if (*stdin_outfile)
305     {
306       /* copy the stdin stream to the specified disk file then open the file */
307 
308       /* Create the output file */
309       status =  file_create(stdin_outfile,handle);
310 
311       if (status)
312       {
313         ffpmsg("Unable to create output file to copy stdin (stdin_open):");
314         ffpmsg(stdin_outfile);
315         return(status);
316       }
317 
318       /* copy the whole stdin stream to the file */
319       status = stdin2file(*handle);
320       file_close(*handle);
321 
322       if (status)
323       {
324         ffpmsg("failed to copy stdin to file (stdin_open)");
325         ffpmsg(stdin_outfile);
326         return(status);
327       }
328 
329       /* reopen file with proper rwmode attribute */
330       status = file_open(stdin_outfile, rwmode, handle);
331     }
332     else
333     {
334 
335       /* get the first character, then put it back */
336       cbuff = fgetc(stdin);
337       ungetc(cbuff, stdin);
338 
339       /* compressed files begin with 037 or 'P' */
340       if (cbuff == 31 || cbuff == 75)
341       {
342          /* looks like the input stream is compressed */
343          status = mem_compress_stdin_open(filename, rwmode, handle);
344 
345       }
346       else
347       {
348         /* copy the stdin stream into memory then open file in memory */
349 
350         if (rwmode != READONLY)
351         {
352           ffpmsg("cannot open stdin with WRITE access");
353           return(READONLY_FILE);
354         }
355 
356         status = mem_createmem(2880L, handle);
357 
358         if (status)
359         {
360           ffpmsg("failed to create empty memory file (stdin_open)");
361           return(status);
362         }
363 
364         /* copy the whole stdin stream into memory */
365         status = stdin2mem(*handle);
366 
367         if (status)
368         {
369           ffpmsg("failed to copy stdin into memory (stdin_open)");
370           free(memTable[*handle].memaddr);
371         }
372       }
373     }
374 
375     return(status);
376 }
377 /*--------------------------------------------------------------------------*/
stdin2mem(int hd)378 int stdin2mem(int hd)  /* handle number */
379 /*
380   Copy the stdin stream into memory.  Fill whatever amount of memory
381   has already been allocated, then realloc more memory if necessary.
382 */
383 {
384     size_t nread, memsize, delta;
385     LONGLONG filesize;
386     char *memptr;
387     char simple[] = "SIMPLE";
388     int c, ii, jj;
389 
390     memptr = *memTable[hd].memaddrptr;
391     memsize = *memTable[hd].memsizeptr;
392     delta = memTable[hd].deltasize;
393 
394     filesize = 0;
395     ii = 0;
396 
397     for(jj = 0; (c = fgetc(stdin)) != EOF && jj < 2000; jj++)
398     {
399        /* Skip over any garbage at the beginning of the stdin stream by */
400        /* reading 1 char at a time, looking for 'S', 'I', 'M', 'P', 'L', 'E' */
401        /* Give up if not found in the first 2000 characters */
402 
403        if (c == simple[ii])
404        {
405            ii++;
406            if (ii == 6)   /* found the complete string? */
407            {
408               memcpy(memptr, simple, 6);  /* copy "SIMPLE" to buffer */
409               filesize = 6;
410               break;
411            }
412        }
413        else
414           ii = 0;  /* reset search to beginning of the string */
415     }
416 
417    if (filesize == 0)
418    {
419        ffpmsg("Couldn't find the string 'SIMPLE' in the stdin stream.");
420        ffpmsg("This does not look like a FITS file.");
421        return(FILE_NOT_OPENED);
422    }
423 
424     /* fill up the remainder of the initial memory allocation */
425     nread = fread(memptr + 6, 1, memsize - 6, stdin);
426     nread += 6;  /* add in the 6 characters in 'SIMPLE' */
427 
428     if (nread < memsize)    /* reached the end? */
429     {
430        memTable[hd].fitsfilesize = nread;
431        return(0);
432     }
433 
434     filesize = nread;
435 
436     while (1)
437     {
438         /* allocate memory for another FITS block */
439         memptr = realloc(memptr, memsize + delta);
440 
441         if (!memptr)
442         {
443             ffpmsg("realloc failed while copying stdin (stdin2mem)");
444             return(MEMORY_ALLOCATION);
445         }
446         memsize += delta;
447 
448         /* read another FITS block */
449         nread = fread(memptr + filesize, 1, delta, stdin);
450 
451         filesize += nread;
452 
453         if (nread < delta)    /* reached the end? */
454            break;
455     }
456 
457      memTable[hd].fitsfilesize = filesize;
458     *memTable[hd].memaddrptr = memptr;
459     *memTable[hd].memsizeptr = memsize;
460 
461     return(0);
462 }
463 /*--------------------------------------------------------------------------*/
stdin2file(int handle)464 int stdin2file(int handle)  /* handle number */
465 /*
466   Copy the stdin stream to a file.  .
467 */
468 {
469     size_t nread;
470     char simple[] = "SIMPLE";
471     int c, ii, jj, status;
472     char recbuf[RECBUFLEN];
473 
474     ii = 0;
475     for(jj = 0; (c = fgetc(stdin)) != EOF && jj < 2000; jj++)
476     {
477        /* Skip over any garbage at the beginning of the stdin stream by */
478        /* reading 1 char at a time, looking for 'S', 'I', 'M', 'P', 'L', 'E' */
479        /* Give up if not found in the first 2000 characters */
480 
481        if (c == simple[ii])
482        {
483            ii++;
484            if (ii == 6)   /* found the complete string? */
485            {
486               memcpy(recbuf, simple, 6);  /* copy "SIMPLE" to buffer */
487               break;
488            }
489        }
490        else
491           ii = 0;  /* reset search to beginning of the string */
492     }
493 
494    if (ii != 6)
495    {
496        ffpmsg("Couldn't find the string 'SIMPLE' in the stdin stream");
497        return(FILE_NOT_OPENED);
498    }
499 
500     /* fill up the remainder of the buffer */
501     nread = fread(recbuf + 6, 1, RECBUFLEN - 6, stdin);
502     nread += 6;  /* add in the 6 characters in 'SIMPLE' */
503 
504     status = file_write(handle, recbuf, nread);
505     if (status)
506        return(status);
507 
508     /* copy the rest of stdin stream */
509     while(0 != (nread = fread(recbuf,1,RECBUFLEN, stdin)))
510     {
511         status = file_write(handle, recbuf, nread);
512         if (status)
513            return(status);
514     }
515 
516     return(status);
517 }
518 /*--------------------------------------------------------------------------*/
stdout_close(int handle)519 int stdout_close(int handle)
520 /*
521   copy the memory file to stdout, then free the memory
522 */
523 {
524     int status = 0;
525 
526     /* copy from memory to standard out.  explicit LONGLONG->size_t cast */
527     if(fwrite(memTable[handle].memaddr, 1,
528               ((size_t) memTable[handle].fitsfilesize), stdout) !=
529               (size_t) memTable[handle].fitsfilesize )
530     {
531                 ffpmsg("failed to copy memory file to stdout (stdout_close)");
532                 status = WRITE_ERROR;
533     }
534 
535     free( memTable[handle].memaddr );   /* free the memory */
536     memTable[handle].memaddrptr = 0;
537     memTable[handle].memaddr = 0;
538     return(status);
539 }
540 /*--------------------------------------------------------------------------*/
mem_compress_openrw(char * filename,int rwmode,int * hdl)541 int mem_compress_openrw(char *filename, int rwmode, int *hdl)
542 /*
543   This routine opens the compressed diskfile and creates an empty memory
544   buffer with an appropriate size, then calls mem_uncompress2mem. It allows
545   the memory 'file' to be opened with READWRITE access.
546 */
547 {
548    return(mem_compress_open(filename, READONLY, hdl));
549 }
550 /*--------------------------------------------------------------------------*/
mem_compress_open(char * filename,int rwmode,int * hdl)551 int mem_compress_open(char *filename, int rwmode, int *hdl)
552 /*
553   This routine opens the compressed diskfile and creates an empty memory
554   buffer with an appropriate size, then calls mem_uncompress2mem.
555 */
556 {
557     FILE *diskfile;
558     int status, estimated = 1;
559     unsigned char buffer[4];
560     size_t finalsize, filesize;
561     LONGLONG llsize = 0;
562     unsigned int modulosize;
563     char *ptr;
564 
565     if (rwmode != READONLY)
566     {
567         ffpmsg(
568   "cannot open compressed file with WRITE access (mem_compress_open)");
569         ffpmsg(filename);
570         return(READONLY_FILE);
571     }
572 
573     /* open the compressed disk file */
574     status = file_openfile(filename, READONLY, &diskfile);
575     if (status)
576     {
577         ffpmsg("failed to open compressed disk file (compress_open)");
578         ffpmsg(filename);
579         return(status);
580     }
581 
582     if (fread(buffer, 1, 2, diskfile) != 2)  /* read 2 bytes */
583     {
584         fclose(diskfile);
585         return(READ_ERROR);
586     }
587 
588     if (memcmp(buffer, "\037\213", 2) == 0)  /* GZIP */
589     {
590         /* the uncompressed file size is give at the end */
591         /* of the file in the ISIZE field  (modulo 2^32) */
592 
593         fseek(diskfile, 0, 2);            /* move to end of file */
594         filesize = ftell(diskfile);       /* position = size of file */
595         fseek(diskfile, -4L, 1);          /* move back 4 bytes */
596         fread(buffer, 1, 4L, diskfile);   /* read 4 bytes */
597 
598         /* have to worry about integer byte order */
599 	modulosize  = buffer[0];
600 	modulosize |= buffer[1] << 8;
601 	modulosize |= buffer[2] << 16;
602 	modulosize |= buffer[3] << 24;
603 
604 /*
605   the field ISIZE in the gzipped file header only stores 4 bytes and contains
606   the uncompressed file size modulo 2^32.  If the uncompressed file size
607   is less than the compressed file size (filesize), then one probably needs to
608   add 2^32 = 4294967296 to the uncompressed file size, assuming that the gzip
609   produces a compressed file that is smaller than the original file.
610 
611   But one must allow for the case of very small files, where the
612   gzipped file may actually be larger then the original uncompressed file.
613   Therefore, only perform the modulo 2^32 correction test if the compressed
614   file is greater than 10,000 bytes in size.  (Note: this threhold would
615   fail only if the original file was greater than 2^32 bytes in size AND gzip
616   was able to compress it by more than a factor of 400,000 (!) which seems
617   highly unlikely.)
618 
619   Also, obviously, this 2^32 modulo correction cannot be performed if the
620   finalsize variable is only 32-bits long.  Typically, the 'size_t' integer
621   type must be 8 bytes or larger in size to support data files that are
622   greater than 2 GB (2^31 bytes) in size.
623 */
624         finalsize = modulosize;
625 
626         if (sizeof(size_t) > 4 && filesize > 10000) {
627 	    llsize = (LONGLONG) finalsize;
628 	    /* use LONGLONG variable to suppress compiler warning */
629             while (llsize <  (LONGLONG) filesize) llsize += 4294967296;
630 
631             finalsize = (size_t) llsize;
632         }
633 
634         estimated = 0;  /* file size is known, not estimated */
635     }
636     else if (memcmp(buffer, "\120\113", 2) == 0)   /* PKZIP */
637     {
638         /* the uncompressed file size is give at byte 22 the file */
639 
640         fseek(diskfile, 22L, 0);            /* move to byte 22 */
641         fread(buffer, 1, 4L, diskfile);   /* read 4 bytes */
642 
643         /* have to worry about integer byte order */
644 	modulosize  = buffer[0];
645 	modulosize |= buffer[1] << 8;
646 	modulosize |= buffer[2] << 16;
647 	modulosize |= buffer[3] << 24;
648         finalsize = modulosize;
649 
650         estimated = 0;  /* file size is known, not estimated */
651     }
652     else if (memcmp(buffer, "\037\036", 2) == 0)  /* PACK */
653         finalsize = 0;  /* for most methods we can't determine final size */
654     else if (memcmp(buffer, "\037\235", 2) == 0)  /* LZW */
655         finalsize = 0;  /* for most methods we can't determine final size */
656     else if (memcmp(buffer, "\037\240", 2) == 0)  /* LZH */
657         finalsize = 0;  /* for most methods we can't determine final size */
658     else
659     {
660         /* not a compressed file; this should never happen */
661         fclose(diskfile);
662         return(1);
663     }
664 
665     if (finalsize == 0)  /* estimate uncompressed file size */
666     {
667             fseek(diskfile, 0, 2);   /* move to end of the compressed file */
668             finalsize = ftell(diskfile);  /* position = size of file */
669             finalsize = finalsize * 3;   /* assume factor of 3 compression */
670     }
671 
672     fseek(diskfile, 0, 0);   /* move back to beginning of file */
673 
674     /* create a memory file big enough (hopefully) for the uncompressed file */
675     status = mem_createmem(finalsize, hdl);
676 
677     if (status && estimated)
678     {
679         /* memory allocation failed, so try a smaller estimated size */
680         finalsize = finalsize / 3;
681         status = mem_createmem(finalsize, hdl);
682     }
683 
684     if (status)
685     {
686         fclose(diskfile);
687         ffpmsg("failed to create empty memory file (compress_open)");
688         return(status);
689     }
690 
691     /* uncompress file into memory */
692     status = mem_uncompress2mem(filename, diskfile, *hdl);
693 
694     fclose(diskfile);
695 
696     if (status)
697     {
698         mem_close_free(*hdl);   /* free up the memory */
699         ffpmsg("failed to uncompress file into memory (compress_open)");
700         return(status);
701     }
702 
703     /* if we allocated too much memory initially, then free it */
704     if (*(memTable[*hdl].memsizeptr) >
705        (( (size_t) memTable[*hdl].fitsfilesize) + 256L) )
706     {
707         ptr = realloc(*(memTable[*hdl].memaddrptr),
708                      ((size_t) memTable[*hdl].fitsfilesize) );
709         if (!ptr)
710         {
711             ffpmsg("Failed to reduce size of allocated memory (compress_open)");
712             return(MEMORY_ALLOCATION);
713         }
714 
715         *(memTable[*hdl].memaddrptr) = ptr;
716         *(memTable[*hdl].memsizeptr) = (size_t) (memTable[*hdl].fitsfilesize);
717     }
718 
719     return(0);
720 }
721 /*--------------------------------------------------------------------------*/
mem_compress_stdin_open(char * filename,int rwmode,int * hdl)722 int mem_compress_stdin_open(char *filename, int rwmode, int *hdl)
723 /*
724   This routine reads the compressed input stream and creates an empty memory
725   buffer, then calls mem_uncompress2mem.
726 */
727 {
728     int status;
729     char *ptr;
730 
731     if (rwmode != READONLY)
732     {
733         ffpmsg(
734   "cannot open compressed input stream with WRITE access (mem_compress_stdin_open)");
735         return(READONLY_FILE);
736     }
737 
738     /* create a memory file for the uncompressed file */
739     status = mem_createmem(28800, hdl);
740 
741     if (status)
742     {
743         ffpmsg("failed to create empty memory file (compress_stdin_open)");
744         return(status);
745     }
746 
747     /* uncompress file into memory */
748     status = mem_uncompress2mem(filename, stdin, *hdl);
749 
750     if (status)
751     {
752         mem_close_free(*hdl);   /* free up the memory */
753         ffpmsg("failed to uncompress stdin into memory (compress_stdin_open)");
754         return(status);
755     }
756 
757     /* if we allocated too much memory initially, then free it */
758     if (*(memTable[*hdl].memsizeptr) >
759        (( (size_t) memTable[*hdl].fitsfilesize) + 256L) )
760     {
761         ptr = realloc(*(memTable[*hdl].memaddrptr),
762                       ((size_t) memTable[*hdl].fitsfilesize) );
763         if (!ptr)
764         {
765             ffpmsg("Failed to reduce size of allocated memory (compress_stdin_open)");
766             return(MEMORY_ALLOCATION);
767         }
768 
769         *(memTable[*hdl].memaddrptr) = ptr;
770         *(memTable[*hdl].memsizeptr) = (size_t) (memTable[*hdl].fitsfilesize);
771     }
772 
773     return(0);
774 }
775 /*--------------------------------------------------------------------------*/
mem_iraf_open(char * filename,int rwmode,int * hdl)776 int mem_iraf_open(char *filename, int rwmode, int *hdl)
777 /*
778   This routine creates an empty memory buffer, then calls iraf2mem to
779   open the IRAF disk file and convert it to a FITS file in memeory.
780 */
781 {
782     int status;
783     size_t filesize = 0;
784 
785     /* create a memory file with size = 0 for the FITS converted IRAF file */
786     status = mem_createmem(filesize, hdl);
787     if (status)
788     {
789         ffpmsg("failed to create empty memory file (mem_iraf_open)");
790         return(status);
791     }
792 
793     /* convert the iraf file into a FITS file in memory */
794     status = iraf2mem(filename, memTable[*hdl].memaddrptr,
795                       memTable[*hdl].memsizeptr, &filesize, &status);
796 
797     if (status)
798     {
799         mem_close_free(*hdl);   /* free up the memory */
800         ffpmsg("failed to convert IRAF file into memory (mem_iraf_open)");
801         return(status);
802     }
803 
804     memTable[*hdl].currentpos = 0;           /* save starting position */
805     memTable[*hdl].fitsfilesize=filesize;   /* and initial file size  */
806 
807     return(0);
808 }
809 /*--------------------------------------------------------------------------*/
mem_rawfile_open(char * filename,int rwmode,int * hdl)810 int mem_rawfile_open(char *filename, int rwmode, int *hdl)
811 /*
812   This routine creates an empty memory buffer, writes a minimal
813   image header, then copies the image data from the raw file into
814   memory.  It will byteswap the pixel values if the raw array
815   is in little endian byte order.
816 */
817 {
818     FILE *diskfile;
819     fitsfile *fptr;
820     short *sptr;
821     int status, endian, datatype, bytePerPix, naxis;
822     long dim[5] = {1,1,1,1,1}, ii, nvals, offset = 0;
823     size_t filesize = 0, datasize;
824     char rootfile[FLEN_FILENAME], *cptr = 0, *cptr2 = 0;
825     void *ptr;
826 
827     if (rwmode != READONLY)
828     {
829         ffpmsg(
830   "cannot open raw binary file with WRITE access (mem_rawfile_open)");
831         ffpmsg(filename);
832         return(READONLY_FILE);
833     }
834 
835     cptr = strchr(filename, '[');   /* search for opening bracket [ */
836 
837     if (!cptr)
838     {
839         ffpmsg("binary file name missing '[' character (mem_rawfile_open)");
840         ffpmsg(filename);
841         return(URL_PARSE_ERROR);
842     }
843 
844     *rootfile = '\0';
845     strncat(rootfile, filename, cptr - filename);  /* store the rootname */
846 
847     cptr++;
848 
849     while (*cptr == ' ')
850        cptr++;    /* skip leading blanks */
851 
852     /* Get the Data Type of the Image */
853 
854     if (*cptr == 'b' || *cptr == 'B')
855     {
856       datatype = BYTE_IMG;
857       bytePerPix = 1;
858     }
859     else if (*cptr == 'i' || *cptr == 'I')
860     {
861       datatype = SHORT_IMG;
862       bytePerPix = 2;
863     }
864     else if (*cptr == 'u' || *cptr == 'U')
865     {
866       datatype = USHORT_IMG;
867       bytePerPix = 2;
868 
869     }
870     else if (*cptr == 'j' || *cptr == 'J')
871     {
872       datatype = LONG_IMG;
873       bytePerPix = 4;
874     }
875     else if (*cptr == 'r' || *cptr == 'R' || *cptr == 'f' || *cptr == 'F')
876     {
877       datatype = FLOAT_IMG;
878       bytePerPix = 4;
879     }
880     else if (*cptr == 'd' || *cptr == 'D')
881     {
882       datatype = DOUBLE_IMG;
883       bytePerPix = 8;
884     }
885     else
886     {
887         ffpmsg("error in raw binary file datatype (mem_rawfile_open)");
888         ffpmsg(filename);
889         return(URL_PARSE_ERROR);
890     }
891 
892     cptr++;
893 
894     /* get Endian: Big or Little; default is same as the local machine */
895 
896     if (*cptr == 'b' || *cptr == 'B')
897     {
898         endian = 0;
899         cptr++;
900     }
901     else if (*cptr == 'l' || *cptr == 'L')
902     {
903         endian = 1;
904         cptr++;
905     }
906     else
907         endian = BYTESWAPPED; /* byteswapped machines are little endian */
908 
909     /* read each dimension (up to 5) */
910 
911     naxis = 1;
912     dim[0] = strtol(cptr, &cptr2, 10);
913 
914     if (cptr2 && *cptr2 == ',')
915     {
916       naxis = 2;
917       dim[1] = strtol(cptr2+1, &cptr, 10);
918 
919       if (cptr && *cptr == ',')
920       {
921         naxis = 3;
922         dim[2] = strtol(cptr+1, &cptr2, 10);
923 
924         if (cptr2 && *cptr2 == ',')
925         {
926           naxis = 4;
927           dim[3] = strtol(cptr2+1, &cptr, 10);
928 
929           if (cptr && *cptr == ',')
930             naxis = 5;
931             dim[4] = strtol(cptr+1, &cptr2, 10);
932         }
933       }
934     }
935 
936     cptr = maxvalue(cptr, cptr2);
937 
938     if (*cptr == ':')   /* read starting offset value */
939         offset = strtol(cptr+1, 0, 10);
940 
941     nvals = dim[0] * dim[1] * dim[2] * dim[3] * dim[4];
942     datasize = nvals * bytePerPix;
943     filesize = nvals * bytePerPix + 2880;
944     filesize = ((filesize - 1) / 2880 + 1) * 2880;
945 
946     /* open the raw binary disk file */
947     status = file_openfile(rootfile, READONLY, &diskfile);
948     if (status)
949     {
950         ffpmsg("failed to open raw  binary file (mem_rawfile_open)");
951         ffpmsg(rootfile);
952         return(status);
953     }
954 
955     /* create a memory file with corrct size for the FITS converted raw file */
956     status = mem_createmem(filesize, hdl);
957     if (status)
958     {
959         ffpmsg("failed to create memory file (mem_rawfile_open)");
960         fclose(diskfile);
961         return(status);
962     }
963 
964     /* open this piece of memory as a new FITS file */
965     ffimem(&fptr, (void **) memTable[*hdl].memaddrptr, &filesize, 0, 0, &status);
966 
967     /* write the required header keywords */
968     ffcrim(fptr, datatype, naxis, dim, &status);
969 
970     /* close the FITS file, but keep the memory allocated */
971     ffclos(fptr, &status);
972 
973     if (status > 0)
974     {
975         ffpmsg("failed to write basic image header (mem_rawfile_open)");
976         fclose(diskfile);
977         mem_close_free(*hdl);   /* free up the memory */
978         return(status);
979     }
980 
981     if (offset > 0)
982        fseek(diskfile, offset, 0);   /* offset to start of the data */
983 
984     /* read the raw data into memory */
985     ptr = *memTable[*hdl].memaddrptr + 2880;
986 
987     if (fread((char *) ptr, 1, datasize, diskfile) != datasize)
988       status = READ_ERROR;
989 
990     fclose(diskfile);  /* close the raw binary disk file */
991 
992     if (status)
993     {
994         mem_close_free(*hdl);   /* free up the memory */
995         ffpmsg("failed to copy raw file data into memory (mem_rawfile_open)");
996         return(status);
997     }
998 
999     if (datatype == USHORT_IMG)  /* have to subtract 32768 from each unsigned */
1000     {                            /* value to conform to FITS convention. More */
1001                                  /* efficient way to do this is to just flip  */
1002                                  /* the most significant bit.                 */
1003 
1004       sptr = (short *) ptr;
1005 
1006       if (endian == BYTESWAPPED)  /* working with native format */
1007       {
1008         for (ii = 0; ii < nvals; ii++, sptr++)
1009         {
1010           *sptr =  ( *sptr ) ^ 0x8000;
1011         }
1012       }
1013       else  /* pixels are byteswapped WRT the native format */
1014       {
1015         for (ii = 0; ii < nvals; ii++, sptr++)
1016         {
1017           *sptr =  ( *sptr ) ^ 0x80;
1018         }
1019       }
1020     }
1021 
1022     if (endian)  /* swap the bytes if array is in little endian byte order */
1023     {
1024       if (datatype == SHORT_IMG || datatype == USHORT_IMG)
1025       {
1026         ffswap2( (short *) ptr, nvals);
1027       }
1028       else if (datatype == LONG_IMG || datatype == FLOAT_IMG)
1029       {
1030         ffswap4( (INT32BIT *) ptr, nvals);
1031       }
1032 
1033       else if (datatype == DOUBLE_IMG)
1034       {
1035         ffswap8( (double *) ptr, nvals);
1036       }
1037     }
1038 
1039     memTable[*hdl].currentpos = 0;           /* save starting position */
1040     memTable[*hdl].fitsfilesize=filesize;    /* and initial file size  */
1041 
1042     return(0);
1043 }
1044 /*--------------------------------------------------------------------------*/
mem_uncompress2mem(char * filename,FILE * diskfile,int hdl)1045 int mem_uncompress2mem(char *filename, FILE *diskfile, int hdl)
1046 {
1047 /*
1048   lower level routine to uncompress a file into memory.  The file
1049   has already been opened and the memory buffer has been allocated.
1050 */
1051 
1052   size_t finalsize;
1053   int status;
1054   /* uncompress file into memory */
1055   status = 0;
1056 
1057     if (strstr(filename, ".Z")) {
1058          zuncompress2mem(filename, diskfile,
1059 		 memTable[hdl].memaddrptr,   /* pointer to memory address */
1060 		 memTable[hdl].memsizeptr,   /* pointer to size of memory */
1061 		 realloc,                     /* reallocation function */
1062 		 &finalsize, &status);        /* returned file size nd status*/
1063     } else {
1064          uncompress2mem(filename, diskfile,
1065 		 memTable[hdl].memaddrptr,   /* pointer to memory address */
1066 		 memTable[hdl].memsizeptr,   /* pointer to size of memory */
1067 		 realloc,                     /* reallocation function */
1068 		 &finalsize, &status);        /* returned file size nd status*/
1069     }
1070 
1071   memTable[hdl].currentpos = 0;           /* save starting position */
1072   memTable[hdl].fitsfilesize=finalsize;   /* and initial file size  */
1073   return status;
1074 }
1075 /*--------------------------------------------------------------------------*/
mem_size(int handle,LONGLONG * filesize)1076 int mem_size(int handle, LONGLONG *filesize)
1077 /*
1078   return the size of the file; only called when the file is first opened
1079 */
1080 {
1081     *filesize = memTable[handle].fitsfilesize;
1082     return(0);
1083 }
1084 /*--------------------------------------------------------------------------*/
mem_close_free(int handle)1085 int mem_close_free(int handle)
1086 /*
1087   close the file and free the memory.
1088 */
1089 {
1090     free( *(memTable[handle].memaddrptr) );
1091 
1092     memTable[handle].memaddrptr = 0;
1093     memTable[handle].memaddr = 0;
1094     return(0);
1095 }
1096 /*--------------------------------------------------------------------------*/
mem_close_keep(int handle)1097 int mem_close_keep(int handle)
1098 /*
1099   close the memory file but do not free the memory.
1100 */
1101 {
1102     memTable[handle].memaddrptr = 0;
1103     memTable[handle].memaddr = 0;
1104     return(0);
1105 }
1106 /*--------------------------------------------------------------------------*/
mem_close_comp(int handle)1107 int mem_close_comp(int handle)
1108 /*
1109   compress the memory file, writing it out to the fileptr (which might
1110   be stdout)
1111 */
1112 {
1113     int status = 0;
1114     size_t compsize;
1115 
1116     /* compress file in  memory to a .gz disk file */
1117 
1118     if(compress2file_from_mem(memTable[handle].memaddr,
1119               (size_t) (memTable[handle].fitsfilesize),
1120               memTable[handle].fileptr,
1121               &compsize, &status ) )
1122     {
1123             ffpmsg("failed to copy memory file to file (mem_close_comp)");
1124             status = WRITE_ERROR;
1125     }
1126 
1127     free( memTable[handle].memaddr );   /* free the memory */
1128     memTable[handle].memaddrptr = 0;
1129     memTable[handle].memaddr = 0;
1130 
1131     /* close the compressed disk file (except if it is 'stdout' */
1132     if (memTable[handle].fileptr != stdout)
1133         fclose(memTable[handle].fileptr);
1134 
1135     return(status);
1136 }
1137 /*--------------------------------------------------------------------------*/
mem_seek(int handle,LONGLONG offset)1138 int mem_seek(int handle, LONGLONG offset)
1139 /*
1140   seek to position relative to start of the file.
1141 */
1142 {
1143     if (offset >  memTable[handle].fitsfilesize )
1144         return(END_OF_FILE);
1145 
1146     memTable[handle].currentpos = offset;
1147     return(0);
1148 }
1149 /*--------------------------------------------------------------------------*/
mem_read(int hdl,void * buffer,long nbytes)1150 int mem_read(int hdl, void *buffer, long nbytes)
1151 /*
1152   read bytes from the current position in the file
1153 */
1154 {
1155     if (memTable[hdl].currentpos + nbytes > memTable[hdl].fitsfilesize)
1156         return(END_OF_FILE);
1157 
1158     memcpy(buffer,
1159            *(memTable[hdl].memaddrptr) + memTable[hdl].currentpos,
1160            nbytes);
1161 
1162     memTable[hdl].currentpos += nbytes;
1163     return(0);
1164 }
1165 /*--------------------------------------------------------------------------*/
mem_write(int hdl,void * buffer,long nbytes)1166 int mem_write(int hdl, void *buffer, long nbytes)
1167 /*
1168   write bytes at the current position in the file
1169 */
1170 {
1171     size_t newsize;
1172     char *ptr;
1173 
1174     if ((size_t) (memTable[hdl].currentpos + nbytes) >
1175          *(memTable[hdl].memsizeptr) )
1176     {
1177 
1178         if (!(memTable[hdl].mem_realloc))
1179         {
1180             ffpmsg("realloc function not defined (mem_write)");
1181             return(WRITE_ERROR);
1182         }
1183 
1184         /*
1185           Attempt to reallocate additional memory:
1186           the memory buffer size is incremented by the larger of:
1187              1 FITS block (2880 bytes) or
1188              the defined 'deltasize' parameter
1189          */
1190 
1191         newsize = maxvalue( (size_t)
1192             (((memTable[hdl].currentpos + nbytes - 1) / 2880) + 1) * 2880,
1193             *(memTable[hdl].memsizeptr) + memTable[hdl].deltasize);
1194 
1195         /* call the realloc function */
1196         ptr = (memTable[hdl].mem_realloc)(
1197                                     *(memTable[hdl].memaddrptr),
1198                                      newsize);
1199         if (!ptr)
1200         {
1201             ffpmsg("Failed to reallocate memory (mem_write)");
1202             return(MEMORY_ALLOCATION);
1203         }
1204 
1205         *(memTable[hdl].memaddrptr) = ptr;
1206         *(memTable[hdl].memsizeptr) = newsize;
1207     }
1208 
1209     /* now copy the bytes from the buffer into memory */
1210     memcpy( *(memTable[hdl].memaddrptr) + memTable[hdl].currentpos,
1211              buffer,
1212              nbytes);
1213 
1214     memTable[hdl].currentpos += nbytes;
1215     memTable[hdl].fitsfilesize =
1216                maxvalue(memTable[hdl].fitsfilesize,
1217                         memTable[hdl].currentpos);
1218     return(0);
1219 }
1220