Ejemplo n.º 1
0
/*
 *   Given a saved state file, get the name of the image file that was
 *   loaded when the state file was created. 
 */
int CVmSaveFile::restore_get_image(osfildef *fp,
                                   char *fname_buf, size_t fname_buf_len)
{
    /* read the signature, size/checksum, and timestamp fields */
    char buf[128];
    if (osfrb(fp, buf, sizeof(VMSAVEFILE_SIG)-1 + 8 + 24))
        return VMERR_READ_FILE;

    /* check the signature */
    if (memcmp(buf, VMSAVEFILE_SIG, sizeof(VMSAVEFILE_SIG)-1) != 0)
        return VMERR_NOT_SAVED_STATE;

    /* read the length of the image file name */
    if (osfrb(fp, buf, 2))
        return VMERR_READ_FILE;

    /* get the length from the buffer */
    size_t len = osrp2(buf);

    /* if it won't fit in the buffer, return an error */
    if (len + 1 > fname_buf_len)
        return VMERR_READ_FILE;

    /* read the name into the caller's buffer */
    if (osfrb(fp, fname_buf, len))
        return VMERR_READ_FILE;

    /* null-terminate the name */
    fname_buf[len] = '\0';

    /* success */
    return 0;
}
Ejemplo n.º 2
0
/*
 *   os_exfld - load in an external function from an open file, given the
 *   size of the function (in bytes).  Returns a pointer to the newly
 *   allocated memory block containing the function in memory.  
 */
int (*os_exfld(osfildef *fp, unsigned len))(void *)
{
    void      *extfn;
    unsigned   alo;

#ifdef MSOS2
    /* for OS/2, don't load anything, but seek past the resource */
# ifdef MICROSOFT
    if (_osmode == OS2_MODE)
# endif /* MICROSOFT */
    {
        osfseek(fp, (long)len, OSFSK_SET);
        return((int (*)(void))0);
    }
#endif /* MSOS2 */

#ifdef __DPMI16__

    HANDLE selector;

    selector = GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT, len);
    if (!selector || !(extfn = GlobalLock(selector)))
        return 0;

    /* read the file */
    osfrb(fp, extfn, len);

    /* change the selector to a code segment */
    _asm
    {
        mov   bx, selector                                  /* get selector */
            lar   ax, bx                       /* get current access rights */
            mov   cl, ah
            or    cl, 8               /* set the CODE bit in the descriptor */
            mov   ax, 9                 /* function = set descriptor rights */
            mov   ch, 0
            int   31h
    }

    /* close the file and return the pointer to the function in memory */
    return((int (*)(void *))extfn);

#else /* __DPMI16 __ */

    /* figure out how much memory is needed and allocate it */
    alo = ((len + 0xf) & ~0xf) + 16;    /* round to mult of 16, plus 1 page */
    extfn = canon(malloc(alo));/* allocate the memory, canonicalize pointer */
    if (!extfn)
        return((int (*)(void *))0 );

    /* read the file */
    osfrb(fp, extfn, len);

    /* close the file and return the pointer to the function in memory */
    return((int (*)(void *))extfn);

#endif /* __DPMI16__ */
}
Ejemplo n.º 3
0
Archivo: tok.c Proyecto: BPaden/garglk
/*
 *   Read preprocessor state from a file 
 */
void tok_read_defines(tokcxdef *ctx, osfildef *fp, errcxdef *ec)
{
    int        i;
    tokdfdef **dfp;
    tokdfdef  *df;
    char       buf[4];

    /* write each element of the hash chains */
    for (i = TOKDFHSHSIZ, dfp = ctx->tokcxdf ; i ; ++dfp, --i)
    {
        /* read this hash chain */
        for (;;)
        {
            /* read the next entry's header, and stop if this is the end */
            if (osfrb(fp, buf, 4)) errsig(ec, ERR_RDGAM);
            if (osrp2(buf) == 0) break;

            /* set up a new symbol of the appropriate size */
            df = (tokdfdef *)mchalo(ec,
                                    (sizeof(tokdfdef) + osrp2(buf)
                                     + osrp2(buf+2) - 1),
                                    "tok_read_defines");
            df->explen = osrp2(buf+2);
            df->nm = df->expan + df->explen;
            df->len = osrp2(buf);

            /* read the rest of the symbol */
            if (osfrb(fp, df->nm, df->len)
                || (df->explen != 0 && osfrb(fp, df->expan, df->explen)))
                errsig(ec, ERR_RDGAM);

            /*
             *   If a symbol with this name already exists in the table,
             *   discard the new one -- the symbols defined by -D and the
             *   current set of built-in symbols takes precedence over the
             *   set loaded from the file.  
             */
            if (tok_find_define(ctx, df->nm, df->len))
            {
                /* simply discard this symbol */
                mchfre(df);
            }
            else
            {
                /* link it into this hash chain */
                df->nxt = *dfp;
                *dfp = df;
            }
        }
    }
}
Ejemplo n.º 4
0
/*
 *   Find a multimedia resource with the given name in the given file.  The
 *   file must be positioned at the start of the tads game file when we're
 *   invoked - this allows searching for a resource within a game file that
 *   is embedded in a larger file stream, since we don't care where within
 *   the osfildef stream the tads game file starts.
 *   
 *   Fills in the resource information structure with the seek offset and
 *   size of the resource in the file and returns true if the resource is
 *   found; returns false if a resource with the given name doesn't exist in
 *   the file.  
 */
int tads_find_resource_fp(osfildef *fp, const char *resname,
                          tads_resinfo *info)
{
    char buf[12];

    /* read the signature */
    if (!osfrb(fp, buf, 12))
    {
        /* seek back to the start of the header */
        osfseek(fp, -12, OSFSK_CUR);
        
        /* check which signature we have */
        if (memcmp(buf, T2_SIG, strlen(T2_SIG)) == 0)
        {
            /* it's a tads 2 game file - read it accordingly */
            return t2_find_res(fp, resname, info);
        }
        else if (memcmp(buf, T3_SIG, strlen(T3_SIG)) == 0)
        {
            /* it's a t3 image file - read it accordingly */
            return t3_find_res(fp, resname, info);
        }
    }

    /* 
     *   if we get here, it means either that we couldn't read the
     *   signature, or that we didn't recognize the signature - in either
     *   case, we can't parse the file at all, so we can't find the resource 
     */
    return FALSE;
}
Ejemplo n.º 5
0
/*
 *   Given the name of a file, determine the engine (TADS 2 or TADS 3) for
 *   which the file was compiled, based on the file's signature.  Returns
 *   one of the VM_GGT_xxx codes.  
 */
static int vm_get_game_type_for_file(const char *filename)
{
    osfildef *fp;
    char buf[16];
    int ret;
    
    /* try opening the filename exactly as given */
    fp = osfoprb(filename, OSFTBIN);

    /* if the file doesn't exist, tell the caller */
    if (fp == 0)
        return VM_GGT_NOT_FOUND;

    /* read the first few bytes of the file, where the signature resides */
    if (osfrb(fp, buf, 16))
    {
        /* 
         *   error reading the file - any valid game file is going to be at
         *   least long enough to hold the number of bytes we asked for, so
         *   it must not be a valid file 
         */
        ret = VM_GGT_INVALID;
    }
    else
    {
        /* check the signature we read against the known signatures */
        if (memcmp(buf, "TADS2 bin\012\015\032", 12) == 0)
            ret = VM_GGT_TADS2;
        else if (memcmp(buf, "T3-image\015\012\032", 11) == 0)
            ret = VM_GGT_TADS3;
        else
            ret = VM_GGT_INVALID;
    }

    /* close the file */
    osfcls(fp);

    /* return the version identifier */
    return ret;
}
Ejemplo n.º 6
0
static void copybytes(osfildef *fpin, osfildef *fpout, ulong siz)
{
    uint  cursiz;

    /* copy bytes until we run out */
    while (siz != 0)
    {
        /* we can copy up to one full buffer at a time */
        cursiz = (siz > sizeof(copybuf) ? sizeof(copybuf) : siz);

        /* deduct the amount we're copying from the total */
        siz -= cursiz;

        /* read from input, copy to output */
        if (osfrb(fpin, copybuf, cursiz)
            || osfwb(fpout, copybuf, cursiz))
        {
            /* error - close files and display an error */
            osfcls(fpin);
            osfcls(fpout);
            errexit("error copying resource", 1);
        }
    }
}
Ejemplo n.º 7
0
/*
 *   Given a saved game file, try to identify the game file that created the
 *   saved game.  
 */
