/***********************************************************************/
/* Open Visualization Data Explorer                                    */
/* (C) Copyright IBM Corp. 1989,1999                                   */
/* ALL RIGHTS RESERVED                                                 */
/* This code licensed under the                                        */
/*    "IBM PUBLIC LICENSE - Open Visualization Data Explorer"          */
/***********************************************************************/
/*
 * $Header: /home/gda/dxcvs/dx/src/exec/dxmods/readimage.c,v 1.3 1999/05/10 15:45:29 gda Exp $
 */

#include <dxconfig.h>


/***
MODULE:
    ReadImage
INPUTS:
    name;        string;   image.rgb;       file name 
    format;      string;   data dependent;  format of file
    start;       integer;  first frame;     starting movie frame
    end;         integer;  last frame;      ending movie frame 
    delta;       integer;  1;               delta of images to read
    width;       integer;  data dependent;  width of image
    height;      Integer;  data dependent;  height of image
    delayed;     integer;  env. dep;        use delayed if present in image file
    colortype;   string;   env. dep;        "float" or "byte"
***/

#include <stdio.h>
#include <string.h>
#include <dx/dx.h>
#include <_helper_jea.h>
#include <_rw_image.h>
#include <fcntl.h>

#ifdef	DXD_WIN   /*   ajay    */
#include <errno.h>
#endif

#if DXD_HAS_LIBIOP
#include <iop/mov.h>
#include <iop/pfs.h>
#endif

#define COLORS_PIXEL 3
#define SPECIFIED(a) 	((a) != VALUE_UNSPECIFIED)

#define CONCAT_PATHS(a, b, c) \
	if (strlen(b)+strlen(c)<MAX_IMAGE_NAMELEN) \
	    sprintf(a, "%s%s", b, c); \
	else \
	    strcpy(a, c); 

static Field InputADASD     (int width, int height, int frame, char* fname, char *colortype);
static Field InputRGB       (int width, int height, int fh, char *colortype);
static Field InputR_G_B     (int width, int height, int fh[3], char *colortype);

static int   get_subpath(char *env_str, int count, char *subpath, int subpathsize);
Field DXMakeImageFormat(int width, int height, char *format);

