/* Program Name            : FILERDEC.C                                 */
/*   Original Author       : C. K. Hung					*/
/*   Date                  : 30-MAY-1991				*/
/*   Program Description   :                                            */
/*                         :                                            */
/* Revision History follows                                             */
/*  03-Jun-1999 JL usaged of __FIB                                      */
 
 
 
#include "global.h"
#include "endecode.h"
#include "filer.h"
#include "filercpy.h"
#include "filerdec.h"
#include "filerenc.h"
#include "filerque.h"
#include "inquire.h"
#include <atrdef.h>
#include <fibdef.h>
#include <iodef.h>
#include <sbkdef.h>
 
/**  Record Attributes Area  **/
struct raa_tag {
    unsigned char fat$b_rtype;
    unsigned char fat$b_rattrib;
    unsigned short int fat$w_rsize;
    struct {
	unsigned short int fat$w_hiblkh;
	unsigned short int fat$w_hiblkl;
    } fat$l_hiblk;
    struct {
	unsigned short int fat$w_efblkh;
	unsigned short int fat$w_efblkl;
    } fat$l_efblk;
    short int fat$w_ffbyte;
    unsigned char fat$b_bktsize;
    unsigned char fat$b_vfcsize;
    short int fat$w_maxrec;
    short int fat$w_defext;
    short int fat$w_gbc;
    short int spares1;
    int spares2;
    short int spares3;
    short int fat$w_versions;
};
 
