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