int
m_ReadImage ( Object *in, Object *out )
{

#define  I_name    in[0]
#define  I_format  in[1]
#define  I_start   in[2]
#define  I_end     in[3]
#define  I_delta   in[4]
#define  I_width   in[5]
#define  I_height  in[6]
#define  I_delayed in[7]
#define  I_colortype in[8]
#define  O_image   out[0]

    char      *filename;
    char      *format;
    char      *colortype_string;
    char      *colortype;

    SizeData  param_sizes;
    SizeData  filed_sizes;
    SizeData  image_sizes;

    Field      image  = NULL;
    Series     series = NULL;
    ImageType  imgtyp = img_typ_illegal;
    ImageInfo  *imginfo;

    int        fh[3];
    int        delta, imgflags;
    int        num_files;

    char      basename[MAX_IMAGE_NAMELEN], *fb_name;
    char      originalname[MAX_IMAGE_NAMELEN];
    char      imagefilename[MAX_IMAGE_NAMELEN];
    char      sizefilename[MAX_IMAGE_NAMELEN];
    char      *envstr_DXDATA;
    int       try_count;
    int       got_file;
    int       found_subpath=0;
    char      user_path[MAX_IMAGE_PATHLEN];
    char      user_basename[MAX_IMAGE_NAMELEN];
    int       fd;
    int       frame;
    long int  frame_size_bytes;
    int       i, j;
    int       delayed;
    char      *str;
    FILE      *fh_miff = NULL;
    
#if DXD_HAS_LIBIOP
    int    Input_from_ADASD = 0;
#else
#define    Input_from_ADASD 0
#endif

    struct
    {
        char name[MAX_IMAGE_NAMELEN];
        int use_numerics;  /* numbered names. */
        int ext_sel;       /* extension: "gif" "giff" or nothing */
        int multiples;     /* many images in one file */
    }
    gifopts;
    
    struct
    {
        char name[MAX_IMAGE_NAMELEN];
        int use_numerics;  /* numbered names. */
        int ext_sel;       /* extension: "tiff" "tif" or nothing */
        int multiples;     /* many images in one file */
    }
    tiffopts;

    struct
    {
        char name[MAX_IMAGE_NAMELEN];
        int use_numerics;  /* numbered names. */
        int ext_sel;       /* extension: "miff" "mif" or nothing */
        int multiples;     /* many images in one file */
    }
    miffopts;
    
    /*
     * Error Check all of the inputs 
     */
    
    O_image = NULL;

    fh[0] = fh[1] = fh[2] = -1;

    if (I_delayed)
    {
	if ( !DXExtractInteger( I_delayed, &delayed ) 
			    ||
	    (delayed != DELAYED_NO && delayed != DELAYED_YES))
	    DXErrorGoto2 ( ERROR_BAD_PARAMETER, "#10070", "delayed" );
    }
    else if (NULL != (str = (char *)getenv("DXDELAYEDCOLORS")))
    {
	if (!strcmp(str, "0"))
	    delayed = DELAYED_NO;
	else if (!strcmp(str, "1"))
	    delayed = DELAYED_YES;
	else
	    DXErrorGoto2
		( ERROR_BAD_PARAMETER, "#10070",
			"DXDELAYEDCOLORS environment variable" );
    }
    else
	delayed = DELAYED_YES;

    if (I_colortype)
    {
	if ( !DXExtractString( I_colortype, &colortype_string )) 
	    DXErrorGoto2 ( ERROR_BAD_PARAMETER, "#10070", "colortype" );
	if (!strcmp(colortype_string, "float"))
	    colortype = COLORTYPE_FLOAT;
	else if (!strcmp(colortype_string, "DXFloat"))
	    colortype = COLORTYPE_FLOAT;
	else if (!strcmp(colortype_string, "byte"))
	    colortype = COLORTYPE_BYTE;
	else if (!strcmp(colortype_string, "DXByte"))
	    colortype = COLORTYPE_BYTE;
	else
	    DXErrorGoto2 ( ERROR_BAD_PARAMETER, "#10070", "colortype" );
    }
    else if (NULL != (str = (char *)getenv("DXPIXELTYPE")))
    {
	if (!strcmp(str, "float"))
	    colortype = COLORTYPE_FLOAT;
	else if (!strcmp(str, "DXFloat"))
	    colortype = COLORTYPE_FLOAT;
	else if (!strcmp(str, "byte"))
	    colortype = COLORTYPE_BYTE;
	else if (!strcmp(str, "DXByte"))
	    colortype = COLORTYPE_BYTE;
	else
	    DXErrorGoto2
		( ERROR_BAD_PARAMETER, "#10070",
			"DXPIXELTYPE environment variable" );
    }
    else
	colortype = COLORTYPE_BYTE;

    if (I_name)
    {
        if ( !DXExtractString ( I_name, &filename ) || ( filename == NULL ) )
            DXErrorGoto2 ( ERROR_MISSING_DATA, "#10200", "name" )

        else if ( strchr ( filename, ':' ) ) {
#if DXD_HAS_LIBIOP
            Input_from_ADASD = 1;
        } else { 
            Input_from_ADASD = 0;
#else
#ifndef DXD_OS_NON_UNIX
	    DXErrorGoto(ERROR_INVALID_DATA,  "#12305");
#endif
#endif
	}
	if (strlen(filename) > MAX_IMAGE_NAMELEN) {
            DXSetError( ERROR_INVALID_DATA, "#12210", "name");
	    goto error;
	}
        strcpy(originalname,filename);
    }
    else
        strcpy(originalname,"image");

    strcpy(basename,originalname);

    envstr_DXDATA = (char *)getenv("DXDATA");
    *user_path = '\0';
    
    if ( I_format )
    {
        if ( !DXExtractString ( I_format, &format ) || ( format == NULL ) )
            DXErrorGoto2 ( ERROR_MISSING_DATA, "#10200", "format" )
		
        else if (!(imginfo = _dxf_ImageInfoFromFormat(format)) )
            DXErrorGoto3
                ( ERROR_BAD_PARAMETER, "#10210", format, "the file format" )
		    
	imgflags = imginfo->flags; 
	imgtyp = imginfo->type;
        if (Input_from_ADASD) {
	    if  (!(imgflags & ADASD_OK))
                DXErrorGoto2 ( ERROR_NOT_IMPLEMENTED, "#12215",format);
	} else if (imgflags & ADASD_ONLY) { 
                DXErrorGoto2 ( ERROR_NOT_IMPLEMENTED, "#12220",format);
        }
    }
    else
    {
        format = NULL;

        imginfo = _dxf_ImageInfoFromFileName ( basename );
        if (imginfo)
		imgtyp = imginfo->type; 

        if ( Input_from_ADASD )
        {
            if (!imginfo) { 
                imgtyp = img_typ_fb;
		imginfo = _dxf_ImageInfoFromType(imgtyp);

                if ( imginfo == NULL )
                    DXErrorGoto 
                        ( ERROR_INVALID_DATA, "image type lookup failed" );
	    }
	    if ((imginfo->flags & ADASD_OK) == 0) {
                DXSetError ( ERROR_NOT_IMPLEMENTED, "#12225", "format");
		goto error;
	    }
        }
        else
        {
            if (!imginfo) { 
                imgtyp = img_typ_rgb;
		imginfo = _dxf_ImageInfoFromType(imgtyp);

                if ( imginfo == NULL )
                    DXErrorGoto 
                        ( ERROR_INVALID_DATA, "image type lookup failed" );
	    }

            if ( imginfo->flags & ADASD_ONLY )  {
                DXSetError ( ERROR_NOT_IMPLEMENTED, "#12230", "name");
		goto error;
	    }
        }
    }

    if ( ( imginfo->read ==         NULL ) &&
         ( imginfo->type != img_typ_tiff && imginfo->type != img_typ_gif) && imginfo->type != img_typ_miff  )
        DXErrorGoto ( ERROR_NOT_IMPLEMENTED, "#12235");
	    
    /*
     * Remove the extension in basename if it is recognized
     * and is an acceptable extension for imgtyp.
     */
    _dxf_RemoveImageExtension(basename,imgtyp);

    if ( I_start )
    {
        if ( !DXExtractInteger ( I_start, &param_sizes.startframe )
             ||
             ( param_sizes.startframe < 0 ) )
            DXErrorGoto2
                ( ERROR_INVALID_DATA, "#10030",  "start" )
    }
    else
        param_sizes.startframe = VALUE_UNSPECIFIED;

    if ( I_end )
    {
        if ( !DXExtractInteger ( I_end, &param_sizes.endframe )
             ||
             ( param_sizes.endframe < 0 ) )
            DXErrorGoto2
                ( ERROR_INVALID_DATA, "#10030", "end" )
    } 
    else
        param_sizes.endframe = VALUE_UNSPECIFIED;

    if ( I_delta )
    {
        if ( !DXExtractInteger ( I_delta, &delta ) || ( delta < 1 ) )
            DXErrorGoto2
                ( ERROR_INVALID_DATA, "#10020",  "delta" )
    }
    else
        delta = 1;

    if ( I_width )
    {
        if ( !DXExtractInteger ( I_width, &param_sizes.width )
             ||
             ( param_sizes.width <= 0 ) )
            DXErrorGoto2
                ( ERROR_INVALID_DATA, "#10020", "width" )
    }
    else
        param_sizes.width = VALUE_UNSPECIFIED;

    if ( I_height )
    {
        if ( !DXExtractInteger ( I_height, &param_sizes.height )
             ||
             ( param_sizes.height <= 0 ) )
            DXErrorGoto2
                ( ERROR_INVALID_DATA, "#10020",  "height" )
    }
    else
        param_sizes.height = VALUE_UNSPECIFIED;

    /*
     * Assemble filename from input strings: filename and format.
     */
    if ( Input_from_ADASD )
    {
        DXASSERT ( imgtyp == img_typ_fb );

        /* Note that the sizefilename = imagefilename here.  
	 * Also, we can pass VALUE_UNSPECIFIED as the 'frame number' to 
	 * _dxf_BuildImageFileName, since the fb format has APPENDABLE_FILES and
	 * thus the frame number is ignored.
   	 */

	try_count = 0;
	do {
	    CONCAT_PATHS(user_basename, user_path, basename);
	    if (!_dxf_BuildImageFileName(sizefilename, MAX_IMAGE_NAMELEN, user_basename, 
				         imgtyp, VALUE_UNSPECIFIED,0))
		goto error;
	    if (!_dxf_ReadImageSizesADASD(sizefilename, &filed_sizes))
		goto error;
	} while ( !(got_file = (SPECIFIED(filed_sizes.width) && SPECIFIED(filed_sizes.height)))
	  	  &&
		  (get_subpath(envstr_DXDATA, try_count++, user_path, sizeof(user_path))) );
	found_subpath = *user_path != '\0';

	/* 
	 * Check to see that the file exists (i.e. height/width were found). 
	 * If not, then try and open the file without the extension.
	 */

	if (!got_file) {
	    int same_name;
	    if (!_dxf_BuildImageFileName(sizefilename, MAX_IMAGE_NAMELEN, basename,
					 imgtyp, VALUE_UNSPECIFIED,0))
		goto error;
	    same_name = strcmp(sizefilename,filename) == 0;
	    try_count = 0;
	    if (!same_name) do {
		CONCAT_PATHS(user_basename, user_path, filename);
		if (!_dxf_ReadImageSizesADASD(user_basename, &filed_sizes))
		    goto error;
	    } while ( !(got_file = (SPECIFIED(filed_sizes.width) && SPECIFIED(filed_sizes.height)))
		      &&
		      !found_subpath
		      &&
		      (get_subpath(envstr_DXDATA, try_count++, user_path, sizeof(user_path))) );
	    found_subpath = *user_path != '\0';
	    if (!got_file) {
		if (same_name) {
	            DXErrorGoto2(ERROR_BAD_PARAMETER, "#12240",sizefilename);
		} else {
	            DXErrorGoto3(ERROR_BAD_PARAMETER, 
				"#12245",sizefilename,filename);
		}
	    }
	}
    }
    else
    {
        /*
         * Assemble size-file-name from input string filename and "size"
         * Open and read-in or default backwards.
         */

        switch ( imgtyp /* imginfo->type */ )
        {
            case img_typ_rgb:
            case img_typ_r_g_b:
            case img_typ_fb:
            default:

	        strcpy(sizefilename,basename);
        	strcat(sizefilename,".size");

		try_count=0;
		do {
		    CONCAT_PATHS(user_basename, user_path, sizefilename);
		    if (!_dxf_ReadSizeFile(user_basename, &filed_sizes))
		        goto error;
		} while ( !(got_file = (SPECIFIED(filed_sizes.width))
					&& (SPECIFIED(filed_sizes.height)))
			  &&
			  !found_subpath
			  &&
			  get_subpath(envstr_DXDATA, try_count++, user_path, sizeof(user_path)) );
		found_subpath = *user_path != '\0';
                break;

            case img_typ_gif:

		try_count=0;
		do {
		    CONCAT_PATHS(user_basename, user_path, basename);
		    if ( !_dxf_BuildGIFReadFileName
			     ( gifopts.name,
			       MAX_IMAGE_NAMELEN,
			       user_basename,
			       originalname,
			       (param_sizes.startframe==VALUE_UNSPECIFIED)?
				   0 : param_sizes.startframe,
			       &gifopts.use_numerics,
			       &gifopts.ext_sel ) )
			goto error;
		    got_file = ((fd = open(gifopts.name, O_RDONLY)) != -1);
		    if (got_file)
			close(fd);
		} while ( !got_file
			  &&
			  !found_subpath
			  &&
			  get_subpath(envstr_DXDATA, try_count++, user_path, sizeof(user_path)) );
		if (!got_file)
		    DXErrorGoto2
		      (ERROR_BAD_PARAMETER,
		      "Could not open file %s, nor any other GIF name variation"
		      " in current path or DXDATA",
		      filename);
		if (!_dxf_ReadImageSizesGIF
				       (gifopts.name,
				       param_sizes.startframe,
				       &filed_sizes,
				       &gifopts.use_numerics,
				       gifopts.ext_sel,
				       &gifopts.multiples))
		    goto error;
		found_subpath = *user_path != '\0';
                break;


            case img_typ_tiff:

		try_count=0;
		do {
		    CONCAT_PATHS(user_basename, user_path, basename);
		    if ( !_dxf_BuildTIFFReadFileName
			     ( tiffopts.name,
			       MAX_IMAGE_NAMELEN,
			       user_basename,
			       originalname,
			       (param_sizes.startframe==VALUE_UNSPECIFIED)?
				   0 : param_sizes.startframe,
			       &tiffopts.use_numerics,
			       &tiffopts.ext_sel ) )
			goto error;
		    got_file = ((fd = open(tiffopts.name, O_RDONLY)) != -1);
		    if (got_file)
			close(fd);
		} while ( !got_file
			  &&
			  !found_subpath
			  &&
			  get_subpath(envstr_DXDATA, try_count++, user_path, sizeof(user_path)) );
		if (!got_file)
		    DXErrorGoto2
		      (ERROR_BAD_PARAMETER,
		      "Could not open file %s, nor any other TIFF name variation"
		      " in current path or DXDATA",
		      filename);
		if (!_dxf_ReadImageSizesTIFF
				       (tiffopts.name,
				       param_sizes.startframe,
				       &filed_sizes,
				       &tiffopts.use_numerics,
				       tiffopts.ext_sel,
				       &tiffopts.multiples))
		    goto error;
		found_subpath = *user_path != '\0';
                break;

            case img_typ_miff:

		try_count=0;
		do {
		    CONCAT_PATHS(user_basename, user_path, basename);
		    if (!_dxf_BuildImageFileName(miffopts.name, MAX_IMAGE_NAMELEN, user_basename, 
						imgtyp, 0, 0))
			goto error;
		    miffopts.ext_sel = 0;
		    got_file = ((fd = open(miffopts.name, O_RDONLY)) != -1);
		    if (got_file)
			close(fd);
		} while ( !got_file
			  &&
			  !found_subpath
			  &&
			  get_subpath(envstr_DXDATA, try_count++, user_path, sizeof(user_path)) );
		if (!got_file)
		    DXErrorGoto2
		      (ERROR_BAD_PARAMETER,
		      "Could not open file %s, nor any other MIFF name variation"
		      " in current path or DXDATA",
		      filename);
		if (!_dxf_ReadImageSizesMIFF
				       (miffopts.name,
				       param_sizes.startframe,
				       &filed_sizes,
				       &miffopts.use_numerics,
				       miffopts.ext_sel,
				       &miffopts.multiples))
		    goto error;
		found_subpath = *user_path != '\0';
                break;

        }
    }

    /*
     * Determine size-file inputs from size file and those of the command line.
     */
    /* Size file has precedence */
    image_sizes.width
        = (SPECIFIED(filed_sizes.width) ?
              filed_sizes.width : param_sizes.width);

    /* Size file has precedence */
    image_sizes.height	
        = (SPECIFIED(filed_sizes.height) ? 
              filed_sizes.height : param_sizes.height);

    /* User parameter has precedence, with a default of 0 */
    image_sizes.startframe
        = (SPECIFIED(param_sizes.startframe) ?
            param_sizes.startframe : 
            (SPECIFIED(filed_sizes.startframe) ? filed_sizes.startframe : 0));

    /* User parameter has precedence, with a default of 0 */
    image_sizes.endframe
        = (SPECIFIED(param_sizes.endframe) ?
            param_sizes.endframe : 
            (SPECIFIED(filed_sizes.endframe) ? filed_sizes.endframe : 0));


    /*
     * Warn if the user supplied 'width' and 'height' parameters  don't
     * match those found in the size file (if present).
     */
    if ( SPECIFIED(param_sizes.width) && SPECIFIED(filed_sizes.width) &&
         ( param_sizes.width != filed_sizes.width ) ) 
    {
        DXSetError(ERROR_BAD_PARAMETER, "#12250", "width");
	goto error;
    }

    if ( SPECIFIED(param_sizes.height) && SPECIFIED(filed_sizes.height) &&
         ( param_sizes.height != filed_sizes.height ) )
    {
        DXSetError(ERROR_BAD_PARAMETER, "#12250", "height");
	goto error;
    }

    /*
     * Verify the user supplied 'start' and 'end' parameters. 
     */
    if (SPECIFIED(param_sizes.startframe) && SPECIFIED(filed_sizes.endframe) && 
         ( param_sizes.startframe > filed_sizes.endframe) )
    {
        DXSetError(ERROR_BAD_PARAMETER, "#12255", "start", 
				filed_sizes.startframe, filed_sizes.endframe);
        return ERROR;
    }

    if (SPECIFIED(param_sizes.endframe) && SPECIFIED(filed_sizes.endframe) && 
         ( param_sizes.endframe > filed_sizes.endframe ) )
    {
        DXSetError(ERROR_BAD_PARAMETER, "#12255", "end",
		  filed_sizes.startframe, filed_sizes.endframe);
        return ERROR;
    }

    if ( image_sizes.startframe > image_sizes.endframe ) {
        DXSetError ( ERROR_INVALID_DATA, "#12260",
                   image_sizes.startframe, image_sizes.endframe );
        return ERROR;
    }

    if (
#if DXD_HAS_LIBIOP
   /* The sizes are inside the fb file, so it is always ok for the
    * height and width to not be specified. 
    */
    (imgtyp != img_typ_fb) &&
#endif
    (!SPECIFIED(image_sizes.width) || !SPECIFIED(image_sizes.height))) {
	/* 
	 * ARG!!! Because we allow for the .size file to be optional and
	 * we haven't opened the pixel file yet, we need to try and open the
	 * pixel file in order to give the correct error message (i.e. it
	 * could be that 1) the user gave a bad file name or 2) there is no 
	 * .size file and one of width and height was not specified).
	 */

        /* XXX - tiff name considerations */

	try_count=0;
	do {
	    CONCAT_PATHS(user_basename, user_path, basename);
	    if (!_dxf_BuildImageFileName(imagefilename, MAX_IMAGE_NAMELEN, user_basename, 
						imgtyp, image_sizes.startframe,0))
		return ERROR;
	} while ( ((i = open(imagefilename, O_RDONLY)) <0)
		  &&
		  !found_subpath
		  &&
		  get_subpath(envstr_DXDATA, try_count++, user_path, sizeof(user_path)) );
	found_subpath = *user_path != '\0';

        if (i<0)  {
	    if (!_dxf_BuildImageFileName(imagefilename, MAX_IMAGE_NAMELEN, basename, 
						imgtyp, image_sizes.startframe,0))
		return ERROR;
  	    DXSetError( ERROR_INVALID_DATA, "#12240", imagefilename); /* cannot open fname */
	} else { 
	    close(i);
            DXSetError ( ERROR_INVALID_DATA, "#12265"); /* size file is missing */
	}
        return ERROR;
    }

    /*
     * Attempt to open image file and position to start of frame(s).
     */
    frame_size_bytes = image_sizes.width * image_sizes.height;

    switch ( imgtyp )
    {
        case img_typ_rgb:    frame_size_bytes *= 3;  break;
        case img_typ_r_g_b:  frame_size_bytes *= 1;  break;
        case img_typ_fb:     frame_size_bytes *= 4;  break;
        case img_typ_tiff:                           break;
        case img_typ_gif:                            break;
        case img_typ_miff:                           break;

        default:
            DXErrorGoto ( ERROR_ASSERTION, "imgtyp" );
    }

    num_files = (imgtyp==img_typ_r_g_b)? 3 : 1;

    for ( i=0; i<num_files; i++ )
    {

	do {
	    CONCAT_PATHS(user_basename, user_path, basename);
	    if (imgtyp != img_typ_tiff && imgtyp != img_typ_gif && imgtyp != img_typ_miff)
		if ( !_dxf_BuildImageFileName(imagefilename, MAX_IMAGE_NAMELEN,
					      user_basename, imgtyp,
					      image_sizes.startframe, i))
		    goto error;

	    if ( Input_from_ADASD )
	    {
		DXASSERTGOTO ( num_files == 1 );
	    }
	    else if (imgtyp != img_typ_tiff && imgtyp != img_typ_gif && imgtyp != img_typ_miff)
	    {
		fd = open(imagefilename,O_RDONLY); 
	    }
	} while ( !Input_from_ADASD 
		  &&
		  (imgtyp != img_typ_tiff && imgtyp != img_typ_gif && imgtyp != img_typ_miff)
		  &&
		  (fd<0)
		  &&
		  !found_subpath
		  &&
		  get_subpath(envstr_DXDATA, try_count++, user_path, sizeof(user_path)) );

	found_subpath = *user_path != '\0';
	if (!Input_from_ADASD && (imgtyp != img_typ_tiff && imgtyp != img_typ_gif && imgtyp != img_typ_miff))
	{
	    if (fd < 0) 
	    {
		if ( !_dxf_BuildImageFileName(imagefilename, MAX_IMAGE_NAMELEN,
					      basename, imgtyp,
					      image_sizes.startframe, i))
		    goto error;
		DXErrorGoto2 ( ERROR_INVALID_DATA, 
			"#12240", imagefilename );
	    }
	    if ( imgtyp != img_typ_tiff && imgtyp != img_typ_gif && imgtyp != img_typ_miff)
		if ( lseek ( fd, (image_sizes.startframe*frame_size_bytes), 0 )
		     != ( image_sizes.startframe * frame_size_bytes ) )
		    DXErrorGoto3
			( ERROR_INTERNAL, "#12270",
			  image_sizes.startframe, imagefilename );
	    fh[i] = fd;
	}
    }
            
    /*
     * Read in frame(s).  For multiple images, construct a series group.
     */

    if ( image_sizes.startframe == image_sizes.endframe ) 
        series = NULL;

    else if ( ERROR == ( series = DXNewSeries() ) )
        goto error;

    fb_name = NULL;

    for ( i=0, frame = image_sizes.startframe;
	       frame <= image_sizes.endframe;
	  i++, frame+=delta ) 
    {
	if ((frame != image_sizes.startframe ) && 
	    (delta != 1) &&
            (imgtyp != img_typ_tiff && imgtyp != img_typ_gif && imgtyp != img_typ_miff) &&
	    !Input_from_ADASD )
	{
	    for ( j=0; j<num_files; j++ )
	    {
		if ( lseek ( fh[j], ( frame * frame_size_bytes ), 0 ) 
		     !=
		     ( frame * frame_size_bytes ) ) {
		    DXSetError ( ERROR_INTERNAL, "#12270", frame, "");
		    goto error;
		}
	    }
        }

	switch ( imgtyp )
	{
	    case img_typ_rgb:
		image = InputRGB(image_sizes.width, image_sizes.height, fh[0], colortype);
		break;

	    case img_typ_r_g_b:
		image = InputR_G_B(image_sizes.width, image_sizes.height, fh, colortype);
		break;

	    case img_typ_gif:
		if ( gifopts.use_numerics && !gifopts.multiples )
		{
		    if ( gifopts.ext_sel == 2 )
		    {
			if ( !_dxf_RemoveExtension ( gifopts.name ) )
			    goto error;
		    }
		    else
			if ( !_dxf_RemoveExtension ( gifopts.name ) ||
			     !_dxf_RemoveExtension ( gifopts.name )   )
			    goto error;

		    sprintf
			( &gifopts.name [ strlen( gifopts.name ) ],
			  (gifopts.ext_sel==0)? ".%d.gif" :
			  (gifopts.ext_sel==1)? ".%d.gif"  :
						 ".%d",
			  frame );
		}
		image = _dxf_InputGIF(image_sizes.width,
		    image_sizes.height, gifopts.name,
		   (gifopts.multiples)?(frame-filed_sizes.startframe):0,
		   delayed, colortype);
		break;

	    case img_typ_tiff:
		if ( tiffopts.use_numerics && !tiffopts.multiples )
		{
		    if ( tiffopts.ext_sel == 2 )
		    {
			if ( !_dxf_RemoveExtension ( tiffopts.name ) )
			    goto error;
		    }
		    else
			if ( !_dxf_RemoveExtension ( tiffopts.name ) ||
			     !_dxf_RemoveExtension ( tiffopts.name )   )
			    goto error;

		    sprintf
			( &tiffopts.name [ strlen ( tiffopts.name ) ],
			  (tiffopts.ext_sel==0)? ".%d.tiff" :
			  (tiffopts.ext_sel==1)? ".%d.tif"  :
						 ".%d",
			  frame );
		}
		image = _dxf_InputTIFF(image_sizes.width,
		    image_sizes.height, tiffopts.name,
		   (tiffopts.multiples)?(frame-filed_sizes.startframe):0,
		   delayed, colortype);
		break;

	    case img_typ_miff:
		if ( miffopts.use_numerics && !miffopts.multiples )
		{
		    if ( miffopts.ext_sel == 2 )
		    {
			if ( !_dxf_RemoveExtension ( miffopts.name ) )
			    goto error;
		    }
		    else
			if ( !_dxf_RemoveExtension ( miffopts.name ) ||
			     !_dxf_RemoveExtension ( miffopts.name )   )
			    goto error;

		    sprintf
			( &miffopts.name [ strlen ( miffopts.name ) ],
			  (miffopts.ext_sel==0)? ".%d.miff" :
			  (miffopts.ext_sel==1)? ".%d.mif"  :
						 ".%d",
			  frame );
		}
		image = _dxf_InputMIFF(&fh_miff, image_sizes.width,
		    image_sizes.height, miffopts.name,
		   (miffopts.multiples)?(frame-filed_sizes.startframe):0,
		   delayed, colortype);
		break;

	    case img_typ_fb:
		/* For fb format we allow the file to be opened without
		 * the '.fb' extension.  Once we've found it though,
		 * stay with it.
		 */
		if (!fb_name)  {
		    image = InputADASD(image_sizes.width,
				image_sizes.height, frame, imagefilename, colortype);
		    
		    if (image)
			fb_name = imagefilename; 
		    else
		    {
			image = InputADASD(image_sizes.width,
				image_sizes.height, frame, imagefilename, colortype);

			if (image)
			    fb_name = basename; 
			else
			    goto error;
		    }
		}
		else
		{
		    image = InputADASD (image_sizes.width,
				image_sizes.height, frame, fb_name, colortype);
		    if (! image)
			goto error;
		}

		break;

	    default:
		DXErrorGoto ( ERROR_ASSERTION, "image type" );

	}

	if (! image)
	    goto error;

	if (series && !DXSetSeriesMember(series,i,(float)frame,(Object)image))
	    goto error;
    }

    if ( fh[0] >= 0 ) close  ( fh[0] );
    if ( fh[1] >= 0 ) close  ( fh[1] );
    if ( fh[2] >= 0 ) close  ( fh[2] );

    if (fh_miff != 0) fclose(fh_miff);

    O_image = ( ( series ) ? (Object)series : (Object) image );

    return OK;
error:
    /* Clean up. */

    if ( fh[0] >= 0 ) close  ( fh[0] );
    if ( fh[1] >= 0 ) close  ( fh[1] );
    if ( fh[2] >= 0 ) close  ( fh[2] );
    if (fh_miff != 0) fclose(fh_miff);
    if ( series           ) DXDelete ( (Object) series );
    if ( !series && image ) DXDelete ( (Object) image  );
    return ERROR;
}

