 /*
  * Khoros: $Id: writeimage.c,v 1.5 1992/03/20 23:41:15 dkhoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: writeimage.c,v 1.5 1992/03/20 23:41:15 dkhoros Exp $";
#endif

 /*
  * $Log: writeimage.c,v $
 * Revision 1.5  1992/03/20  23:41:15  dkhoros
 * VirtualPatch5
 *
  */ 

/*
 *----------------------------------------------------------------------
 *
 * Copyright 1990, University of New Mexico.  All rights reserved.

 * Permission to copy and modify this software and its documen-
 * tation only for internal use in your organization is hereby
 * granted, provided that this notice is retained thereon and
 * on all copies.  UNM makes no representations as too the sui-
 * tability and operability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 * 
 * UNM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
 * NESS.  IN NO EVENT SHALL UNM BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY OTHER DAMAGES WHAT-
 * SOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PER-
 * FORMANCE OF THIS SOFTWARE.
 * 
 * No other rights, including for example, the right to redis-
 * tribute this software and its documentation or the right to
 * prepare derivative works, are granted unless specifically
 * provided in a separate license agreement.
 *---------------------------------------------------------------------
 */

/*

    WRITEIMAGE - Write an KHOROS image to the file pointed to by the
                 supplied file descriptor.

    Written: Scott Wilson
    Date:     3-Mar-87

    Returns:  1 if successful
	      0 if unsuccessful

    Modified: Scott Wilson and Tom Sauer 11/23/88
              Scott Wilson 27-Feb-89 - Updated to XV III
              Scott Wilson 22-Apr-89 - Finished encode/decode support
	      Scott Wilson 10-Jul-89 - Added return value
              Scott Wilson 11-Dec-90 - Added normal file locking
              Scott Wilson 14-Feb-91 - Added sanity check on data pointers
              Scott Wilson 26-Feb-91 - Write in small chunks instead of one
                huge one. This should help out with NFS for large images.
              Scott Wilson 30-May-91 - Fix "-" and "#" as output files
	      Mark Young 14-Sep-91   Fix "-" and "#" to not perform flock() and
					not get closed.
              Jeremey Worley 1991 - Completely rewritten.
*/

#include "unmcopyright.h"	 /* Copyright 1990 by UNM */
#include "vinclude.h"
#include "vencode.h"

#define VWRITE_SIZE 65536		/* Write 64KB at a time */
#define BYTE_FIELD_SIZE 520
#define OTHER_FIELD_CNT 25
#define VIFF_HEADER_SIZE 1024