static int vm_get_game_file_from_savefile(const char *savefile,
                                          char *fname, size_t fnamelen)
{
    osfildef *fp;
    char buf[128];
    int ret;
    size_t len;

    /* open the saved game file */
    fp = osfoprb(savefile, OSFTBIN);

    /* if that failed, there's no way to read the game file name */
    if (fp == 0)
        return FALSE;

    /* read the first few bytes */
    if (osfrb(fp, buf, 16))
    {
        /* 
         *   we couldn't even read that much, so it must not really be a
         *   saved game file 
         */
        ret = FALSE;
    }
    else
    {
        /* check for a saved game signature we recognize */
        if (memcmp(buf, "TADS2 save/g\012\015\032\000", 16) == 0)
        {
            /* 
             *   It's a TADS 2 saved game with embedded .GAM file
             *   information.  The filename immediately follows the signature
             *   (the 15 bytes we just matched), with a two-byte length
             *   prefix.  Seek to the length prefix and read it.  
             */
            osfseek(fp, 16, OSFSK_SET);
            osfrb(fp, buf, 2);
            len = osrp2(buf);

            /* limit the read length to our caller's available buffer */
            if (len > fnamelen - 1)
                len = fnamelen - 1;

            /* read the filename and null-terminate it */
            osfrb(fp, fname, len);
            fname[len] = '\0';

            /* success */
            ret = TRUE;
        }
        else if (memcmp(buf, "T3-state-v", 10) == 0)
        {
            /* 
             *   It's a T3 saved state file.  The image filename is always
             *   embedded in this type of file, so seek back to the start of
             *   the file and read the filename.
             *   
             *   Note that restore_get_image() returns zero on success, so we
             *   want to return true if and only if that routine returns
             *   zero.  
             */
            osfseek(fp, 0, OSFSK_SET);
            ret = (CVmSaveFile::restore_get_image(fp, fname, fnamelen) == 0);
        }
        else
        {
            /* 
             *   it's not a signature we know, so it must not be a saved
             *   state file (at least not one we can deal with)
             */
            ret = FALSE;
        }
    }

    /* we're done with the file now, so close it */
    osfcls(fp);

    /* return the result */
    return ret;
}
Ejemplo n.º 8
0
/*
 *   Parse a file 
 */
int CTadsGameInfo::parse_file(osfildef *fp, unsigned long res_seek_pos,
                              unsigned long res_size)
{
    /* find the tail of the existing list */
    tads_valinfo *last_val;
    for (last_val = first_val_ ; last_val != 0 && last_val->nxt != 0 ;
         last_val = last_val->nxt) ;
    
    /* we found the resource - seek to it in the file */
    if (osfseek(fp, res_seek_pos, OSFSK_SET))
        return FALSE;

    /* 
     *   Allocate a block of memory for loading the game information.  The
     *   game information resource is typically fairly small, so for
     *   simplicity we'll just allocate a single block of memory and load
     *   the whole resource into the block.  Allocate space for one extra
     *   byte, so that we can ensure we have a newline at the end of the
     *   buffer.  
     */
    buf_ = (char *)osmalloc(res_size + 1);
    if (buf_ == 0)
        return FALSE;

    /* read the data */
    if (osfrb(fp, buf_, res_size))
        return FALSE;

    /* 
     *   store an extra newline at the end of the buffer, so that we can be
     *   certain that the last line ends in a newline - at worst, this will
     *   add an extra blank line to the end, but since we ignore blank lines
     *   this will do no harm 
     */
    buf_[res_size++] = '\n';

    /* parse the data */
    utf8_ptr p(buf_);
    for (size_t rem = res_size ; rem != 0 ; )
    {
        /* skip any leading whitespace */
        while (rem != 0 && is_space(p.getch()))
            p.inc(&rem);

        /* if the line starts with '#', it's a comment, so skip it */
        if (rem != 0 && p.getch() == '#')
        {
            /* skip the entire line, and go back for the next one */
            skip_to_next_line(&p, &rem);
            continue;
        }

        /* we must have the start of a name - note it */
        utf8_ptr name_start = p;

        /* skip ahead to a space or colon */
        while (rem != 0 && p.getch() != ':' && !is_hspace(p.getch()))
            p.inc(&rem);

        /* note the length of the name */
        size_t name_len = p.getptr() - name_start.getptr();

        /* skip any whitespace before the presumed colon */
        while (rem != 0 && is_hspace(p.getch()))
            p.inc(&rem);

        /* if we're not at a colon, the line is ill-formed, so skip it */
        if (rem == 0 || p.getch() != ':')
        {
            /* skip the entire line, and go back for the next one */
            skip_to_next_line(&p, &rem);
            continue;
        }

        /* skip the colon and any whitespace immediately after it */
        for (p.inc(&rem) ; rem != 0 && is_hspace(p.getch()) ; p.inc(&rem)) ;

        /* 
         *   Whatever terminated the name, replace it with a null character
         *   - this is safe, since we at least have a colon character to
         *   replace, and we've already skipped it so we can overwrite it
         *   now.  A null character in utf-8 is simply a single zero byte,
         *   so we can store our byte directly without worrying about any
         *   utf-8 multi-byte strangeness.  
         */
        *(name_start.getptr() + name_len) = '\0';

        /* note where the value starts */
        utf8_ptr val_start = p;

        /* set up to write to the buffer at the current point */
        utf8_ptr dst = p;

        /*
         *   Now find the end of the value.  The value can span multiple
         *   lines; if we find a newline followed by a space, it means that
         *   the next line is a continuation of the current value, and that
         *   the entire sequence of newlines and immediately following
         *   whitespace should be converted to a single space in the value.
         *   
         *   Note that we copy the transformed value directly over the old
         *   version of the value in the buffer.  This is safe because the
         *   transformation can only remove characters - we merely collapse
         *   each newline-whitespace sequence into a single space.  
         */
        while (rem != 0)
        {
            /* get this character */
            wchar_t ch = p.getch();
            
            /* check for a newline */
            if (is_vspace(ch))
            {
                /* 
                 *   it's a newline - skip it (and any other characters in
                 *   the newline sequence) 
                 */
                skip_newline(&p, &rem);

                /* 
                 *   if there's no leading whitespace on the next line,
                 *   we've reached the end of this value
                 */
                if (rem == 0 || !is_hspace(p.getch()))
                {
                    /* 
                     *   no whitespace -> end of the value - stop scanning
                     *   the value 
                     */
                    break;
                }

                /* skip leading whitespace on the line */
                while (rem != 0 && is_hspace(p.getch()))
                    p.inc(&rem);

                /* 
                 *   add a single whitespace character to the output for the
                 *   entire sequence of the newline plus the leading
                 *   whitespace on the line 
                 */
                dst.setch(' ');
            }
            else if (ch == 0)
            {
                /* change null bytes to spaces */
                dst.setch(' ');

                /* skip this character */
                p.inc(&rem);
            }
            else
            {
                /* it's not a newline - simply copy it out and keep going */
                dst.setch(ch);

                /* skip this character */
                p.inc(&rem);
            }
        }

        /* 
         *   Store a null terminator at the end of the value (it's safe to
         *   write this to the buffer because at worst it'll overwrite the
         *   newline at the end of the last line, which we've already
         *   skipped in the source).  Note that we obtain the length of the
         *   value string before storing the null terminator, because we
         *   don't want to count the null byte in the value's length.  
         */
        dst.setch('\0');

        /* 
         *   Create a new value list entry.  Point the entry directly into
         *   our buffer, since we're keeping the buffer around as long as
         *   the value list is around. 
         */
        tads_valinfo *val_info =
            (tads_valinfo *)osmalloc(sizeof(tads_valinfo));
        val_info->name = name_start.getptr();
        val_info->name_len = name_len;
        val_info->val = store_value(val_start.getptr(),
                                    dst.getptr() - val_start.getptr());
        val_info->nxt = 0;

        /* link the new value at the end of our list */
        if (last_val != 0)
            last_val->nxt = val_info;
        else
            first_val_ = val_info;
        last_val = val_info;
    }

    /* success */
    return TRUE;
}
Ejemplo n.º 9
0
int TADS2::cmap_load_internal(const char *filename) {
	osfildef *fp;
	static char sig1[] = CMAP_SIG_S100;
	char buf[256];
	uchar lenbuf[2];
	size_t len;
	int sysblk;

	// if there's no mapping file, use the default mapping
	if (filename == 0) {
		// initialize with the default mapping
		cmap_init_default();

		// return success
		return 0;
	}

	// open the file
	fp = osfoprb(filename, OSFTCMAP);
	if (fp == 0)
		return 1;

	// check the signature
	if (osfrb(fp, buf, sizeof(sig1))
		|| memcmp(buf, sig1, sizeof(sig1)) != 0) {
		osfcls(fp);
		return 2;
	}

	// load the ID
	G_cmap_id[4] = '\0';
	if (osfrb(fp, G_cmap_id, 4)) {
		osfcls(fp);
		return 3;
	}

	// load the long description
	if (osfrb(fp, lenbuf, 2)
		|| (len = osrp2(lenbuf)) > sizeof(G_cmap_ldesc)
		|| osfrb(fp, G_cmap_ldesc, len)) {
		osfcls(fp);
		return 4;
	}

	// load the two tables - input, then output
	if (osfrb(fp, G_cmap_input, sizeof(G_cmap_input))
		|| osfrb(fp, G_cmap_output, sizeof(G_cmap_output))) {
		osfcls(fp);
		return 5;
	}

	// read the next section header
	if (osfrb(fp, buf, 4)) {
		osfcls(fp);
		return 6;
	}

	// if it's "SYSI", read the system information string
	if (!memcmp(buf, "SYSI", 4)) {
		// read the length prefix, then the string
		if (osfrb(fp, lenbuf, 2)
			|| (len = osrp2(lenbuf)) > sizeof(buf)
			|| osfrb(fp, buf, len)) {
			osfcls(fp);
			return 7;
		}

		// we have a system information block
		sysblk = true;
	} else {
		// there's no system information block
		sysblk = false;
	}

	/*
	 * call the OS code, so that it can do any system-dependent
	 * initialization for the new character mapping
	 */
	os_advise_load_charmap(G_cmap_id, G_cmap_ldesc, sysblk ? buf : "");

	// read the next section header
	if (sysblk && osfrb(fp, buf, 4)) {
		osfcls(fp);
		return 8;
	}

	// see if we have an entity list
	if (!memcmp(buf, "ENTY", 4)) {
		// read the entities
		for (;;) {
			unsigned int cval;
			char expansion[CMAP_MAX_ENTITY_EXPANSION];

			// read the next item's length and character value
			if (osfrb(fp, buf, 4)) {
				osfcls(fp);
				return 9;
			}

			// decode the values
			len = osrp2(buf);
			cval = osrp2(buf+2);

			// if we've reached the zero marker, we're done
			if (len == 0 && cval == 0)
				break;

			// read the string
			if (len > CMAP_MAX_ENTITY_EXPANSION
				|| osfrb(fp, expansion, len)) {
				osfcls(fp);
				return 10;
			}

			// tell the output code about the expansion
			tio_set_html_expansion(cval, expansion, len);
		}
	}

	/*
	 * ignore anything else we find - if the file format is updated to
	 * include extra information in the future, and this old code tries
	 * to load an updated file, we'll just ignore the new information,
	 * which should always be placed after the "SYSI" block (if present)
	 * to ensure compatibility with past versions (such as this code)
	 */
	// no problems - close the file and return success
	osfcls(fp);
	return 0;
}
Ejemplo n.º 10
0
/*
 *   Find a resource in a tads 2 game file 
 */