#define BYTES_FLOAT 4
/*
 * Algorithmic considerations:
 *   Since the pixel content of an unread image is undefined,
 *   and is to be completely overwritten after this call;
 *   We therefore use the 'top fourth' of this area for
 *   our read buffer.
 *   Another useful item is that both the On-disk and in
 *   memory formats store in the order (Red-Green-Blue).
 */
static
Field InputRGB (int width, int height, int fh, char *colortype)
{
    int            oneline;
    int            oneframe;
    unsigned char  *anchor;
    float          *fptr;
    unsigned char  *cptr0;
    unsigned char  *cptr1;
    int            i, y, x;
    Array 	   colorsArray;
    Type 	   type;
    int		   expandToFloat;
    Field	   image = NULL;
    int		   rank, shape[32];

    if ((width * height) == 0)
    {
        DXSetError ( ERROR_BAD_PARAMETER, "#12275",0);
	return ERROR;
    }

    image = DXMakeImageFormat(width, height, colortype);
    if (! image)
	goto error;
    
    colorsArray = (Array)DXGetComponentValue(image, "colors");
    if (! colorsArray)
	goto error;
    
    DXGetArrayInfo(colorsArray, NULL, &type, NULL, &rank, shape);

    if (type == TYPE_FLOAT)
    {
	expandToFloat = 1;
    }
    else 
    {
	if (rank != 1 || shape[0] != 3)
	{
	    DXSetError(ERROR_INTERNAL,
	       "readimage from .rgb files requires 3-vector colors");
	    goto error;
	}
	
	expandToFloat = 0;
    }

    anchor = (unsigned char *)DXGetArrayData(colorsArray);

    oneline  = width * COLORS_PIXEL;
    oneframe = oneline * height;

    /* Read complete image directly into memory in native disk format.
     *
     * Byte format scanlines in image memory after read-in:
     *  +--------------------------------------+
     *  |                   empty              |
     *  +--------------------------------------+
     *  |                     "                |
     *  +--------------------------------------+
     *  |                     "                |
     *  +---------+----------------------------+
     *  |    y0   |           "                |
     *  +---------+---------+---------+--------+
     *  |  ymax-1 |  ymax-2 |   ...   |   y1   |
     *  +---------+---------+---------+--------+
     *(origin)
     */

    /*
     * Note that the above figure is appropriate if the output
     * image type is float.  If its byte, the result is simply:
     *
     *  +--------------------------------------+
     *  |    y0                                |
     *  +--------------------------------------+
     *  |    y1                                |
     *  +--------------------------------------+
     *  |   ...                                |
     *  +--------------------------------------+
     *  |  ymax-2                              |
     *  +--------------------------------------+
     *  |  ymax-1			       |
     *  +--------------------------------------+
     */

    if (read(fh, anchor, oneframe) != oneframe)
    {
        DXSetError
            ( ERROR_BAD_PARAMETER, "#12280", height, width );
        return ERROR;
    }

    /*
     * Invert ordering of scan-lines
     */
    cptr0 = anchor;
    cptr1 = anchor + (height-1)*oneline;
    for (y = 0; y < (height>>1); y++, cptr0 += oneline, cptr1 -= oneline)
    {
	unsigned char *c0 = (char *)cptr0;
	unsigned char *c1 = (char *)cptr1;

	for (x = 0; x < oneline; x++, c0++, c1++)
	{
	    unsigned char tmp = *c1;
	    *c1 = *c0;
	    *c0 = tmp;
	}
    }

    if (expandToFloat)
    {
	float         *dstY = ((float *)anchor) + (height-1)*oneline;
	unsigned char *srcY = ((unsigned char *)anchor) + (height-1)*oneline;
	float	      denom = 1.0 / 255.0;

	for (y = (height-1); y >= 0; y--, dstY -= oneline, srcY -= oneline)
	{
	    float *dstX = dstY + (oneline-1);
	    unsigned char *srcX = srcY + (oneline-1);
	    for (x = 0; x < oneline; x++, dstX--, srcX--)
		*dstX = *srcX * denom;
	}
    }

    return image;

error:
    if (DXGetError() == ERROR_NONE)
	DXSetError(ERROR_INTERNAL, "");

    DXDelete((Object)image);

    return ERROR;
}


