1 /* This file, drvrfile.c contains driver routines for disk 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 "fitsio2.h"
10 #include "group.h" /* needed for fits_get_cwd in file_create */
11
12 #if defined(unix) || defined(__unix__) || defined(__unix)
13 #include <pwd.h> /* needed in file_openfile */
14
15 #ifdef REPLACE_LINKS
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #endif
19
20 #endif
21
22 #ifdef HAVE_FTRUNCATE
23 #if defined(unix) || defined(__unix__) || defined(__unix) || defined(HAVE_UNISTD_H)
24 #include <unistd.h> /* needed for getcwd prototype on unix machines */
25 #endif
26 #endif
27
28 #define IO_SEEK 0 /* last file I/O operation was a seek */
29 #define IO_READ 1 /* last file I/O operation was a read */
30 #define IO_WRITE 2 /* last file I/O operation was a write */
31
32 static char file_outfile[FLEN_FILENAME];
33
34 typedef struct /* structure containing disk file structure */
35 {
36 FILE *fileptr;
37 LONGLONG currentpos;
38 int last_io_op;
39 } diskdriver;
40
41 static diskdriver handleTable[NMAXFILES]; /* allocate diskfile handle tables */
42
43 /*--------------------------------------------------------------------------*/
file_init(void)44 int file_init(void)
45 {
46 int ii;
47
48 for (ii = 0; ii < NMAXFILES; ii++) /* initialize all empty slots in table */
49 {
50 handleTable[ii].fileptr = 0;
51 }
52 return(0);
53 }
54 /*--------------------------------------------------------------------------*/
file_setoptions(int options)55 int file_setoptions(int options)
56 {
57 /* do something with the options argument, to stop compiler warning */
58 options = 0;
59 return(options);
60 }
61 /*--------------------------------------------------------------------------*/
file_getoptions(int * options)62 int file_getoptions(int *options)
63 {
64 *options = 0;
65 return(0);
66 }
67 /*--------------------------------------------------------------------------*/
file_getversion(int * version)68 int file_getversion(int *version)
69 {
70 *version = 10;
71 return(0);
72 }
73 /*--------------------------------------------------------------------------*/
file_shutdown(void)74 int file_shutdown(void)
75 {
76 return(0);
77 }
78 /*--------------------------------------------------------------------------*/
file_open(char * filename,int rwmode,int * handle)79 int file_open(char *filename, int rwmode, int *handle)
80 {
81 FILE *diskfile;
82 int copyhandle, ii, status;
83 char recbuf[2880];
84 size_t nread;
85
86 /*
87 if an output filename has been specified as part of the input
88 file, as in "inputfile.fits(outputfile.fit)" then we have to
89 create the output file, copy the input to it, then reopen the
90 the new copy.
91 */
92
93 if (*file_outfile)
94 {
95 /* open the original file, with readonly access */
96 status = file_openfile(filename, READONLY, &diskfile);
97 if (status) {
98 file_outfile[0] = '\0';
99 return(status);
100 }
101
102 /* create the output file */
103 status = file_create(file_outfile,handle);
104 if (status)
105 {
106 ffpmsg("Unable to create output file for copy of input file:");
107 ffpmsg(file_outfile);
108 file_outfile[0] = '\0';
109 return(status);
110 }
111
112 /* copy the file from input to output */
113 while(0 != (nread = fread(recbuf,1,2880, diskfile)))
114 {
115 status = file_write(*handle, recbuf, nread);
116 if (status) {
117 file_outfile[0] = '\0';
118 return(status);
119 }
120 }
121
122 /* close both files */
123 fclose(diskfile);
124 copyhandle = *handle;
125 file_close(*handle);
126 *handle = copyhandle; /* reuse the old file handle */
127
128 /* reopen the new copy, with correct rwmode */
129 status = file_openfile(file_outfile, rwmode, &diskfile);
130 file_outfile[0] = '\0';
131 }
132 else
133 {
134 *handle = -1;
135 for (ii = 0; ii < NMAXFILES; ii++) /* find empty slot in table */
136 {
137 if (handleTable[ii].fileptr == 0)
138 {
139 *handle = ii;
140 break;
141 }
142 }
143
144 if (*handle == -1)
145 return(TOO_MANY_FILES); /* too many files opened */
146
147 /*open the file */
148 status = file_openfile(filename, rwmode, &diskfile);
149 }
150
151 handleTable[*handle].fileptr = diskfile;
152 handleTable[*handle].currentpos = 0;
153 handleTable[*handle].last_io_op = IO_SEEK;
154
155 return(status);
156 }
157 /*--------------------------------------------------------------------------*/
file_openfile(char * filename,int rwmode,FILE ** diskfile)158 int file_openfile(char *filename, int rwmode, FILE **diskfile)
159 /*
160 lowest level routine to physically open a disk file
161 */
162 {
163 char mode[4];
164
165 #if defined(unix) || defined(__unix__) || defined(__unix)
166 char tempname[1024], *cptr, user[80];
167 struct passwd *pwd;
168 int ii = 0;
169
170 #if defined(REPLACE_LINKS)
171 struct stat stbuf;
172 int success = 0;
173 size_t n;
174 FILE *f1, *f2;
175 char buf[BUFSIZ];
176 #endif
177
178 #endif
179
180 if (rwmode == READWRITE)
181 {
182 strcpy(mode, "r+b"); /* open existing file with read-write */
183 }
184 else
185 {
186 strcpy(mode, "rb"); /* open existing file readonly */
187 }
188
189 #if MACHINE == ALPHAVMS || MACHINE == VAXVMS
190 /* specify VMS record structure: fixed format, 2880 byte records */
191 /* but force stream mode access to enable random I/O access */
192 *diskfile = fopen(filename, mode, "rfm=fix", "mrs=2880", "ctx=stm");
193
194 #elif defined(unix) || defined(__unix__) || defined(__unix)
195
196 /* support the ~user/file.fits or ~/file.fits filenames in UNIX */
197
198 if (*filename == '~')
199 {
200 if (filename[1] == '/')
201 {
202 cptr = getenv("HOME");
203 if (cptr)
204 {
205 if (strlen(cptr) + strlen(filename+1) > 1023)
206 return(FILE_NOT_OPENED);
207
208 strcpy(tempname, cptr);
209 strcat(tempname, filename+1);
210 }
211 else
212 {
213 if (strlen(filename) > 1023)
214 return(FILE_NOT_OPENED);
215
216 strcpy(tempname, filename);
217 }
218 }
219 else
220 {
221 /* copy user name */
222 cptr = filename+1;
223 while (*cptr && (*cptr != '/'))
224 {
225 user[ii] = *cptr;
226 cptr++;
227 ii++;
228 }
229 user[ii] = '\0';
230
231 /* get structure that includes name of user's home directory */
232 pwd = getpwnam(user);
233
234 /* copy user's home directory */
235 if (strlen(pwd->pw_dir) + strlen(cptr) > 1023)
236 return(FILE_NOT_OPENED);
237
238 strcpy(tempname, pwd->pw_dir);
239 strcat(tempname, cptr);
240 }
241
242 *diskfile = fopen(tempname, mode);
243 }
244 else
245 {
246 /* don't need to expand the input file name */
247 *diskfile = fopen(filename, mode);
248
249 #if defined(REPLACE_LINKS)
250
251 if (!(*diskfile) && (rwmode == READWRITE))
252 {
253 /* failed to open file with READWRITE privilege. Test if */
254 /* the file we are trying to open is a soft link to a file that */
255 /* doesn't have write privilege. */
256
257 lstat(filename, &stbuf);
258 if ((stbuf.st_mode & S_IFMT) == S_IFLNK) /* is this a soft link? */
259 {
260 if ((f1 = fopen(filename, "rb")) != 0) /* try opening READONLY */
261 {
262
263 if (strlen(filename) + 7 > 1023)
264 return(FILE_NOT_OPENED);
265
266 strcpy(tempname, filename);
267 strcat(tempname, ".TmxFil");
268 if ((f2 = fopen(tempname, "wb")) != 0) /* create temp file */
269 {
270 success = 1;
271 while ((n = fread(buf, 1, BUFSIZ, f1)) > 0)
272 {
273 /* copy linked file to local temporary file */
274 if (fwrite(buf, 1, n, f2) != n)
275 {
276 success = 0;
277 break;
278 }
279 }
280 fclose(f2);
281 }
282 fclose(f1);
283
284 if (success)
285 {
286 /* delete link and rename temp file to previous link name */
287 remove(filename);
288 rename(tempname, filename);
289
290 /* try once again to open the file with write access */
291 *diskfile = fopen(filename, mode);
292 }
293 else
294 remove(tempname); /* clean up the failed copy */
295 }
296 }
297 }
298 #endif
299
300 }
301
302 #else
303
304 /* other non-UNIX machines */
305 *diskfile = fopen(filename, mode);
306
307 #endif
308
309 if (!(*diskfile)) /* couldn't open file */
310 {
311 return(FILE_NOT_OPENED);
312 }
313 return(0);
314 }
315 /*--------------------------------------------------------------------------*/
file_create(char * filename,int * handle)316 int file_create(char *filename, int *handle)
317 {
318 FILE *diskfile;
319 int ii;
320 char mode[4];
321
322 int status = 0, rootlen, rootlen2, slen;
323 char *cptr, *cpos;
324 char cwd[FLEN_FILENAME], absURL[FLEN_FILENAME];
325 char rootstring[256], rootstring2[256];
326 char username[FLEN_FILENAME], userroot[FLEN_FILENAME], userroot2[FLEN_FILENAME];
327
328 cptr = getenv("HERA_DATA_DIRECTORY");
329 if (cptr) {
330 /* This environment variable is defined in the Hera data analysis environment. */
331 /* It specifies the root directory path to the users data directories. */
332 /* CFITSIO will verify that the path to the file that is to be created */
333 /* is within this root directory + the user's home directory name. */
334
335 /*
336 printf("env = %s\n",cptr);
337 */
338 if (strlen(cptr) > 200) /* guard against possible string overflows */
339 return(FILE_NOT_CREATED);
340
341 /* environment variable has the form "path/one/;/path/two/" where the */
342 /* second path is optional */
343
344 strcpy(rootstring, cptr);
345 cpos = strchr(rootstring, ';');
346 if (cpos) {
347 *cpos = '\0';
348 cpos++;
349 strcpy(rootstring2, cpos);
350 } else {
351 *rootstring2 = '\0';
352 }
353 /*
354 printf("%s, %s\n", rootstring, rootstring2);
355 printf("CWD = %s\n", cwd);
356 printf("rootstring=%s, cwd=%s.\n", rootstring, cwd);
357 */
358 /* Get the current working directory */
359 fits_get_cwd(cwd, &status);
360 slen = strlen(cwd);
361 if ((slen < FLEN_FILENAME) && cwd[slen-1] != '/') strcat(cwd,"/"); /* make sure the CWD ends with slash */
362
363
364 /* check that CWD string matches the rootstring */
365 rootlen = strlen(rootstring);
366 if (strncmp(rootstring, cwd, rootlen)) {
367 ffpmsg("invalid CWD: does not match root data directory");
368 return(FILE_NOT_CREATED);
369 } else {
370
371 /* get the user name from CWD (it follows the root string) */
372 strncpy(username, cwd+rootlen, 50); /* limit length of user name */
373 username[50]=0;
374 cpos=strchr(username, '/');
375 if (!cpos) {
376 ffpmsg("invalid CWD: not equal to root data directory + username");
377 return(FILE_NOT_CREATED);
378 } else {
379 *(cpos+1) = '\0'; /* truncate user name string */
380
381 /* construct full user root name */
382 strcpy(userroot, rootstring);
383 strcat(userroot, username);
384 rootlen = strlen(userroot);
385
386 /* construct alternate full user root name */
387 strcpy(userroot2, rootstring2);
388 strcat(userroot2, username);
389 rootlen2 = strlen(userroot2);
390
391 /* convert the input filename to absolute path relative to the CWD */
392 fits_relurl2url(cwd, filename, absURL, &status);
393
394 /*
395 printf("username = %s\n", username);
396 printf("userroot = %s\n", userroot);
397 printf("userroot2 = %s\n", userroot2);
398 printf("filename = %s\n", filename);
399 printf("ABS = %s\n", absURL);
400 */
401 /* check that CWD string matches the rootstring or alternate root string */
402
403 if ( strncmp(userroot, absURL, rootlen) &&
404 strncmp(userroot2, absURL, rootlen2) ) {
405 ffpmsg("invalid filename: path not within user directory");
406 return(FILE_NOT_CREATED);
407 }
408 }
409 }
410 /* if we got here, then the input filename appears to be valid */
411 }
412
413 *handle = -1;
414 for (ii = 0; ii < NMAXFILES; ii++) /* find empty slot in table */
415 {
416 if (handleTable[ii].fileptr == 0)
417 {
418 *handle = ii;
419 break;
420 }
421 }
422 if (*handle == -1)
423 return(TOO_MANY_FILES); /* too many files opened */
424
425 strcpy(mode, "w+b"); /* create new file with read-write */
426
427 diskfile = fopen(filename, "r"); /* does file already exist? */
428
429 if (diskfile)
430 {
431 fclose(diskfile); /* close file and exit with error */
432 return(FILE_NOT_CREATED);
433 }
434
435 #if MACHINE == ALPHAVMS || MACHINE == VAXVMS
436 /* specify VMS record structure: fixed format, 2880 byte records */
437 /* but force stream mode access to enable random I/O access */
438 diskfile = fopen(filename, mode, "rfm=fix", "mrs=2880", "ctx=stm");
439 #else
440 diskfile = fopen(filename, mode);
441 #endif
442
443 if (!(diskfile)) /* couldn't create file */
444 {
445 return(FILE_NOT_CREATED);
446 }
447
448 handleTable[ii].fileptr = diskfile;
449 handleTable[ii].currentpos = 0;
450 handleTable[ii].last_io_op = IO_SEEK;
451
452 return(0);
453 }
454 /*--------------------------------------------------------------------------*/
file_truncate(int handle,LONGLONG filesize)455 int file_truncate(int handle, LONGLONG filesize)
456 /*
457 truncate the diskfile to a new smaller size
458 */
459 {
460
461 #ifdef HAVE_FTRUNCATE
462 int fdesc;
463
464 fdesc = fileno(handleTable[handle].fileptr);
465 ftruncate(fdesc, (OFF_T) filesize);
466 file_seek(handle, filesize);
467
468 handleTable[handle].currentpos = filesize;
469 handleTable[handle].last_io_op = IO_SEEK;
470
471 #endif
472
473 return(0);
474 }
475 /*--------------------------------------------------------------------------*/
file_size(int handle,LONGLONG * filesize)476 int file_size(int handle, LONGLONG *filesize)
477 /*
478 return the size of the file in bytes
479 */
480 {
481 OFF_T position1,position2;
482 FILE *diskfile;
483
484 diskfile = handleTable[handle].fileptr;
485
486 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
487
488 /* call the VISUAL C++ version of the routines which support */
489 /* Large Files (> 2GB) if they are supported (since VC 8.0) */
490
491 position1 = _ftelli64(diskfile); /* save current postion */
492 if (position1 < 0)
493 return(SEEK_ERROR);
494
495 if (_fseeki64(diskfile, 0, 2) != 0) /* seek to end of file */
496 return(SEEK_ERROR);
497
498 position2 = _ftelli64(diskfile); /* get file size */
499 if (position2 < 0)
500 return(SEEK_ERROR);
501
502 if (_fseeki64(diskfile, position1, 0) != 0) /* seek back to original pos */
503 return(SEEK_ERROR);
504
505 #elif _FILE_OFFSET_BITS - 0 == 64
506
507 /* call the newer ftello and fseeko routines , which support */
508 /* Large Files (> 2GB) if they are supported. */
509
510 position1 = ftello(diskfile); /* save current postion */
511 if (position1 < 0)
512 return(SEEK_ERROR);
513
514 if (fseeko(diskfile, 0, 2) != 0) /* seek to end of file */
515 return(SEEK_ERROR);
516
517 position2 = ftello(diskfile); /* get file size */
518 if (position2 < 0)
519 return(SEEK_ERROR);
520
521 if (fseeko(diskfile, position1, 0) != 0) /* seek back to original pos */
522 return(SEEK_ERROR);
523
524 #else
525
526 position1 = ftell(diskfile); /* save current postion */
527 if (position1 < 0)
528 return(SEEK_ERROR);
529
530 if (fseek(diskfile, 0, 2) != 0) /* seek to end of file */
531 return(SEEK_ERROR);
532
533 position2 = ftell(diskfile); /* get file size */
534 if (position2 < 0)
535 return(SEEK_ERROR);
536
537 if (fseek(diskfile, position1, 0) != 0) /* seek back to original pos */
538 return(SEEK_ERROR);
539
540 #endif
541
542 *filesize = (LONGLONG) position2;
543
544 return(0);
545 }
546 /*--------------------------------------------------------------------------*/
file_close(int handle)547 int file_close(int handle)
548 /*
549 close the file
550 */
551 {
552
553 if (fclose(handleTable[handle].fileptr) )
554 return(FILE_NOT_CLOSED);
555
556 handleTable[handle].fileptr = 0;
557 return(0);
558 }
559 /*--------------------------------------------------------------------------*/
file_remove(char * filename)560 int file_remove(char *filename)
561 /*
562 delete the file from disk
563 */
564 {
565 remove(filename);
566 return(0);
567 }
568 /*--------------------------------------------------------------------------*/
file_flush(int handle)569 int file_flush(int handle)
570 /*
571 flush the file
572 */
573 {
574 if (fflush(handleTable[handle].fileptr) )
575 return(WRITE_ERROR);
576
577 /* The flush operation is not supposed to move the internal */
578 /* file pointer, but it does on some Windows-95 compilers and */
579 /* perhaps others, so seek to original position to be sure. */
580 /* This seek will do no harm on other systems. */
581
582 #if MACHINE == IBMPC
583
584 if (file_seek(handle, handleTable[handle].currentpos))
585 return(SEEK_ERROR);
586
587 #endif
588
589 return(0);
590 }
591 /*--------------------------------------------------------------------------*/
file_seek(int handle,LONGLONG offset)592 int file_seek(int handle, LONGLONG offset)
593 /*
594 seek to position relative to start of the file
595 */
596 {
597
598 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
599
600 /* Microsoft visual studio C++ */
601 /* _fseeki64 supported beginning with version 8.0 */
602
603 if (_fseeki64(handleTable[handle].fileptr, (OFF_T) offset, 0) != 0)
604 return(SEEK_ERROR);
605
606 #elif _FILE_OFFSET_BITS - 0 == 64
607
608 if (fseeko(handleTable[handle].fileptr, (OFF_T) offset, 0) != 0)
609 return(SEEK_ERROR);
610
611 #else
612
613 if (fseek(handleTable[handle].fileptr, (OFF_T) offset, 0) != 0)
614 return(SEEK_ERROR);
615
616 #endif
617
618 handleTable[handle].currentpos = offset;
619 return(0);
620 }
621 /*--------------------------------------------------------------------------*/
file_read(int hdl,void * buffer,long nbytes)622 int file_read(int hdl, void *buffer, long nbytes)
623 /*
624 read bytes from the current position in the file
625 */
626 {
627 long nread;
628 char *cptr;
629
630 if (handleTable[hdl].last_io_op == IO_WRITE)
631 {
632 if (file_seek(hdl, handleTable[hdl].currentpos))
633 return(SEEK_ERROR);
634 }
635
636 nread = (long) fread(buffer, 1, nbytes, handleTable[hdl].fileptr);
637
638 if (nread == 1)
639 {
640 cptr = (char *) buffer;
641
642 /* some editors will add a single end-of-file character to a file */
643 /* Ignore it if the character is a zero, 10, or 32 */
644 if (*cptr == 0 || *cptr == 10 || *cptr == 32)
645 return(END_OF_FILE);
646 else
647 return(READ_ERROR);
648 }
649 else if (nread != nbytes)
650 {
651 return(READ_ERROR);
652 }
653
654 handleTable[hdl].currentpos += nbytes;
655 handleTable[hdl].last_io_op = IO_READ;
656 return(0);
657 }
658 /*--------------------------------------------------------------------------*/
file_write(int hdl,void * buffer,long nbytes)659 int file_write(int hdl, void *buffer, long nbytes)
660 /*
661 write bytes at the current position in the file
662 */
663 {
664 if (handleTable[hdl].last_io_op == IO_READ)
665 {
666 if (file_seek(hdl, handleTable[hdl].currentpos))
667 return(SEEK_ERROR);
668 }
669
670 if((long) fwrite(buffer, 1, nbytes, handleTable[hdl].fileptr) != nbytes)
671 return(WRITE_ERROR);
672
673 handleTable[hdl].currentpos += nbytes;
674 handleTable[hdl].last_io_op = IO_WRITE;
675 return(0);
676 }
677 /*--------------------------------------------------------------------------*/
file_compress_open(char * filename,int rwmode,int * hdl)678 int file_compress_open(char *filename, int rwmode, int *hdl)
679 /*
680 This routine opens the compressed diskfile by creating a new uncompressed
681 file then opening it. The input file name (the name of the compressed
682 file) gets replaced with the name of the uncompressed file, which is
683 initially stored in the global file_outfile string. file_outfile
684 then gets set to a null string.
685 */
686 {
687 FILE *indiskfile, *outdiskfile;
688 int status;
689 char *cptr;
690
691 /* open the compressed disk file */
692 status = file_openfile(filename, READONLY, &indiskfile);
693 if (status)
694 {
695 ffpmsg("failed to open compressed disk file (file_compress_open)");
696 ffpmsg(filename);
697 return(status);
698 }
699
700 /* name of the output uncompressed file is stored in the */
701 /* global variable called 'file_outfile'. */
702
703 cptr = file_outfile;
704 if (*cptr == '!')
705 {
706 /* clobber any existing file with the same name */
707 cptr++;
708 remove(cptr);
709 }
710 else
711 {
712 outdiskfile = fopen(file_outfile, "r"); /* does file already exist? */
713
714 if (outdiskfile)
715 {
716 ffpmsg("uncompressed file already exists: (file_compress_open)");
717 ffpmsg(file_outfile);
718 fclose(outdiskfile); /* close file and exit with error */
719 file_outfile[0] = '\0';
720 return(FILE_NOT_CREATED);
721 }
722 }
723
724 outdiskfile = fopen(cptr, "w+b"); /* create new file */
725 if (!outdiskfile)
726 {
727 ffpmsg("could not create uncompressed file: (file_compress_open)");
728 ffpmsg(file_outfile);
729 file_outfile[0] = '\0';
730 return(FILE_NOT_CREATED);
731 }
732
733 /* uncompress file into another file */
734 uncompress2file(filename, indiskfile, outdiskfile, &status);
735 fclose(indiskfile);
736 fclose(outdiskfile);
737
738 if (status)
739 {
740 ffpmsg("error in file_compress_open: failed to uncompressed file:");
741 ffpmsg(filename);
742 ffpmsg(" into new output file:");
743 ffpmsg(file_outfile);
744 file_outfile[0] = '\0';
745 return(status);
746 }
747
748 strcpy(filename, cptr); /* switch the names */
749 file_outfile[0] = '\0';
750
751 status = file_open(filename, rwmode, hdl);
752
753 return(status);
754 }
755 /*--------------------------------------------------------------------------*/
file_is_compressed(char * filename)756 int file_is_compressed(char *filename) /* I - FITS file name */
757 /*
758 Test if the disk file is compressed. Returns 1 if compressed, 0 if not.
759 This may modify the filename string by appending a compression suffex.
760 */
761 {
762 FILE *diskfile;
763 unsigned char buffer[2];
764 char tmpfilename[FLEN_FILENAME];
765
766 /* Open file. Try various suffix combinations */
767 if (file_openfile(filename, 0, &diskfile))
768 {
769 if (strlen(filename) > FLEN_FILENAME - 5)
770 return(0);
771
772 strcpy(tmpfilename,filename);
773 strcat(filename,".gz");
774 if (file_openfile(filename, 0, &diskfile))
775 {
776 #if HAVE_BZIP2
777 strcpy(filename,tmpfilename);
778 strcat(filename,".bz2");
779 if (file_openfile(filename, 0, &diskfile))
780 {
781 #endif
782 strcpy(filename, tmpfilename);
783 strcat(filename,".Z");
784 if (file_openfile(filename, 0, &diskfile))
785 {
786 strcpy(filename, tmpfilename);
787 strcat(filename,".z"); /* it's often lower case on CDROMs */
788 if (file_openfile(filename, 0, &diskfile))
789 {
790 strcpy(filename, tmpfilename);
791 strcat(filename,".zip");
792 if (file_openfile(filename, 0, &diskfile))
793 {
794 strcpy(filename, tmpfilename);
795 strcat(filename,"-z"); /* VMS suffix */
796 if (file_openfile(filename, 0, &diskfile))
797 {
798 strcpy(filename, tmpfilename);
799 strcat(filename,"-gz"); /* VMS suffix */
800 if (file_openfile(filename, 0, &diskfile))
801 {
802 strcpy(filename,tmpfilename); /* restore original name */
803 return(0); /* file not found */
804 }
805 }
806 }
807 }
808 }
809 #if HAVE_BZIP2
810 }
811 #endif
812 }
813 }
814
815 if (fread(buffer, 1, 2, diskfile) != 2) /* read 2 bytes */
816 {
817 fclose(diskfile); /* error reading file so just return */
818 return(0);
819 }
820
821 fclose(diskfile);
822
823 /* see if the 2 bytes have the magic values for a compressed file */
824 if ( (memcmp(buffer, "\037\213", 2) == 0) || /* GZIP */
825 (memcmp(buffer, "\120\113", 2) == 0) || /* PKZIP */
826 (memcmp(buffer, "\037\036", 2) == 0) || /* PACK */
827 (memcmp(buffer, "\037\235", 2) == 0) || /* LZW */
828 #if HAVE_BZIP2
829 (memcmp(buffer, "BZ", 2) == 0) || /* BZip2 */
830 #endif
831 (memcmp(buffer, "\037\240", 2) == 0)) /* LZH */
832 {
833 return(1); /* this is a compressed file */
834 }
835 else
836 {
837 return(0); /* not a compressed file */
838 }
839 }
840 /*--------------------------------------------------------------------------*/
file_checkfile(char * urltype,char * infile,char * outfile)841 int file_checkfile (char *urltype, char *infile, char *outfile)
842 {
843 /* special case: if file:// driver, check if the file is compressed */
844 if ( file_is_compressed(infile) )
845 {
846 /* if output file has been specified, save the name for future use: */
847 /* This is the name of the uncompressed file to be created on disk. */
848 if (strlen(outfile))
849 {
850 if (!strncmp(outfile, "mem:", 4) )
851 {
852 /* uncompress the file in memory, with READ and WRITE access */
853 strcpy(urltype, "compressmem://"); /* use special driver */
854 *file_outfile = '\0';
855 }
856 else
857 {
858 strcpy(urltype, "compressfile://"); /* use special driver */
859
860 /* don't copy the "file://" prefix, if present. */
861 if (!strncmp(outfile, "file://", 7) )
862 strcpy(file_outfile,outfile+7);
863 else
864 strcpy(file_outfile,outfile);
865 }
866 }
867 else
868 {
869 /* uncompress the file in memory */
870 strcpy(urltype, "compress://"); /* use special driver */
871 *file_outfile = '\0'; /* no output file was specified */
872 }
873 }
874 else /* an ordinary, uncompressed FITS file on disk */
875 {
876 /* save the output file name for later use when opening the file. */
877 /* In this case, the file to be opened will be opened READONLY, */
878 /* and copied to this newly created output file. The original file */
879 /* will be closed, and the copy will be opened by CFITSIO for */
880 /* subsequent processing (possibly with READWRITE access). */
881 if (strlen(outfile)) {
882 file_outfile[0] = '\0';
883 strncat(file_outfile,outfile,FLEN_FILENAME-1);
884 }
885 }
886
887 return 0;
888 }
889 /**********************************************************************/
890 /**********************************************************************/
891 /**********************************************************************/
892
893 /**** driver routines for stream//: device (stdin or stdout) ********/
894
895
896 /*--------------------------------------------------------------------------*/
stream_open(char * filename,int rwmode,int * handle)897 int stream_open(char *filename, int rwmode, int *handle)
898 {
899 /*
900 read from stdin
901 */
902 if (filename)
903 rwmode = 1; /* dummy statement to suppress unused parameter compiler warning */
904
905 *handle = 1; /* 1 = stdin */
906
907 return(0);
908 }
909 /*--------------------------------------------------------------------------*/
stream_create(char * filename,int * handle)910 int stream_create(char *filename, int *handle)
911 {
912 /*
913 write to stdout
914 */
915
916 if (filename) /* dummy statement to suppress unused parameter compiler warning */
917 *handle = 2;
918 else
919 *handle = 2; /* 2 = stdout */
920
921 return(0);
922 }
923 /*--------------------------------------------------------------------------*/
stream_size(int handle,LONGLONG * filesize)924 int stream_size(int handle, LONGLONG *filesize)
925 /*
926 return the size of the file in bytes
927 */
928 {
929 handle = 0; /* suppress unused parameter compiler warning */
930
931 /* this operation is not supported in a stream; return large value */
932 *filesize = LONG_MAX;
933 return(0);
934 }
935 /*--------------------------------------------------------------------------*/
stream_close(int handle)936 int stream_close(int handle)
937 /*
938 don't have to close stdin or stdout
939 */
940 {
941 handle = 0; /* suppress unused parameter compiler warning */
942
943 return(0);
944 }
945 /*--------------------------------------------------------------------------*/
stream_flush(int handle)946 int stream_flush(int handle)
947 /*
948 flush the file
949 */
950 {
951 if (handle == 2)
952 fflush(stdout);
953
954 return(0);
955 }
956 /*--------------------------------------------------------------------------*/
stream_seek(int handle,LONGLONG offset)957 int stream_seek(int handle, LONGLONG offset)
958 /*
959 seeking is not allowed in a stream
960 */
961 {
962 offset = handle; /* suppress unused parameter compiler warning */
963 return(1);
964 }
965 /*--------------------------------------------------------------------------*/
stream_read(int hdl,void * buffer,long nbytes)966 int stream_read(int hdl, void *buffer, long nbytes)
967 /*
968 reading from stdin stream
969 */
970
971 {
972 long nread;
973
974 if (hdl != 1)
975 return(1); /* can only read from stdin */
976
977 nread = (long) fread(buffer, 1, nbytes, stdin);
978
979 if (nread != nbytes)
980 {
981 /* return(READ_ERROR); */
982 return(END_OF_FILE);
983 }
984
985 return(0);
986 }
987 /*--------------------------------------------------------------------------*/
stream_write(int hdl,void * buffer,long nbytes)988 int stream_write(int hdl, void *buffer, long nbytes)
989 /*
990 write bytes at the current position in the file
991 */
992 {
993 if (hdl != 2)
994 return(1); /* can only write to stdout */
995
996 if((long) fwrite(buffer, 1, nbytes, stdout) != nbytes)
997 return(WRITE_ERROR);
998
999 return(0);
1000 }
1001
1002
1003
1004
1005