static int t2_find_res(osfildef *fp, const char *resname,
                       tads_resinfo *info)
{
    char buf[300];
    unsigned long startpos;
    size_t resname_len;
    int found;

    /* we haven't found what we're looking for yet */
    found = FALSE;

    /* note the length of the name we're seeking */
    resname_len = strlen(resname);

    /* 
     *   note the seek location of the start of the tads 2 game file stream
     *   within the file - if the game file is embedded in a larger file
     *   stream, the seek locations we find within the file are relative to
     *   this starting location 
     */
    startpos = osfpos(fp);

    /* 
     *   skip past the tads 2 file header (13 bytes for the signature, 7
     *   bytes for the version header, 2 bytes for the flags, 26 bytes for
     *   the timestamp) 
     */
    osfseek(fp, 13 + 7 + 2 + 26, OSFSK_CUR);

    /* 
     *   scan the sections in the file; stop on $EOF, and skip everything
     *   else but HTMLRES, which is the section type that 
     */
    for (;;)
    {
        unsigned long endofs;
        
        /* read the section type and next-section pointer */
        if (osfrb(fp, buf, 1)
            || osfrb(fp, buf + 1, (int)((unsigned char)buf[0] + 4)))
        {
            /* failed to read it - give up */
            return FALSE;
        }

        /* note the ending position of this section */
        endofs = t3rp4u(buf + 1 + (unsigned char)buf[0]);

        /* check the type */
        if (buf[0] == 7 && memcmp(buf+1, "HTMLRES", 7) == 0)
        {
            unsigned long entry_cnt;
            unsigned long i;
            
            /* 
             *   It's a multimedia resource block.  Read the index table
             *   header (which contains the number of entries and a reserved
             *   uint32).  
             */
            if (osfrb(fp, buf, 8))
                return FALSE;

            /* get the number of entries from the header */
            entry_cnt = t3rp4u(buf);

            /* read the entries */
            for (i = 0 ; i < entry_cnt ; ++i)
            {
                unsigned long res_ofs;
                unsigned long res_siz;
                unsigned short name_len;

                /* read the entry header */
                if (osfrb(fp, buf, 10))
                    return FALSE;

                /* parse the header */
                res_ofs = t3rp4u(buf);
                res_siz = t3rp4u(buf + 4);
                name_len = osrp2(buf + 8);

                /* read the entry's name */
                if (name_len > sizeof(buf) || osfrb(fp, buf, name_len))
                    return FALSE;

                /* 
                 *   if it matches the name we're looking for, note that we
                 *   found it 
                 */
                if (name_len == resname_len
                    && memicmp(resname, buf, name_len) == 0)
                {
                    /* 
                     *   note that we found it, and note its resource size
                     *   and offset in the return structure - but keep
                     *   scanning the rest of the directory, since we need
                     *   to know where the directory ends to know where the
                     *   actual resources begin 
                     */
                    found = TRUE;
                    info->seek_pos = res_ofs;
                    info->siz = res_siz;
                }
            }

            /* 
             *   if we found our resource, the current seek position is the
             *   base of the offset we found in the directory; so fix up the
             *   offset to give the actual file location 
             */
            if (found)
            {
                /* fix up the offset with the actual file location */
                info->seek_pos += osfpos(fp);

                /* tell the caller we found it */
                return TRUE;
            }

            /* we didn't find it - seek to the end of this section */
            osfseek(fp, endofs + startpos, OSFSK_SET);
        }
        else if (buf[0] == 4 && memcmp(buf+1, "$EOF", 4) == 0)
        {
            /* 
             *   that's the end of the file - we've finished without finding
             *   the resource, so return failure 
             */
            return FALSE;
        }
        else
        {
            /* 
             *   this isn't a section we're interested in - skip to the end
             *   of the section and keep going
             */
            osfseek(fp, endofs + startpos, OSFSK_SET);
        }
    }
}
Ejemplo n.º 11
0
int main(int argc, char **argv)
{
    osfildef *fp;
    const char *fname;
    const char *resname;
    tads_resinfo res_info;
    unsigned long rem;
    
    /* check usage */
    if (argc != 3)
    {
        fprintf(stderr, "usage: resfind <filename> <resname>\n");
        exit(2);
    }

    /* get the arguments */
    fname = argv[1];
    resname = argv[2];

    /* open the file */
    if ((fp = osfoprb(fname, OSFTGAME)) == 0
        && (fp = osfoprb(fname, OSFTT3IMG)) == 0)
    {
        fprintf(stderr, "unable to open file \"%s\"\n", fname);
        exit(2);
    }

    /* find the resource */
    if (!tads_find_resource_fp(fp, resname, &res_info))
    {
        fprintf(stderr, "unable to find resource \"%s\"\n", resname);
        osfcls(fp);
        exit(1);
    }

    /* seek to the resource */
    osfseek(fp, res_info.seek_pos, OSFSK_SET);

    /* copy the resource to standard output */
    for (rem = res_info.siz ; rem != 0 ; )
    {
        char buf[1024];
        size_t cur;

        /* 
         *   read up to the buffer size or up to the resource size
         *   remaining, whichever is smaller 
         */
        cur = sizeof(buf);
        if (cur > rem)
            cur = (size_t)rem;

        /* read the chunk */
        if (osfrb(fp, buf, cur))
        {
            fprintf(stderr, "error reading %u bytes from file\n",
                    (unsigned)cur);
            osfcls(fp);
            exit(2);
        }

        /* copy the chunk to standard output */
        fwrite(buf, cur, 1, stdout);

        /* deduct the amount we just read from the size remaining */
        rem -= cur;
    }

    /* done with the file - close it */
    osfcls(fp);

    /* success */
    exit(0);
    return 0;
}
Ejemplo n.º 12
0
/*
 *   Find a resource in a T3 image file
 */