static
Field InputR_G_B (int width, int height, int fh[3], char *colortype)
{
    int            oneframe;
    Pointer        *pixels;
    ubyte   	   *buffer = NULL;
    ubyte   	   *c_ptr;
    int            c;
    int            i, j;
    Field	   image = NULL;
    Array	   colorsArray = NULL;
    Type	   type;
    int		   rank, shape[32];

    if ((width * height) == 0) 
        DXErrorReturn(ERROR_BAD_PARAMETER, "Attempt to read 0 sized image");

    image = DXMakeImageFormat(width, height, colortype);
    if (! image)
	goto error;
    
    colorsArray = (Array)DXGetComponentValue(image, "colors");
    if (! colorsArray)
	goto error;
    
    pixels = DXGetArrayData(colorsArray);

    oneframe = width * height;
    if (!( buffer = DXAllocateLocal(oneframe)))
        goto error;

    DXGetArrayInfo(colorsArray, NULL, &type, NULL, &rank, shape);

    if (type == TYPE_UBYTE)
    {
	ubyte *p_ptr;

	if (rank != 1 || shape[0] != 3)
	{
	    DXSetError(ERROR_INTERNAL,
	       "readimage from r+g+b files requires 3-vector colors");
	    goto error;
	}
	
	for (c=0; c<3; c++)
	{
	    if ( read ( fh[c], buffer, oneframe ) != oneframe )
	    {
		DXSetError
		    ( ERROR_BAD_PARAMETER, "#12290",
		      height, width, (c==0)?'r' : (c==1)?'g' : 'b' );
		return ERROR;
	    }

	    for ( i=0; i<height; i++ )
	    {
		c_ptr = buffer + width*( height-i-1);
		p_ptr = ((ubyte *)pixels) + 3*width*i + c;

		for ( j=0; j<width; j++, c_ptr++, p_ptr+=3)
		    *p_ptr = *c_ptr;
	    }
	}
    }
    else if (type == TYPE_FLOAT)
    {
	float *p_ptr;

	for (c=0; c<3; c++)
	{
	    if ( read ( fh[c], buffer, oneframe ) != oneframe )
	    {
		DXSetError
		    ( ERROR_BAD_PARAMETER, "#12290",
		      height, width, (c==0)?'r' : (c==1)?'g' : 'b' );
		return ERROR;
	    }

	    for ( i=0; i<height; i++ )
	    {
		c_ptr = buffer + width*(height-i-1);
		p_ptr = ((float *)pixels) + 3*width*i + c;

		for ( j=0; j<width; j++, c_ptr++, p_ptr+=3 )
		    *p_ptr = *c_ptr / 255.0;
	    }
	}
    }
    else
    {
	DXSetError(ERROR_INTERNAL,
	   "readimage from .rgb files requires 3-vector byte or float colors");
	goto error;
    }
	

    DXFree((Pointer)buffer);

    return image;

error:
    if(DXGetError() == ERROR_NONE)
	DXSetError(ERROR_INTERNAL, "");

    DXFree((Pointer)buffer);
    DXDelete((Object)image);
    return ERROR;
}


