Resources for DOS

by Paul Hsieh
Recently while tinkering around with a video game I've been working on, I decided I didn't want to have a subdirectory of files exposing my resources (including the title screen and sprites.) I wanted a way to incorporate all the raw data into my executable directly. What I came up with is the following:

I wrote a program which took any binary file and encoded it as a named array of char's, short's or long's in source format. This, I then would compile and include into a library file (I have hundreds of sprites, so cutting down on linking time is a desirable thing) using my compiler's library manager.

Setting things up properly with a hand made makefile I am able to build smooth as glass, with the speed and reliability of resource binding methods. The makefile defines dependencies from graphics files to object files. The build command is assigned to a batch file which processes the graphics source into a C file, compiles the C file to an object file and then deletes the C file (to save space.) Of course, it is also required that the application be able to read these resources straight from memory.

I present the binary to C translator below. Clearly it is not difficult to adapt this program to other languages as well.


Syntax: bin2c SourceFile SymbolName Size [FormatString]

The SymbolName is the global symbol name that points to the start of the resource in question, which is accessible in your source code. The Size is 1, 2 or 4 standing for char, short and long, respectively. If the optional FormatString is used, it must contain a %%s and a %%u in succession. The %%s will be replaced by the symbol name and the %%u will be replaced by the resource size and is output at the end. The output goes to stdout.

//
// Copyright 1996 Paul Hsieh.  All rights reserved.
//
// This program is public domain, subject to the conditions that any use made
// of it that results in a derivative work or product must credit the author,
// Paul Hsieh and that this source never be distributed without these comments
// appearing intact at the top of the program.
//

#include <stdio.h>

char *sizetype[5]={ "NULL","char","short","??","long" };
char buffer[4];
char comma=' ';
char *separator[6]={ "\n"," "," "," "," "," " };
char Fmt[1024];

main(int argc, char *argv[]) {
int i,size=1;
long count=0;
FILE *fp;

        if( 3>argc ) {
                printf("Syntax: %s  file  name  [size  [format]]\n",argv[0]);
                exit(-1);
        }

        if( argc>=4 ) {
                sscanf(argv[3],"%d",&size);
                if( 1>size || size>4 || size==3 ) {
                        printf("Invalid size\n");
                        exit(-1);
                }
        }

        printf("/* Inline declaration of %s from %s */\n\n",argv[2],argv[1]);
        printf("%s %s[]= {\n",sizetype[size],argv[2]);

        fp = fopen(argv[1],"rb");
        while( 0!=fread(buffer,1,size,fp) ) {
                printf("%c%s0x",comma,separator[count%6]);
                for(i=size-1;i>=0;i--) {
                        printf("%02x",buffer[i]);
                        buffer[i]='\0';
                }
                comma=',';
                count++;
        }

        printf("};\n\n");

        if( argc>=5 ) {
                Fmt[0]='\0';
                for(i=5;argc>=i;i++) {
                        if( Fmt[0]!='\0' ) strcat(Fmt," ");
                        strcat(Fmt,argv[i-1]);
                }
                printf(Fmt,argv[2],count);
                printf("\n");
        } else {
                printf("/* %ld %ss = %ld bytes */\n",count, sizetype[size], count*((long)size));
        }
       exit(0);
}

Update!

I have written a slightly more sophisticated program that supercedes the functionality of bin2c. Its called metaC. What it does is take a meta-C file which is a mostly C source file which includes tokens for inlining data directly, and translates them to proper C files with direct inline data declarations.

In more detail:

METAC: A program for inlining binary data into C
written by Paul Hsieh

        Metac will take a C-like file, simply output the file's
        contents to standard out until it reads an inline file
        token.  Such tokens appear with the syntax:

            @filename

        So, for example, if you wanted to include a string that you
        have authored as an ordinary text file into your C code you
        could simply write:

            char Msg1[] = "@readme.txt";

        then filtering through metac, the @readme.txt contents are
        injected inline between the quotes as standard C syntax
        chars, replacing the occurrence of @readme.txt.

        The idea was inspired by Window's resources which were in
        turn inspired by people who would arbitrarily tack data on
        the ends of their executables.  Clearly this idea is more
        general and easier on the programmer.  But it has the
        disadvantage or necessarily including the inlined data in
        memory during execution.

        KNOWN BUGS:

        Intrudes on otherwise legal uses of the @ symbol.

The program is available for download here:

I cannot distribute the source because I am using a library that I am not at liberty to distribute (and because its an embarassing hack.) Clearly this program is not much of a challenge to write, but is provided here as a convenience for the lazy programmer.



Copyright © 1996, Paul Hsieh All Rights Reserved.