static int t3_find_res(osfildef *fp, const char *resname,
                       tads_resinfo *info)
{
    char buf[256];
    size_t resname_len;
    
    /* note the length of the name we're seeking */
    resname_len = strlen(resname);

    /* 
     *   skip the file header - 11 bytes for the signature, 2 bytes for the
     *   format version, 32 reserved bytes, and 24 bytes for the timestamp 
     */
    osfseek(fp, 11 + 2 + 32 + 24, OSFSK_CUR);

    /* scan the data blocks */
    for (;;)
    {
        unsigned long siz;
        
        /* read the block header */
        if (osfrb(fp, buf, 10))
            return FALSE;

        /* get the block size */
        siz = t3rp4u(buf + 4);

        /* check the type */
        if (memcmp(buf, "MRES", 4) == 0)
        {
            unsigned long base_ofs;
            unsigned int entry_cnt;
            unsigned int i;

            /* 
             *   remember the current seek position - the data seek location
             *   for each index entry is given as an offset from this
             *   location 
             */
            base_ofs = osfpos(fp);

            /* read the number of entries */
            if (osfrb(fp, buf, 2))
                return FALSE;

            /* parse the entry count */
            entry_cnt = osrp2(buf);

            /* read the entries */
            for (i = 0 ; i < entry_cnt ; ++i)
            {
                unsigned long entry_ofs;
                unsigned long entry_siz;
                unsigned int entry_name_len;
                char *p;
                size_t rem;

                /* read this index entry's header */
                if (osfrb(fp, buf, 9))
                    return FALSE;

                /* parse the header */
                entry_ofs = t3rp4u(buf);
                entry_siz = t3rp4u(buf + 4);
                entry_name_len = (unsigned char)buf[8];

                /* read the entry's name */
                if (osfrb(fp, buf, entry_name_len))
                    return FALSE;

                /* XOR the bytes of the name with 0xFF */
                for (p = buf, rem = entry_name_len ; rem != 0 ; ++p, --rem)
                    *p ^= 0xFF;

                /* if this is the one we're looking for, return it */
                if (entry_name_len == resname_len
                    && memicmp(resname, buf, resname_len) == 0)
                {
                    /* 
                     *   fill in the return information - note that the
                     *   entry offset given in the header is an offset from
                     *   data block's starting location, so fix this up to
                     *   an absolute seek location for the return value
                     */
                    info->seek_pos = base_ofs + entry_ofs;
                    info->siz = entry_siz;

                    /* return success */
                    return TRUE;
                }
            }
        }
        else if (memcmp(buf, "EOF ", 4) == 0)
        {
            /* 
             *   end of file - we've finished without finding the resource,
             *   so return failure 
             */
            return FALSE;
        }
        else
        {
            /* 
             *   we don't care about anything else - just skip this block
             *   and keep going; to skip the block, simply seek ahead by the
             *   size of the block's contents as given in the block header 
             */
            osfseek(fp, siz, OSFSK_CUR);
        }
    }
}
Ejemplo n.º 13
0
/* write game to binary file */
static void fiowrt1(mcmcxdef *mctx, voccxdef *vctx, tokcxdef *tokctx,
                    tokthdef *tab, uchar *fmts, uint fmtl, osfildef *fp,
                    uint flags, objnum preinit, int extc, uint prpcnt,
                    char *filever)
{
    int         i;
    int         j;
    int         k;
    uchar       buf[TOKNAMMAX + 50];
    errcxdef   *ec = vctx->voccxerr;
    ulong       fpos;
    int         obj;
    vocidef  ***vpg;
    vocidef   **v;
    objnum     *sc;
    vocdef     *voc;
    vocwdef    *vw;
    vocdef    **vhsh;
    struct tm  *tblock;
    time_t      timer;
    fiowcxdef   cbctx;                    /* callback context for toktheach */
    uint        xor_seed = 63;
    uint        xor_inc = 64;
    char       *vsnhdr;
    uint        vsnlen;
    char        fastnamebuf[OSFNMAX];    /* fast-load record temp file name */
    long        flag_seek;

    /* generate appropriate file version */
    switch(filever[0])
    {
    case 'a':          /* generate .GAM compatible with pre-2.0.15 runtimes */
        vsnhdr = FIOVSNHDR2;
        vsnlen = sizeof(FIOVSNHDR2);
        xor_seed = 17;                                /* use old xor values */
        xor_inc = 29;
        break;

    case 'b':                                    /* generate 2.0.15+ format */
        vsnhdr = FIOVSNHDR3;
        vsnlen = sizeof(FIOVSNHDR3);
        break;

    case 'c':
    case '*':                                            /* current version */
        vsnhdr = FIOVSNHDR;
        vsnlen = sizeof(FIOVSNHDR);
        break;

    default:
        errsig(ec, ERR_WRTVSN);
    }

    /* write file header and version header */
    if (osfwb(fp, FIOFILHDR, sizeof(FIOFILHDR))
          || osfwb(fp, vsnhdr, vsnlen))
        errsig(ec, ERR_WRTGAM);

    /* 
     *   write the flags - remember where we wrote it in case we need to
     *   change the flags later 
     */
    flag_seek = osfpos(fp);
    oswp2(buf, flags);
    if (osfwb(fp, buf, 2))
        errsig(ec, ERR_WRTGAM);

    /* write the timestamp */
    timer = time(NULL);
    tblock = localtime(&timer);
    strcpy(vctx->voccxtim, asctime(tblock));
    if (osfwb(fp, vctx->voccxtim, (size_t)26))
        errsig(ec, ERR_WRTGAM);

    /* write xor parameters if generating post 2.0.15 .GAM file */
    if (filever[0] != 'a')
    {
        fpos = fiowhd(fp, ec, "\003XSI");
        buf[0] = xor_seed;
        buf[1] = xor_inc;
        if (osfwb(fp, buf, 2)) errsig(ec, ERR_WRTGAM);
        fiowcls(fp, ec, fpos);
    }
    
    /* write count of external functions */
    if (extc)
    {
        fpos = fiowhd(fp, ec, "\006EXTCNT");
        oswp2(buf, extc);              /* write the external function count */
        if (osfwb(fp, buf, 2)) errsig(ec, ERR_WRTGAM);

        /* write XFCN-seek-location header if post 2.0.15 file version */
        if (filever[0] != 'a')
        {
            oswp4(buf, 0);      /* placeholder - TADSRSC sets this up later */
            if (osfwb(fp, buf, 4)) errsig(ec, ERR_WRTGAM);
        }

        /* close the resource */
        fiowcls(fp, ec, fpos);
    }
    
    /* 
     *   write the character set information, if a character set was
     *   specified 
     */
    if (G_cmap_id[0] != '\0')
    {
        size_t len;

        /* this is not allowed with explicit file versions a, b, or c */
        if (filever[0] == 'a' || filever[0] == 'b' || filever[0] == 'c')
            errsig(ec, ERR_VNOCTAB);

        /* write out the CHRSET resource header */
        fpos = fiowhd(fp, ec, "\006CHRSET");

        /* write out the ID and LDESC of the internal character set */
        len = strlen(G_cmap_ldesc) + 1;
        oswp2(buf, len);
        if (osfwb(fp, G_cmap_id, 4)
            || osfwb(fp, buf, 2)
            || osfwb(fp, G_cmap_ldesc, len))
            errsig(ec, ERR_WRTGAM);

        /* close the resource */
        fiowcls(fp, ec, fpos);
    }

    /* write OBJ resource header */
    fpos = fiowhd(fp, ec, "\003OBJ");

    /* set up the symbol table callback context for writing the objects */
    cbctx.fiowcxmem = mctx;
    cbctx.fiowcxerr = ec;
    cbctx.fiowcxfp  = fp;
    cbctx.fiowcxund = 0;
    cbctx.fiowcxseed = xor_seed;
    cbctx.fiowcxinc = xor_inc;
    cbctx.fiowcxdebug = (flags & FIOFSYM);
    if (flags & FIOFFAST)
    {
        /* try creating the temp file */
        cbctx.fiowcxffp = os_create_tempfile(0, fastnamebuf);

        /* if that failed, we don't have a fast-load table after all */
        if (cbctx.fiowcxffp == 0)
        {
            long curpos;
            char flag_buf[2];
            
            /* clear the fast-load flag */
            flags &= ~FIOFFAST;

            /* 
             *   go back to the flags we wrote to the .gam file header, and
             *   re-write the new flags without the fast-load bit - since
             *   we're not going to write a fast-load table, we don't want
             *   readers thinking they're going to find one 
             */

            /* first, remember where we are right now */
            curpos = osfpos(fp);

            /* seek back to the flags and re-write the new flags */
            osfseek(fp, flag_seek, OSFSK_SET);
            oswp2(flag_buf, flags);
            if (osfwb(fp, flag_buf, 2))
                errsig(ec, ERR_WRTGAM);

            /* seek back to where we started */
            osfseek(fp, curpos, OSFSK_SET);
        }
    }
    else
        cbctx.fiowcxffp = (osfildef *)0;
    cbctx.fiowcxflg = flags;

    /* go through symbol table, and write each object */
    toktheach((toktdef *)tab, fiowrtobj, &cbctx);

    /* also write all objects created with 'new' */
    for (vpg = vctx->voccxinh, i = 0 ; i < VOCINHMAX ; ++vpg, ++i)
    {
        objnum obj;

        if (!*vpg) continue;
        for (v = *vpg, obj = (i << 8), j = 0 ; j < 256 ; ++v, ++obj, ++j)
        {
            /* if the object was dynamically allocated, write it out */
            if (*v && (*v)->vociflg & VOCIFNEW)
            {
                toksdef t;

                /* clear the 'new' flag, as this is a static object now */
                (*v)->vociflg &= ~VOCIFNEW;

                /* set up a toksdef, and write it out */
                t.tokstyp = TOKSTOBJ;
                t.toksval = obj;
                fiowrtobj(&cbctx, &t);
            }
        }
    }
                    
    /* close the resource */
    fiowcls(fp, ec, fpos);
    
    /* copy fast-load records to output file if applicable */
    if (cbctx.fiowcxffp)
    {
        osfildef *fp2 = cbctx.fiowcxffp;
        char      copybuf[1024];
        ulong     len;
        ulong     curlen;
        
        /* start with resource header for fast-load records */
        fpos = fiowhd(fp, ec, "\003FST");

        /* get length of temp file, then rewind it */
        len = osfpos(fp2);
        osfseek(fp2, 0L, OSFSK_SET);

        /* copy the whole thing to the output file */
        while (len)
        {
            curlen = (len > sizeof(copybuf) ? sizeof(copybuf) : len);
            if (osfrb(fp2, copybuf, (size_t)curlen)
                || osfwb(fp, copybuf, (size_t)curlen))
                errsig(ec, ERR_WRTGAM);
            len -= curlen;
        }

        /* close the fast-load resource */
        fiowcls(fp, ec, fpos);
        
        /* close and delete temp file */
        osfcls(fp2);
        osfdel_temp(fastnamebuf);
    }
    
    /* write vocabulary inheritance records - start with header */
    fpos = fiowhd(fp, ec, "\003INH");
    
    /* go through inheritance records and write to file */
    for (vpg = vctx->voccxinh, i = 0 ; i < VOCINHMAX ; ++vpg, ++i)
    {
        if (!*vpg) continue;
        for (v = *vpg, obj = (i << 8), j = 0 ; j < 256 ; ++v, ++obj, ++j)
        {
            if (*v)
            {
                buf[0] = (*v)->vociflg;
                oswp2(buf + 1, obj);
                oswp2(buf + 3, (*v)->vociloc);
                oswp2(buf + 5, (*v)->vociilc);
                oswp2(buf + 7, (*v)->vocinsc);
                for (k = 0, sc = (*v)->vocisc ; k < (*v)->vocinsc ; ++sc, ++k)
                {
                    if (k + 9 >= sizeof(buf)) errsig(ec, ERR_FIOMSC);
                    oswp2(buf + 9 + (k << 1), (*sc));
                }
                if (osfwb(fp, buf, 9 + (2 * (*v)->vocinsc)))
                    errsig(ec, ERR_WRTGAM);
            }
        }
    }
    
    /* close resource */
    fiowcls(fp, ec, fpos);
    
    /* write format strings */
    if (fmtl)
    {
        fpos = fiowhd(fp, ec, "\006FMTSTR");
        oswp2(buf, fmtl);
        if (flags & FIOFCRYPT) fioxor(fmts, fmtl, xor_seed, xor_inc);
        if (osfwb(fp, buf, 2) || osfwb(fp, fmts, fmtl))
            errsig(ec, ERR_WRTGAM);
        fiowcls(fp, ec, fpos);
    }
    
    /* write preinit if preinit object was specified */
    if (flags & FIOFPRE)
    {
        fpos = fiowhd(fp, ec, "\007PREINIT");
        oswp2(buf, preinit);
        if (osfwb(fp, buf, 2)) errsig(ec, ERR_WRTGAM);
        fiowcls(fp, ec, fpos);
    }
    
    /* write required objects out of voccxdef */
    fpos = fiowhd(fp, ec, "\003REQ");
    fiowrq(ec, fp, vctx->voccxme);
    fiowrq(ec, fp, vctx->voccxvtk);
    fiowrq(ec, fp, vctx->voccxstr);
    fiowrq(ec, fp, vctx->voccxnum);
    fiowrq(ec, fp, vctx->voccxprd);
    fiowrq(ec, fp, vctx->voccxvag);
    fiowrq(ec, fp, vctx->voccxini);
    fiowrq(ec, fp, vctx->voccxpre);
    fiowrq(ec, fp, vctx->voccxper);
    fiowrq(ec, fp, vctx->voccxprom);
    fiowrq(ec, fp, vctx->voccxpdis);
    fiowrq(ec, fp, vctx->voccxper2);
    fiowrq(ec, fp, vctx->voccxpdef);
    fiowrq(ec, fp, vctx->voccxpask);
    fiowrq(ec, fp, vctx->voccxppc);
    fiowrq(ec, fp, vctx->voccxpask2);
    fiowrq(ec, fp, vctx->voccxperp);
    fiowrq(ec, fp, vctx->voccxpostprom);
    fiowrq(ec, fp, vctx->voccxinitrestore);
    fiowrq(ec, fp, vctx->voccxpuv);
    fiowrq(ec, fp, vctx->voccxpnp);
    fiowrq(ec, fp, vctx->voccxpostact);
    fiowrq(ec, fp, vctx->voccxendcmd);
    fiowrq(ec, fp, vctx->voccxprecmd);
    fiowrq(ec, fp, vctx->voccxpask3);
    fiowrq(ec, fp, vctx->voccxpre2);
    fiowrq(ec, fp, vctx->voccxpdef2);
    fiowcls(fp, ec, fpos);
    
    /* write compound words */
    if (vctx->voccxcpl)
    {
        fpos = fiowhd(fp, ec, "\004CMPD");
        oswp2(buf, vctx->voccxcpl);
        if (flags & FIOFCRYPT)
            fioxor((uchar *)vctx->voccxcpp, (uint)vctx->voccxcpl,
                   xor_seed, xor_inc);
        if (osfwb(fp, buf, 2)
            || osfwb(fp, vctx->voccxcpp, (uint)vctx->voccxcpl))
            errsig(ec, ERR_WRTGAM);
        fiowcls(fp, ec, fpos);
    }
    
    /* write special words */
    if (vctx->voccxspl)
    {
        fpos = fiowhd(fp, ec, "\010SPECWORD");
        oswp2(buf, vctx->voccxspl);
        if (flags & FIOFCRYPT)
            fioxor((uchar *)vctx->voccxspp, (uint)vctx->voccxspl,
                   xor_seed, xor_inc);
        if (osfwb(fp, buf, 2)
            || osfwb(fp, vctx->voccxspp, (uint)vctx->voccxspl))
            errsig(ec, ERR_WRTGAM);
        fiowcls(fp, ec, fpos);
    }
    
    /* write vocabulary */
    fpos = fiowhd(fp, ec, "\003VOC");

    /* go through each hash chain */
    for (i = 0, vhsh = vctx->voccxhsh ; i < VOCHASHSIZ ; ++i, ++vhsh)
    {
        /* go through each word in this hash chain */
        for (voc = *vhsh ; voc ; voc = voc->vocnxt)
        {
            /* encrypt the word if desired */
            if (flags & FIOFCRYPT)
                fioxor(voc->voctxt, (uint)(voc->voclen + voc->vocln2),
                       xor_seed, xor_inc);

            /* go through each object relation attached to the word */
            for (vw = vocwget(vctx, voc->vocwlst) ; vw ;
                 vw = vocwget(vctx, vw->vocwnxt))
            {
                /* clear the 'new' flag, as this is a static object now */
                vw->vocwflg &= ~VOCFNEW;

                /* write out this object relation */
                oswp2(buf, voc->voclen);
                oswp2(buf+2, voc->vocln2);
                oswp2(buf+4, vw->vocwtyp);
                oswp2(buf+6, vw->vocwobj);
                oswp2(buf+8, vw->vocwflg);
                if (osfwb(fp, buf, 10)
                    || osfwb(fp, voc->voctxt, voc->voclen + voc->vocln2))
                    errsig(ec, ERR_WRTGAM);
            }
        }
    }
    fiowcls(fp, ec, fpos);
    
    /* write the symbol table, if desired */
    if (flags & FIOFSYM)
    {
        fpos = fiowhd(fp, ec, "\006SYMTAB");
        toktheach((toktdef *)tab, fiowrtsym, &cbctx);

        /* indicate last symbol with a length of zero */
        buf[0] = 0;
        if (osfwb(fp, buf, 4)) errsig(ec, ERR_WRTGAM);
        fiowcls(fp, ec, fpos);
    }
    
    /* write line source chain, if desired */
    if ((flags & (FIOFLIN | FIOFLIN2)) != 0 && vctx->voccxrun->runcxdbg != 0)
    {
        lindef *lin;

        /* write the SRC header */
        fpos = fiowhd(fp, ec, "\003SRC");

        /* write the line records */
        for (lin = vctx->voccxrun->runcxdbg->dbgcxlin ; lin ;
             lin = lin->linnxt)
        {
            /* write this record */
            if (linwrt(lin, fp))
                errsig(ec, ERR_WRTGAM);
        }

        /* done with this section */
        fiowcls(fp, ec, fpos);

        /* 
         *   if we have new-style line records, put a SRC2 header (with no
         *   block contents) in the file, so that the debugger realizes
         *   that it has new-style line records (with line numbers rather
         *   than seek offsets) 
         */
        if ((flags & FIOFLIN2) != 0)
        {
            fpos = fiowhd(fp, ec, "\004SRC2");
            fiowcls(fp, ec, fpos);
        }
    }

    /* if writing a precompiled header, write some more information */
    if (flags & FIOFBIN)
    {
        /* write property count */
        fpos = fiowhd(fp, ec, "\006PRPCNT");
        oswp2(buf, prpcnt);
        if (osfwb(fp, buf, 2)) errsig(ec, ERR_WRTGAM);
        fiowcls(fp, ec, fpos);

        /* write preprocessor symbol table */
        fpos = fiowhd(fp, ec, "\006TADSPP");
        tok_write_defines(tokctx, fp, ec);
        fiowcls(fp, ec, fpos);
    }

    /* write end-of-file resource header */
    (void)fiowhd(fp, ec, "\004$EOF");
    osfcls(fp);
    
    /* if there are undefined functions/objects, signal an error */
    if (cbctx.fiowcxund) errsig(ec, ERR_UNDEF);
}
Ejemplo n.º 14
0
/* process changes to resource file (or just list it) */
static opdef *rscproc(osfildef *fp, osfildef *fpout, opdef *oplist)
{
    char   buf[128];
    ulong  siz;
    char   datebuf[27];
    ulong  endpos;
    uchar  nambuf[40];
    uint   rsiz;
    opdef *op;
    int    copyrsc;
    ulong  startpos;
    uint   endpos_ofs;
    ulong  first_xfcn = 0;
    ulong  extcnt_pos = 0;
    int    found_user_rsc = FALSE;
    int    showed_heading = FALSE;
    int    found_htmlres = FALSE;
    char  *file_type;

    /* 
     *   if we're reading an existing file, check it header; otherwise,
     *   write out a brand new file header 
     */
    if (fp != 0)
    {
        /* 
         *   the input file exists -- check file and version headers, and
         *   get flags and timestamp 
         */
        if (osfrb(fp, buf, (int)(sizeof(FIOFILHDR) + sizeof(FIOVSNHDR) + 2)))
            listexit(fp, "error reading file header");

        /* check the file type */
        if (memcmp(buf, FIOFILHDR, sizeof(FIOFILHDR)) == 0)
            file_type = "game";
        else if (memcmp(buf, FIOFILHDRRSC, sizeof(FIOFILHDRRSC)) == 0)
            file_type = "resource";
        else
            listexit(fp, "invalid resource file header");

        /* check the version header */
        if (memcmp(buf + sizeof(FIOFILHDR), FIOVSNHDR, sizeof(FIOVSNHDR))
            && memcmp(buf + sizeof(FIOFILHDR), FIOVSNHDR2, sizeof(FIOVSNHDR2))
            && memcmp(buf + sizeof(FIOFILHDR), FIOVSNHDR3, sizeof(FIOVSNHDR3)))
            listexit(fp, "incompatible resource file version");

        /* get the timestamp */
        if (osfrb(fp, datebuf, (size_t)26))
            listexit(fp, "error reading file");
        datebuf[26] = '\0';
    }
    else
    {
        struct tm  *tblock;
        time_t      timer;

        /* construct a new file header */
        memcpy(buf, FIOFILHDRRSC, sizeof(FIOFILHDRRSC));
        memcpy(buf + sizeof(FIOFILHDR), FIOVSNHDR, sizeof(FIOVSNHDR));

        /* clear the flags */
        oswp2(buf + sizeof(FIOFILHDR) + sizeof(FIOVSNHDR), 0);

        /* construct the timestamp */
        timer = time(0);
        tblock = localtime(&timer);
        strcpy(datebuf, asctime(tblock));
    }
        
    if (fpout)
    {
        if (osfwb(fpout, buf,
                  (int)(sizeof(FIOFILHDR) + sizeof(FIOVSNHDR) + 2))
            || osfwb(fpout, datebuf, (size_t)26))
            listexit(fp, "error writing header");
    }

    /* if listing, show file creation timestamp */
    if (fpout == 0)
        rscptf("\n"
               "File type:     TADS %s file\n"
               "Date compiled: %s\n", file_type, datebuf);

    /*
     *   Process the input file, if there is one 
     */
    for ( ; fp != 0 ; )
    {
        /* assume this resource will be copied to the output */
        copyrsc = TRUE;

        startpos = osfpos(fp);
        if (osfrb(fp, buf, 1)
            || osfrb(fp, buf + 1, (int)(buf[0] + 4)))
            listexit(fp, "error reading file");

        memcpy(nambuf, buf + 1, (size_t)buf[0]);
        nambuf[buf[0]] = '\0';
        
        endpos_ofs = 1 + buf[0];
        endpos = osrp4(buf + endpos_ofs);
        siz = endpos - startpos;
        
        /* see what kind of resource we have, and do the right thing */
        if (!strcmp((char *)nambuf, "$EOF"))
        {
            /* end of file marker - quit here */
            break;
        }
        else if (!strcmp((char *)nambuf, "HTMLRES"))
        {
            /* if we've already found an HTMLRES list, it's an error */
            if (found_htmlres)
            {
                rscptf("error: multiple HTMLRES maps found in file\n"
                       " -- redundant entries have been deleted.\n");
                copyrsc = FALSE;
            }
            else
            {
                /* go process it */
                oplist = prochtmlres(fp, fpout, oplist, &copyrsc,
                                     &showed_heading, TRUE);
            }

            /* note that we've found a resource */
            found_user_rsc = TRUE;
            found_htmlres = TRUE;
        }
        else if (!strcmp((char *)nambuf, "EXTCNT"))
        {
            /* place to write start of XFCN's? */
            if (siz >= 17 && fpout)
                extcnt_pos = osfpos(fpout);
        }
        else if (!strcmp((char *)nambuf, "XFCN"))
        {
            if (osfrb(fp, buf, 3) || osfrb(fp, buf + 3, (int)buf[2]))
                listexit(fp, "error reading file");
            rsiz = osrp2(buf);
            buf[3 + buf[2]] = '\0';

            if (fpout)
            {
                /* see if this resource is in the list */
                for (op = oplist ; op ; op = op->opnxt)
                {
                    if (!(op->opflag & OPFDONE)
                        && op->oprestype == RESTYPE_XFCN
                        && !stricmp((char *)buf + 3, op->opres))
                    {
                        /* note that this resource has now been processed */
                        op->opflag |= OPFDONE;

                        /* 
                         *   if it's already here, and we're not deleting
                         *   it, warn that the old one will stay around 
                         */
                        if (!(op->opflag & OPFDEL))
                        {
                            /* warn that we're going to ignore it */
                            rscptf("warning: XFCN resource \"%s\" already in "
                                   "file\n -- the old resource will be kept "
                                   "(use -replace to replace it)\n",
                                   op->opres);

                            /* don't add it */
                            op->opflag &= ~OPFADD;
                        }
                        else
                        {
                            /* 
                             *   we're deleting this resource; if adding
                             *   it back in (i.e., replacing it), process
                             *   the add operation now 
                             */
                            if (op->opflag & OPFADD)
                            {
                                /* show what we're doing */
                                show_op("replacing", op->opres,
                                        strlen(op->opres), op->oprestype);

                                /* 
                                 *   add the external file, replacing the
                                 *   one in the input file 
                                 */
                                procop(fpout, op, &first_xfcn);
                            }
                            else
                            {
                                /* note that we're deleting it */
                                show_op("deleting", op->opres,
                                        strlen(op->opres), op->oprestype);
                            }

                            /* don't copy the one out of the file */
                            copyrsc = FALSE;
                        }
                        break;
                    }
                }
            }
            else
            {
                /* no output file - just list the resource */
                show_list_item(&showed_heading, "XFCN",
                               (ulong)rsiz, buf + 3, (size_t)buf[2]);
            }

            /* note that we've found a user resource */
            found_user_rsc = TRUE;
        }
        
        if (fpout != 0 && copyrsc)
        {
            osfseek(fp, startpos, OSFSK_SET);
            copyres(fp, fpout, siz, endpos_ofs);
        }
        
        /* skip to the next resource */
        osfseek(fp, endpos, OSFSK_SET);
    }
    
    /* add the HTML resources if we haven't already */
    if (!found_htmlres)
        oplist = prochtmlres(fp, fpout, oplist, &copyrsc,
                             &showed_heading, FALSE);

    /* now go through what's left, and add new non-HTML resources */
    if (fpout != 0)
    {
        for (op = oplist ; op != 0 ; op = op->opnxt)
        {
            if (!(op->opflag & OPFDONE) && (op->opflag & OPFADD)
                && op->oprestype != RESTYPE_HTML)
            {
                /* show what we're doing */
                show_op("adding", op->opres,
                        strlen(op->opres), op->oprestype);

                /* add the file */
                procop(fpout, op, &first_xfcn);

                /* mark the operation as completed */
                op->opflag |= OPFDONE;
            }
        }
    }

    /* if just listing, and we didn't find anything, tell the user so */
    if (fpout == 0 && !found_user_rsc)
        rscptf("No user resources found.\n");

    /* done reading the file - finish it up */
    if (fpout != 0)
    {
        /* write EOF resource */
        if (osfwb(fpout, "\004$EOF\0\0\0\0", 9))
            errexit("error writing resource", 1);

        /* write first_xfcn value to EXTCNT resource */
        if (extcnt_pos)
        {
            osfseek(fpout, extcnt_pos + 13, OSFSK_SET);
            oswp4(buf, first_xfcn);
            osfwb(fpout, buf, 4);
        }
    }

    /* 
     *   return the final oplist (it may have been changed during
     *   processing) 
     */
    return oplist;
}
Ejemplo n.º 15
0
/*
 *   Process an HTML resource list.  If 'old_htmlres' is true, it
 *   indicates that the input file is pointing to an old resource map;
 *   otherwise, we need to construct a brand new one.  
 */