static
Field InputADASD (int width, int height, int frame, char* fname, char *colortype)
{

#if !defined(DXD_HAS_LIBIOP)
    DXErrorReturn(ERROR_INVALID_DATA, "#12295");
#else
    typedef struct { unsigned char b, g, r, a } BGRA;
    static float   lut [ 256 ];
    static int     lut_loaded = 0;
    char    *ibuffer = NULL;
    int     mov_errcode; /* 'mov_errno' is a global */
    struct  mov_stat_s ms;
    u_int   *buffer_aligned;
    mov_id  mid = 0;
    Pointer *opixels;
    BGRA    *ipixels;
    BGRA    *ip;
    int     i, j, bufsize;
    Field   image = NULL;
    Array   colorsArray;
    Type    type;


    image = DXMakeImageFormat(width, height, colortype);
    if (! image)
	goto error;
    
    colorsArray = (Array *)DXGetComponentValue(image, "colors");

    opixels = (Pointer)DXGetArrayData(colorsArray);

    DXGetArrayInfo(colorsArray, NULL, &type, NULL, NULL, NULL);


    if (mov_stat(fname, &ms) < 0) {
        DXErrorGoto2 ( ERROR_INTERNAL, 
			"%s, (mov_open)", mov_errmsg ( mov_errno ) );
    }

    if (frame+1 > ms.frames)
        DXErrorGoto2 ( ERROR_INVALID_DATA,  "#12300", frame);

    bufsize = ms.frame_blocks * MOV_BLK_SIZE + 1023;

    ibuffer = (char *)DXAllocate(bufsize);
    if (! ibuffer)
        goto error;

    buffer_aligned = ( (int)ibuffer % 1024 )
                     ? (u_int *)( (int)ibuffer + 1024 - ( (int)ibuffer % 1024))
                     : (u_int *)ibuffer;


    if ((mid = mov_open(fname)) == 0)
        DXErrorGoto2
            ( ERROR_INTERNAL, "%s, (mov_open)", mov_errmsg ( mov_errno ) );

    if ( ( mov_errcode = mov_get
                             ( mid,
                               ( frame + 1 ),
                               ( frame + 1 ),
                               (u_int *)buffer_aligned ) ) < 0 )
        DXErrorGoto2
            ( ERROR_INTERNAL, "%s, (mov_get)", mov_errmsg ( mov_errcode ));
        
    if ( ( mov_errcode = mov_close ( mid ) ) < 0 )
        DXErrorGoto2
            ( ERROR_INTERNAL, "%s, (mov_close)", mov_errmsg ( mov_errcode ));

    mid = 0;

    ipixels = (BGRA *) buffer_aligned;

    if (type == TYPE_FLOAT)
    {
	/* 
	 * Pre-Calculate the divisions, so they aren't recalculated on a 
	 * per-pixel basis.
	 */
	if ( !lut_loaded )
	{
	    for (i=0; i<256; i++)
		lut [i] = ((float)i / 255.0);

	    lut_loaded = 1;
	}

	for ( i=0; i<height; i++ )
	{
	    RGBColor *op = ((RGBColor *)opixels) + i*width;
	    ip = &ipixels [ (height-i-1) * width ];

	    for ( j=0; j<width; j++, ip++, op++ )
	    {
		op->r = lut[ip->r];
		op->g = lut[ip->g];
		op->b = lut[ip->b];
	    }
	}
    }
    else if (type == TYPE_UBYTE)
    {
	for ( i=0; i<height; i++ )
	{
	    ubyte *op = ((ubyte *)opixels) + i*width;
	    ip = ipixels + (height-i-1)*width;

	    memcpy(op, ip, 3*width);
	}
    }
    else
    {
	DXSetError(ERROR_INTERNAL,
	   "readimage from adasd files requires 3-vector byte or float colors");
	goto error;
    }
			      
    if (ibuffer) DXFree ( (Pointer) ibuffer );

    return image;

error:
    if (ibuffer)
        DXFree((Pointer)ibuffer);

    if (DXGetError() == ERROR_NONE)
	DXSetError(ERROR_INTERNAL, "");

    DXDelete((Object)image);

    return ERROR;

#endif
}

static int get_subpath(char *env_str, int count, char *subpath, int subpathsize)
{
    int i;
    char *s;
#ifndef DXD_OS_NON_UNIX
#   define PATH_SEP_CHAR ':'
#else
#   define PATH_SEP_CHAR ';'
#endif

    *subpath = '\0';
    for (s=env_str,i=0;i<count && s && *s;i++)
    {
	s = strchr(s, PATH_SEP_CHAR);
	if (s && *s)
	    s++;
    }
    if (s && *s)
	strncpy(subpath, s, subpathsize);
    s = strchr(subpath, PATH_SEP_CHAR);
    if (s && *s)
	*s = '\0';
    if (*subpath && (subpath[strlen(subpath)-1] != '/'))
	strcat(subpath,"/");
    
    return (int) *subpath;
}