writeimage(filename,imageptr)
struct xvimage *imageptr;
char *filename;
  {
    char buf[512];
    int imgsize,locsize,mapsize,imgcnt,loccnt,mapcnt,index,n;
    char *temp1,*temp3;
    float *temp2;
    unsigned char *temp,*ptemp,*ptemp2,*ptemp3,*ptemp4;
    int headersize,i;
    int file;

    /* 
     * Check the image pointer 
     */
    if(imageptr == NULL){
       fprintf(stderr,"writeimage: NULL image pointer, no image written!\n");
       return(NULL);
    }

    /* 
     * Open the output file 
     */
    if(!vfullpath(filename,NULL,buf))return(NULL);

    if((file = kopen(buf,O_WRONLY|O_TRUNC|O_CREAT,0664)) < 0){
       fprintf(stderr,"writeimage: unable to access %s for writing\n",
                           filename);
       return(NULL);
    }

    if (ktransport_permanence(filename) == TRUE) kflock(file, LOCK_EX);

    if(!imagesize(imageptr,&imgsize,&imgcnt,&mapsize,&mapcnt,&locsize, 
       &loccnt)) {
       fprintf(stderr,"writeimage: Uninterpretable image specification\n");
       kwclose(file);
       return(0);
    }

    /* 
     * Sanity check 
     */
    if(imgsize != 0 && imageptr->imagedata == NULL){
       fprintf(stderr,
          "writeimage: Bogus image - no image data but nonzero image size!\n");
       fprintf(stderr,"writeimage: Image not written!\n");
       kwclose(file);
       return(0);
    }

    if(mapsize != 0 && imageptr->maps == NULL){
       fprintf(stderr,
           "writeimage: Bogus image - no map data but nonzero map size!\n");
       fprintf(stderr,"writeimage: Image not written!\n");
       kwclose(file);
       return(0);
    }

    if(locsize != 0 && imageptr->location == NULL){
       fprintf(stderr,"writeimage: Bogus image - no location ");
       fprintf(stderr,"data but nonzero location size!\n");
       fprintf(stderr,"writeimage: Image not written!\n");
       kwclose(file);
       return(0);
    }

    /* 
     * Write the image header 
     * Note that the pointer fields in the header must be written out
     * as NULLs in order that an image file on the disk can be
     * compared using diff or cmp! 
     */
    temp1 = imageptr->maps;      /* Save pointers to data areas */
    temp2 = imageptr->location;
    temp3 = imageptr->imagedata;

    imageptr->maps = NULL;       /* Set 'em to NULL */
    imageptr->location = NULL;
    imageptr->imagedata = NULL;

    if(imageptr->machine_dep!=VFF_DEP_CRAYORDER){
       if(kwrite(file,(char *)imageptr,sizeof(struct xvimage)) 
          != sizeof(struct xvimage)) {
          fprintf(stderr,"writeimage: Unable to write image header\n");
          kwclose(file);
          return(0);
       }
    }else{
        temp = (unsigned char *)imageptr;

        headersize = VIFF_HEADER_SIZE;
        if((ptemp = (unsigned char *)malloc((unsigned)headersize))==NULL){
           (void)fprintf(stderr,"\nwriteimage: Not enough memory to write ");
           (void)fprintf(stderr,"image header\n");
           return(NULL);
        }

        if((ptemp2 = (unsigned char *)malloc(5*sizeof(long)))==NULL){
           (void)fprintf(stderr,"\nwriteimage: Not enough memory to write ");
           (void)fprintf(stderr,"image header\n");
           return(NULL);
        }
        if((ptemp3 = (unsigned char *)malloc(2*sizeof(float)))==NULL){
           (void)fprintf(stderr,"\nwriteimage: Not enough memory to write ");
           (void)fprintf(stderr,"image header\n");
           return(NULL);
        }
        if((ptemp4 = (unsigned char *)malloc(18*sizeof(long)))==NULL){
           (void)fprintf(stderr,"\nwriteimage: Not enough memory to write ");
           (void)fprintf(stderr,"image header\n");
           return(NULL);
        }

        bcopy((char *)(temp+BYTE_FIELD_SIZE),(char *)ptemp2,40);
        bcopy((char *)(temp+BYTE_FIELD_SIZE+40),(char *)ptemp3,16);
        bcopy((char *)(temp+BYTE_FIELD_SIZE+56),(char *)ptemp4,144);

        /*
         * first convert long stuff
         */
        i = convert_long((unsigned char **)&ptemp2,
                             (unsigned int)VFF_DEP_CRAYORDER,
                             (unsigned int)VFF_DEP_IEEEORDER,
                             (unsigned int)5);
        if(!i){
           fprintf(stderr,"\nData format conversion failed in readheader.\n");
           free(ptemp);
           free(ptemp2);
           free(ptemp3);
           free(ptemp4);
           return(0);
        }

        /*
         * then convert float stuff
         */
        i = convert_float((unsigned char **)&ptemp3,
                             (unsigned int)VFF_DEP_CRAYORDER,
                             (unsigned int)VFF_DEP_IEEEORDER,
                             (unsigned int)2);
        if(!i){
           fprintf(stderr,"\nData format conversion failed in readheader.\n");
           free(ptemp);
           free(ptemp2);
           free(ptemp3);
           free(ptemp4);
           return(0);
        }

        /*
         * and then convert last long stuff 
         */
        i = convert_long((unsigned char **)&ptemp4,
                             (unsigned int)VFF_DEP_CRAYORDER,
                             (unsigned int)VFF_DEP_IEEEORDER,
                             (unsigned int)18);
        if(!i){
           fprintf(stderr,"\nData format conversion failed in readheader.\n");
           free(ptemp);
           free(ptemp2);
           free(ptemp3);
           free(ptemp4);
           return(0);
        }

        /*
         * now construct a new header and write it
         */
        bcopy((char *)imageptr,ptemp,BYTE_FIELD_SIZE);
        bcopy((char *)ptemp2,ptemp+BYTE_FIELD_SIZE, 20);
        bcopy((char *)ptemp3,ptemp+BYTE_FIELD_SIZE+20,8);
        bcopy((char *)ptemp4,ptemp+BYTE_FIELD_SIZE+28,72);

        if(kwrite(file,(char *)ptemp,headersize)!=headersize) {
           fprintf(stderr,"writeimage: Unable to write image header\n");
           kwclose(file);
           return(0);
        }
    } /* end cray special case */

    imageptr->maps = temp1;      /* Restore the previous values */
    imageptr->location = temp2;
    imageptr->imagedata = temp3;

    /* 
     * Write maps 
     */

    index = imageptr->data_encode_scheme;

    /* 
     * Write to normal file descriptor 
     */
    switch(imageptr->data_encode_scheme){
       case VFF_DES_RAW:
            n = kwrite(file,imageptr->maps,mapsize);
	    if(n != mapsize){
	       fprintf(stderr,"writeimage: Unable to write maps\n");
               kwclose(file);
               return(0);
            }
            break;
       case VFF_DES_COMPRESS:
       case VFF_DES_RLE:
       case VFF_DES_TRANSFORM:
       case VFF_DES_CCITT:
       case VFF_DES_ADPCM:
       case VFF_DES_GENERIC:
            n = write_compressed(file,(char *)imageptr->maps,mapsize,
                 compr_cmd[index]);
            if (n != mapsize){
                fprintf(stderr,"writeimage: Unable to write maps\n");
                kwclose(file);
                return(0);
            }
	    break;
       default:
            fprintf(stderr,
               "writeimage: Unknown encoding scheme: %d maps not written!\n",
               imageptr->data_encode_scheme);
            kwclose(file);
            return(0);
            /* break; */
    } /* end switch */
                 
    /* 
     * Write the location data 
     */

    switch(imageptr->data_encode_scheme){
       case VFF_DES_RAW: 
            n = kwrite(file,(char *)imageptr->location,locsize);
            if(n != locsize){
               fprintf(stderr,"writeimage: Unable to write location data\n");
               kwclose(file);
               return(0);
            }
            break;
       case VFF_DES_COMPRESS:
       case VFF_DES_RLE:
       case VFF_DES_TRANSFORM:
       case VFF_DES_CCITT:
       case VFF_DES_ADPCM:
       case VFF_DES_GENERIC:
            n = write_compressed(file,(char *)imageptr->location,locsize,
                                 compr_cmd[index]);
            if(n != locsize){
               fprintf(stderr,"writeimage: Unable to write location data\n");
               kwclose(file);
               return(0);
            }
	    break;
       default:
            fprintf(stderr,
            "writeimage: Unknown encoding scheme: %d locations not written!\n",
            imageptr->data_encode_scheme);
            kwclose(file);
            return(0);
            /* break; */
    } /* end switch */
                 
    /* 
     * write image data 
     */

    switch(imageptr->data_encode_scheme){
       case VFF_DES_RAW:
            n = kwrite(file,imageptr->imagedata,imgsize);
            if(n != imgsize){
               fprintf(stderr,"writeimage: Unable to write image data\n");
               kwclose(file);
               return(0);
            }
            break;
       case VFF_DES_COMPRESS:
       case VFF_DES_RLE:
       case VFF_DES_TRANSFORM:
       case VFF_DES_CCITT:
       case VFF_DES_ADPCM:
       case VFF_DES_GENERIC:
            n = write_compressed(file,imageptr->imagedata,imgsize,                                               compr_cmd[index]);
            if(n != imgsize){
               fprintf(stderr,"writeimage: Unable to write image data\n");
               kwclose(file);
               return(0);
            }
	    break;
       default:
            fprintf(stderr,"writeimage: Unknown encoding scheme: %d ",
                    "imagedata not written!\n",index);
            kwclose(file);
            return(0);
            /* break; */
    }

    kwclose(file);
    return(1);
}

kwclose(file)
int file;
  {
        kclose(file);
        kflock(file,LOCK_UN); 
  }