static opdef *prochtmlres(osfildef *fp, osfildef *fpout, opdef *oplist,
                          int *copyrsc, int *showed_heading, int old_htmlres)
{
    opdef *op;
    opdef *add_list = 0;
    opdef *prev_op;
    opdef *next_op;
    int    found;
    char   buf[512];
    ulong  in_entry_cnt;
    ulong  in_table_siz;
    ulong  out_hdr_siz;
    ulong  out_hdr_pos;
    ulong  i;
    ulong  out_res_cnt;
    ulong  out_total_name_len;
    ulong  rem;
    struct idx_t **in_list = 0, *out_list = 0, **p, *cur;
    ulong  in_res_base, out_res_base;
    ulong  out_endpos;

    /*
     *   Scan the oplist for an HTML resource.  If there aren't any, we
     *   don't need to modify the HTMLRES list, so tell the caller to copy
     *   this resource unchanged.  
     */
    for (op = oplist, found = FALSE ; op != 0 ; op = op->opnxt)
    {
        /* if this is an HTML resource, note it and stop looking */
        if (op->oprestype == RESTYPE_HTML)
        {
            found = TRUE;
            break;
        }
    }

    /* 
     *   If we didn't find any operations on this resource, and we're not
     *   simply listing resources or we don't have an old resource to
     *   list, tell the caller to copy it unchanged.  
     */
    if (!found && (fpout != 0 || !old_htmlres))
    {
        *copyrsc = TRUE;
        return oplist;
    }

    /* we'll be handling the resource - tell the caller not to copy it */
    *copyrsc = FALSE;

    /* if there's an old HTMLRES resource, read it */
    if (old_htmlres)
    {
        /* read the index entry count and size */
        if (osfrb(fp, buf, 8))
            listexit(fp, "unable to read HTMLRES header");
        in_entry_cnt = osrp4(buf);
        in_table_siz = osrp4(buf + 4);

        /* allocate space for pointers to all of the entries */
        if (in_entry_cnt != 0)
        {
            in_list = (struct idx_t **)
                      malloc(in_entry_cnt * sizeof(struct idx_t *));
            if (in_list == 0)
                listexit(fp, "unable to allocate space for HTMLRES entries");
        }

        /* read the index table entries */
        for (i = 0, p = in_list ; i < in_entry_cnt ; ++i, ++p)
        {
            ushort name_siz;
            ulong  res_siz;
            ulong  res_ofs;
            
            /* read the entry information */
            if (osfrb(fp, buf, 10))
                listexit(fp,
                         "unable to read HTMLRES index table entry (prefix)");
            
            /* get the resource size */
            res_ofs = osrp4(buf);
            res_siz = osrp4(buf + 4);
            
            /* read the name */
            name_siz = osrp2(buf + 8);
            if (name_siz > sizeof(buf))
                listexit(fp, "name too large in HTMLRES index table entry");
            if (osfrb(fp, buf, name_siz))
                listexit(fp,
                         "unable to read HTMLRES index table entry (name)");
            
            /* build this entry */
            *p = alloc_idx_entry(res_ofs, res_siz, buf, name_siz, 0, 0);
        }

        /* if we don't have an output file, list the HTMLRES contents */
        if (fpout == 0)
        {
            /* display all of the entries */
            for (i = 0, p = in_list ; i < in_entry_cnt ; ++i, ++p)
                show_list_item(showed_heading, "HTML",
                               (*p)->siz, (*p)->nam, (*p)->namlen);
            
            /* there's no more processing to do */
            goto done;
        }

        /*
         *   The resources start at the end of the index table - note the
         *   location of the end of the input table, since it's the base
         *   address relative to which the resource offsets are stated.  
         */
        in_res_base = osfpos(fp);

        /*
         *   Go through the resource table in the input file.  Find each
         *   one in the op list.  If it's not in the op list, we'll copy
         *   it to the output file.  
         */
        for (i = 0, p = in_list ; i < in_entry_cnt ; ++i, ++p)
        {
            int remove_res = FALSE;
            int add_res = FALSE;
            
            /* see if we can find this entry in the op list */
            for (prev_op = 0, op = oplist ; op != 0 ;
                 prev_op = op, op = op->opnxt)
            {
                /* if this one matches, note it */
                if (op->oprestype == RESTYPE_HTML
                    && strlen(op->opres) == (*p)->namlen
                    && !memicmp(op->opres, (*p)->nam, (*p)->namlen))
                {
                    /* 
                     *   if we're adding this resource (not replacing it),
                     *   warn that it's already in the file, and ignore
                     *   this op; if we're removing it or replacing it,
                     *   simply delete this entry from the input list so
                     *   it doesn't get copied to the output.  
                     */
                    if (!(op->opflag & OPFDEL))
                    {
                        /* warn that the old one will stay */
                        rscptf("warning: HTML resource \"%s\" already "
                               "present\n"
                               "  -- old version will be kept (use -replace "
                               "to replace it)\n", op->opres);
                        
                        /* remove it from the processing list */
                        remove_res = TRUE;
                    }
                    else
                    {
                        /* we are deleting it; see if we're also adding it */
                        if (op->opflag & OPFADD)
                        {
                            /* 
                             *   we're replacing this resource - take this
                             *   op out of the main list and put it into
                             *   the add list 
                             */
                            remove_res = TRUE;
                            add_res = TRUE;

                            /* note the addition */
                            show_op("replacing", op->opres, strlen(op->opres),
                                    op->oprestype);
                        }
                        else
                        {
                            /* note the deletion */
                            show_op("deleting", op->opres, strlen(op->opres),
                                    op->oprestype);

                            /* just remove it */
                            remove_res = TRUE;
                        }

                        /* get rid of this item from the input list */
                        free(*p);
                        *p = 0;
                    }
                    
                    /* no need to look further in the operations list */
                    break;
                }
            }
            
            /*
             *   If desired, remove this resource from the main list, and
             *   add it into the list of resources to add.  
             */
            if (remove_res)
            {
                /* unlink it from the main list */
                if (prev_op == 0)
                    oplist = op->opnxt;
                else
                    prev_op->opnxt = op->opnxt;
                
                /* if desired, add it to the additions list */
                if (add_res)
                {
                    /* we're adding it - put it in the additions list */
                    op->opnxt = add_list;
                    add_list = op;
                }
                else
                {
                    /* this item has been processed - delete it */
                    free(op);
                }
            }
        }
    }
    else
    {
        /* there are no entries in the input file */
        in_entry_cnt = 0;
        in_table_siz = 0;
    }

    /*
     *   Move all of the HTML resources marked as additions in the main
     *   operations list into the additions list. 
     */
    for (prev_op = 0, op = oplist ; op != 0 ; op = next_op)
    {
        /* note the next op, in case we move this one to the other list */
        next_op = op->opnxt;
        
        /* 
         *   if it's an HTML resource to be added, move it to the
         *   additions list 
         */
        if (op->oprestype == RESTYPE_HTML && (op->opflag & OPFADD) != 0)
        {
            /* show what we're doing */
            show_op("adding", op->opres, strlen(op->opres), op->oprestype);
            
            /* unlink it from the main list */
            if (prev_op == 0)
                oplist = op->opnxt;
            else
                prev_op->opnxt = op->opnxt;

            /* add it to the additions list */
            op->opnxt = add_list;
            add_list = op;

            /* 
             *   note that we don't want to advance the 'prev_op' pointer,
             *   since we just removed this item - the previous item is
             *   still the same as it was on the last iteration 
             */
        }
        else
        {
            /* 
             *   we're leaving this op in the original list - it's now the
             *   previous op in the main list 
             */
            prev_op = op;
        }
    }

    /*
     *   Figure out what we'll be putting in the HTMLRES list: we'll add
     *   each surviving entry from the input file, plus all of the items
     *   in the add list, plus all of the HTML items in the main list that
     *   are marked for addition.  
     */
    out_res_cnt = 0;
    out_total_name_len = 0;

    /* count input file entries that we're going to copy */
    for (i = 0, p = in_list ; i < in_entry_cnt ; ++i, ++p)
    {
        if (*p != 0)
            add_idx_entry(&out_list, &out_res_cnt, &out_total_name_len,
                          0, 0, (*p)->nam, (*p)->namlen, 0, *p);
    }

    /* 
     *   Count items in the additions list.  Note that every HTML resource
     *   marked for addition is in the additions list, since we moved all
     *   such resources out of the main list and into the additions list
     *   earlier.  
     */
    for (op = add_list ; op != 0 ; op = op->opnxt)
        add_idx_entry(&out_list, &out_res_cnt, &out_total_name_len,
                      0, 0, op->opres, (ushort)strlen(op->opres), op, 0);

    /* write the resource header */
    if (osfwb(fpout, "\007HTMLRES\0\0\0\0", 12))
        listexit(fp, "unable to write HTMLRES type header");
    out_hdr_pos = osfpos(fpout);

    /*
     *   Reserve space in the output file for the index table.  We need
     *   eight bytes for the index table prefix, then ten bytes per entry
     *   plus the name sizes. 
     */
    out_hdr_siz = 8 + (10 * out_res_cnt) + out_total_name_len;

    /* write the index table prefix */
    oswp4(buf, out_res_cnt);
    oswp4(buf + 4, out_hdr_siz);
    if (osfwb(fpout, buf, 8))
        listexit(fp, "unable to write HTMLRES prefix");

    /* 
     *   Reserve space for the headers.  Don't actually write them yet,
     *   since we don't know the actual locations and sizes of the
     *   entries; for now, simply reserve the space, so that we can come
     *   back here later and write the actual headers.  Note that we
     *   deduct the eight bytes we've already written from the amount of
     *   filler to put in.  
     */
    for (rem = out_hdr_siz - 8 ; rem != 0 ; )
    {
        ulong amt;
        
        /* write out a buffer full */
        amt = (rem > sizeof(buf) ? sizeof(buf) : rem);
        if (osfwb(fpout, buf, amt))
            listexit(fp, "unable to write HTMLRES header");

        /* deduct the amount we wrote from the remainder */
        rem -= amt;
    }

    /* 
     *   note the current position in the output file - this is the base
     *   address of the resources 
     */
    out_res_base = osfpos(fpout);

    /*
     *   Write the resources.  
     */
    for (cur = out_list ; cur != 0 ; cur = cur->nxt)
    {
        /* 
         *   note the current file position as an offset from the resource
         *   base in the output file - this is the offset that we need to
         *   store in the index entry for this object 
         */
        cur->ofs = osfpos(fpout) - out_res_base;
        
        /* 
         *   Copy the resource to the output.  If it comes from the input
         *   file, copy from there, otherwise go out and find the external
         *   file and copy its contents. 
         */
        if (cur->src_op != 0)
        {
            osfildef *fpext;
            ulong fsiz;
            
            /* it comes from an external file - open the file */
            fpext = osfoprb(cur->src_op->opfile, OSFTGAME);
            if (fpext == 0)
            {
                rscptf("%s: ", cur->src_op->opfile);
                errexit("unable to open file", 1);
            }

            /* figure the size of the file */
            osfseek(fpext, 0L, OSFSK_END);
            fsiz = osfpos(fpext);
            osfseek(fpext, 0L, OSFSK_SET);

            /* copy the contents of the external file to the output */
            copybytes(fpext, fpout, fsiz);

            /* the size is the same as the external file's size */
            cur->siz = fsiz;

            /* done with the file */
            osfcls(fpext);
        }
        else
        {
            /* 
             *   it comes from the input resource file - seek to the start
             *   of the resource in the input file, and copy the data to
             *   the output file 
             */
            osfseek(fp, in_res_base + cur->src_idx->ofs, OSFSK_SET);
            copybytes(fp, fpout, cur->src_idx->siz);

            /* the size is the same as in the input file */
            cur->siz = cur->src_idx->siz;
        }
    }

    /* note the current output position - this is the end of the resource */
    out_endpos = osfpos(fpout);

    /*
     *   Now that we've written all of the resources and know their actual
     *   layout in the file, we can go back and write the index table. 
     */
    osfseek(fpout, out_hdr_pos + 8, OSFSK_SET);
    for (cur = out_list ; cur != 0 ; cur = cur->nxt)
    {
        /* build this object's index table entry */
        oswp4(buf, cur->ofs);
        oswp4(buf + 4, cur->siz);
        oswp2(buf + 8, cur->namlen);

        /* write the entry */
        if (osfwb(fpout, buf, 10)
            || osfwb(fpout, cur->nam, cur->namlen))
            listexit(fp, "unable to write HTML index table entry");
    }

    /*
     *   We're done building the resource; now all we need to do is go
     *   back and write the ending position of the resource in the
     *   resource header.  
     */
    osfseek(fpout, out_hdr_pos - 4, OSFSK_SET);
    oswp4(buf, out_endpos);
    if (osfwb(fpout, buf, 4))
        errexit("error writing resource", 1);

    /* seek back to the end of the resource in the output file */
    osfseek(fpout, out_endpos, OSFSK_SET);

done:
    /* if we have an input list, free it */
    if (in_list != 0)
    {
        /* delete all of the entries in the input table */
        for (i = 0, p = in_list ; i < in_entry_cnt ; ++i, ++p)
        {
            /* delete this entry if we haven't already done so */
            if (*p != 0)
                free(*p);
        }

        /* delete the input pointer list itself */
        free(in_list);
    }

    /* 
     *   delete everything in the additions list, since we're done with
     *   them now 
     */
    for (op = add_list ; op != 0 ; op = next_op)
    {
        /* note the next entry in the list */
        next_op = op->opnxt;

        /* delete this entry */
        free(op);
    }

    /* return the op list in its current form */
    return oplist;
}