/*
**
**  INTERNAL FUNCTION PROTOTYPING
**
**/
 
    static int		    filer_decode$2(char *from, char *to, char *errmsg);
    static int		    create_same(char *output_file_name, FILE *lzw_file, char *errmsg, unsigned short chan);
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      tbs
**
**--
**/
int	filer_decode()
{
    if (DX_CURRENT_DIRECTORY.filemode == multiple)
	filer_multiple_decode();
    else
	filer_single_decode();
   return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      to be specified
**
**--
**/
int	filer_multiple_decode()
{
    char dummy[] = "";
    char errmsg[MAXFILESPEC+1];
 
    strcpy(errmsg, "Error decoding file");
    multi_get_userinput_and_exec(
	filer_decode$1,
	"Multiple Decode",
	"Decode to: ",
	"",
	errmsg);
   return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      tbs
**
**--
**/
int	filer_single_decode()
{
    char fn[MAXFILESPEC+1];
    char errmsg[MAXFILESPEC+1];
 
    if (!strcmp(DX_CURRENT_FILE->fn, "[-]"))
    {
        signal_err("Expand a parent directory file not allowed", bell);
    }
    else
    {
	find_full_path_name(DX_CURRENT_FILE->fn, fn, cntrl_info_block.cur_win);
	strcpy(errmsg, "Error decoding file");
	get_userinput_and_execute(
	    filer_decode$1,
	    "Decode File",
	    "Decode to: ",
	    "",
	    errmsg,
	    fn);
    }
   return DX__NORMAL;
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      tbs
**
**--
**/
int	filer_decode$1(to, from, errmsg)
char *to;
char *from;
char *errmsg;
{
    return filer_decode$2(from, to, errmsg);
}
 
 

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      tbs
**
**--
**/
 
static int	filer_decode$2(from, to , errmsg)
char *from;
char *to;
char *errmsg;
{
    FILE *output_file;
    FILE *lzw_file;
 
    unsigned long status;
    long vm_len;
 
    struct FAB to_fab;
    struct NAM to_nam;
    char expand_name[NAM$C_MAXRSS];
    struct fil_dx_tag temp_entry;
    struct filespec_list_tag *s;
    unsigned short int chan;
    int total_dids;
    char equ_name[MAXFILESPEC+1],
	 dir_name[MAXFILESPEC+1];
    int i;
 
    vm_len = TABLE_SIZE*sizeof(unsigned int);
    if ((status = lib$get_vm (
			 &vm_len,
			 &prefix_code,
			 0)) != SS$_NORMAL) {
 
	strcpy(errmsg, "Error allocating virtual memory - exceeded quota");
	return DX__ERROR;
 
    }
 
    vm_len = TABLE_SIZE*sizeof(unsigned char);
    if ((status = lib$get_vm (
			 &vm_len,
			 &append_character,
			 0)) != SS$_NORMAL) {
 
	strcpy(errmsg, "Error allocating virtual memory - exceeded quota");
	return DX__ERROR;
 
    }
 
    lzw_file = fopen(from, "r");
    if (lzw_file == NULL)
    {
        sprintf(errmsg, "Error opening input file %s", from);
	return DX__ERROR;
    }
 
    /**  GET DIRECTORY FID AND FILE NAME OF THE OUTPUT FILE  **/
    to_fab = cc$rms_fab;
    to_nam = cc$rms_nam;
 
    to_fab.fab$l_fna = to;
    to_fab.fab$b_fns = strlen(to);
    to_fab.fab$l_nam = &to_nam;
    to_fab.fab$l_xab = NULL;
 
    to_fab.fab$l_dna = from;
    to_fab.fab$b_dns = strcspn (from, ";");
 
    to_nam.nam$l_esa = &expand_name;
    to_nam.nam$b_ess = NAM$C_MAXRSS;
 
    if ((status = sys$parse(&to_fab, 0, 0)) != RMS$_NORMAL)
    {
	sprintf(errmsg, "Invalid file specification");
	return DX__ERROR;
    }
 
    expand_name[to_nam.nam$b_esl] = EOS;
 
    /*
    **	Find the I/O channel for this file
    **/
 
    strcpy(equ_name, "");
    strcpy(dir_name, "");
    total_dids = 0;
    for (s = DX_CURRENT_DIRECTORY.cur_filter.name_filespec_list;
	    s != (struct filespec_list_tag *)NULL;  s = s->next)
    {
	struct w_dids_tag *t;
 
        for (t = s->w_dids;  t != (struct w_dids_tag *)NULL;  t = t->next)
        {
	    if (t->did[0] == DX_CURRENT_FILE->did[0] &&
		t->did[1] == DX_CURRENT_FILE->did[1] &&
		t->did[2] == DX_CURRENT_FILE->did[2])
	    {
		chan = t->chan;
		strcpy(dir_name, t->equivalent_name);
	    }
            if (strcmp(equ_name, t->equivalent_name))
            {
                total_dids++;
		strcpy(equ_name, t->equivalent_name);
            }
        }
    }
 
    if (create_same(expand_name, lzw_file, errmsg, chan) == -1)
    {
	sprintf(errmsg, "Error creating output file %s", expand_name);
	return DX__ERROR;
    }
 
    output_file = fopen(expand_name, "r+");
    if (output_file == NULL)
    {
        sprintf(errmsg, "Error re-opening output file %s", expand_name);
	return DX__ERROR;
    }
 
    if (expand(errmsg, lzw_file, output_file) != DX__NORMAL)
    {
	return DX__ERROR;
    }
 
    fclose(lzw_file);
    fclose(output_file);
 
    vm_len = TABLE_SIZE*sizeof(unsigned int);
    if ((status = lib$free_vm(
			    &vm_len,
			    &prefix_code,
			    0)) != SS$_NORMAL)
    {
	strcpy(errmsg, "Error freeing up virtual memory used");
	return DX__ERROR;
    }
 
    vm_len = TABLE_SIZE*sizeof(unsigned char);
    if ((status = lib$free_vm(
			    &vm_len,
			    &append_character,
			    0)) != SS$_NORMAL)
    {
	strcpy(errmsg, "Error freeing up virtual memory used");
	return DX__ERROR;
    }
 
    /*
    **	Get file attributes
    **/
 
    if (filestat(expand_name, &temp_entry, errmsg) == DX__ERROR)
    {
        return DX__ERROR;
    }
 
    if (total_dids > 1)
    {
        strcat(dir_name, temp_entry.fn);
	strcpy(temp_entry.fn, dir_name);
    }
    temp_entry.state = waiting;
    temp_entry.beg_y = temp_entry.beg_x = 0;
    temp_entry.forward = temp_entry.backward = NULL;
 
    /*
    **  Update cache queue.
    **	In case of running out of memory, output error message
    **	but update current display(s) anyway.
    **/
 
    if (update_filer_cache(temp_entry, add_to_filer_cache, errmsg) == DX__ERROR)
    {
        signal_err(errmsg, bell);
    }
 
    /*
    **	Update the filer list and display
    **/
 
    if (add_to_filer(temp_entry, errmsg, cntrl_info_block.cur_win) == DX__ERROR)
    {
        return DX__ERROR;
    }
 
    /**  Update other windows  **/
    for (i = 0;  i < cntrl_info_block.windows;  i++)
    {
        if (i != cntrl_info_block.cur_win)
        {
            if (add_to_filer(temp_entry, errmsg, i) == DX__ERROR)
            {
                 return DX__ERROR;
            }
        }
    }
 
    return DX__NORMAL;
}
 
 

static int create_same(char *to, FILE *lzw_file, char *errmsg, unsigned short chan)
{
    static struct fibdef fib;
    $DESCRIPTOR(fib_descriptor, (char *)&fib);
 
    struct FAB to_fab;
    struct NAM to_nam;
    char expand_name[NAM$C_MAXRSS];
    unsigned long status;
    char devname[256];
    char dirname[256];
 
    char filespec[256];
    unsigned short filespec_length;
    $DESCRIPTOR (filespec_descriptor, filespec);
 
    char resultant_name[256];
    unsigned short resultant_length;
    $DESCRIPTOR (resultant_name_descriptor, resultant_name);
 
    /**  File Characteristics Bits  **/
    unsigned long fch;
 
    /**  Record attribute  **/
    struct raa_tag raa;
 
    /**  Statistics Block  **/
    struct sbkdef asb;
 
    /**  Access Control Block  **/
    struct {
	unsigned short w_size;
	unsigned short w_type;
	char *l_addr;
    } acb[] = {
	{ ATR$S_UCHAR, ATR$C_UCHAR, &fch },
	{ ATR$S_RECATTR, ATR$C_RECATTR, &raa },
	{ ATR$S_STATBLK, ATR$C_STATBLK, &asb },
	{ 0, 0, (char *)NULL },
    };
 
    struct {
	unsigned short status;
	unsigned short bytcnt;
	int filler;
    } iosb;
 
    unsigned short len;
    char *cp;
    unsigned short chan_o;
 
    unsigned short get_chan(char *);
 
    /**  Get original file name  **/
    fread (&len, sizeof (unsigned short), 1, lzw_file);
    if (len > MAXFILESPEC)
    {
	sprintf(errmsg, "Source file is not a compressed file");
	return DX__ERROR;
    }
    fread (filespec, sizeof (char), len, lzw_file);
 
    /**  Get original file characteristics  **/
    fread (&fib, sizeof (struct fibdef), 1, lzw_file);
    fread(&fch, sizeof (unsigned long), 1, lzw_file);
    fread(&raa, sizeof (struct raa_tag), 1, lzw_file);
    fread(&asb, sizeof (struct sbkdef), 1, lzw_file);
 
    /**  Initialize FAB and NAM block  **/
    to_fab = cc$rms_fab;
    to_nam = cc$rms_nam;
 
    /**  Assign value for FAB and NAM block  **/
    to_fab.fab$l_fna = to;
    to_fab.fab$b_fns = strlen(to);
    to_fab.fab$l_nam = &to_nam;
    to_nam.nam$l_esa = &expand_name;
    to_nam.nam$b_ess = NAM$C_MAXRSS;
 
    /**  Get output file characteristics  **/
    if ((status = sys$parse(&to_fab, 0, 0)) != RMS$_NORMAL) {
 
	sprintf(errmsg, "Invalid file specification");
	return DX__ERROR;
 
    }
 
    /**  Get a channel for output file  **/
    strncpy(devname, to_nam.nam$l_dev, to_nam.nam$b_dev);
    devname[to_nam.nam$b_dev] = '\0';
    strncpy(dirname, to_nam.nam$l_dir, to_nam.nam$b_dir);
    dirname[to_nam.nam$b_dir] = '\0';
    if ((chan_o = get_chan(devname)) == 0) {
 
	sprintf(errmsg, "Establish a logical link with %s failed", to);
	return DX__ERROR;
    }
 
    /**  Directory fid for the input file  **/
    __FIB(fib,fib$r_did_overlay,fib$w_did[0]) = to_nam.nam$w_did[0];
    __FIB(fib,fib$r_did_overlay,fib$w_did[1]) = to_nam.nam$w_did[1];
    __FIB(fib,fib$r_did_overlay,fib$w_did[2]) = to_nam.nam$w_did[2];
    __FIB(fib,fib$r_acctl_overlay.fib$r_acctl_bits0,fib$v_write) = 1;
 
    /**  SYS$QIO will not use device and directory name  **/
    strncpy(filespec, to_nam.nam$l_name, to_nam.nam$b_name);
    filespec[to_nam.nam$b_name] = EOS;
    strncat(filespec, to_nam.nam$l_type, to_nam.nam$b_type);
    filespec[to_nam.nam$b_name+to_nam.nam$b_type] = EOS;
    if (strchr(to, ';') == 0)
	strcat(filespec, ";0");
    else {
	strncat(filespec, to_nam.nam$l_ver, to_nam.nam$b_ver);
	filespec[to_nam.nam$b_name+to_nam.nam$b_type+to_nam.nam$b_ver] = EOS;
    }
 
    LENGTH(filespec_descriptor) = strlen(filespec);
    LENGTH(fib_descriptor) = sizeof (struct fibdef);
    status = sys$qiow (		/**  Read input file attributes  **/
		 0,
		 chan_o,
		 IO$_CREATE+IO$M_CREATE,
		 &iosb,
		 0,
		 0,
		 &fib_descriptor,
		 &filespec_descriptor,
		 &resultant_length,
		 &resultant_name_descriptor,
		 acb,
		 0);
 
    if (iosb.status != SS$_NORMAL) {	/**  No WRITE access  **/
 
	sprintf(errmsg, "Insufficient privilege for write operation");
	return DX__ERROR;
 
    }
 
    resultant_name[resultant_length] = EOS;
 
    sprintf(to, "%s%s%s", devname, dirname, resultant_name);
 
    status = sys$dassgn (chan_o);
    if (status != SS$_NORMAL) {		/**  Deassign channel failed  **/
 
	sprintf(errmsg, "Error deassigning channel");
	return DX__ERROR;
 
    }
 
    return DX__NORMAL;
}
