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