[comp.lang.c] Embedding binary data in C source

john13@garfield.UUCP (John Russell) (12/14/87)

--

I saw a post on comp.lang.c the other day regarding using binary constants
in C source files. Now I have utilities to convert between various types of
data (eg graphic image file, definition of an icon for a program) and hex
constants for inclusion in a program, but it's frustrating to have to use
them for very small jobs or every time I want to make minor changes. And the
best of these utilities I've got is half disabled, the authors want $15 for
the complete version. If I needed it that badly I'd spend a month writing
it myself and save the $15 :-) !

Don't suggest graph paper -- that's right out (yech, ptui, sprites on the
C64)!

That poster gave a "short form" for adding binary data in the form of a
picture that you could see; for an image, you could also modify it right
in the program. I added to that idea a little bit, and here is the result.
One thing I like is that it doesn't add to the size of the program, auto-
initialized global variables are all constants.

I have included some editor macros to make this scheme less tedious. They're
meant for the editor DME on the Amiga, but if your editor supports arbitrary
remapping of keys you should be able to adapt them.

A word of warning - many of the lines are longer than 80 characters so they
will likely be split during transmission and you'll have to join them by
hand.

John

---- Cut here for bintest.c, then strip the .signature ----

/* You may want to change the names of these macros if you have them as */
/* typedefs already. The Amiga uses typedefs in all caps. */

#define byte(a,b,c,d,e,f,g,h) (((a) << 7) + ((b) << 6) + ((c) << 5) + ((d) << 4) + ((e) << 3) + ((f) << 2) + ((g) << 1) + (h))

#define word(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) ( (byte((a),(b),(c),(d),(e),(f),(g),(h)) << 8) +\
    (byte((i),(j),(k),(l),(m),(n),(o),(p))) )

/* $#%@%$%# I can't define any high-contrast symbols like . and @ because
   the preprocessor complains! Please feel free to substitute your own. */

#define X 1
#define o 0

short bitimage[] =  /* these "words" are 16-bit */
{
    word( o,o,X,X,X,X,X,X,X,X,X,o,o,o,o,o ),	/* I really wish I could use */
    word( o,o,X,o,o,o,o,o,o,o,X,o,o,o,o,o ),	/* "." for 0 and "@" for 1! */
    word( o,o,X,o,X,X,X,X,X,o,X,o,o,o,o,o ),
    word( o,o,X,o,X,o,o,o,X,o,X,o,o,o,o,o ),
    word( o,o,X,o,X,o,X,o,X,o,X,o,o,o,o,o ),
    word( o,o,X,o,X,o,o,o,X,o,X,o,o,o,o,o ),
    word( o,o,X,o,X,X,X,X,X,o,X,o,o,o,o,o ),
    word( o,o,X,o,o,o,o,o,o,o,X,o,o,o,o,o ),
    word( o,o,X,X,X,X,X,X,X,X,X,o,o,o,o,o ),
    word( o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o ),
    word( X,X,X,X,X,X,X,X,X,X,X,X,X,o,o,o ),
    word( X,X,X,X,X,X,X,X,X,X,X,X,o,o,o,o ),
    word( X,X,o,o,o,o,o,o,o,X,X,o,o,o,o,o ),
    word( X,X,o,o,o,o,o,o,X,X,o,o,o,o,o,o ),
    word( X,X,X,X,X,X,X,X,X,o,o,o,o,o,o,o ),
    word( X,X,X,X,X,X,X,X,o,o,o,o,o,o,o,o )
};

/*
 *  Here are some useful macros to define in DME if you want to edit these
 *  images quickly (you need to unmap them afterwards though to keep your
 *  sanity!). They let you use the h,j,k,l keys for movement as in vi.
 *  Also meta-combinations with '1' are mapped to helpful drawing commands,
 *  and 0 is mapped to various erase commands. (I wanted to map the space
 *  bar, but it seems DME doesn't call it anything?)
 *
 *  NB: you can read this section in directly and bsource the following
 *  lines. Also for the tabs to work correctly you must align your image
 *  so that 1's or spaces will be put at `odd' character positions on the
 *  line. Don't include the TURN_ON/OFF lines in the block, you'll see
 *  their purpose a little later on.

TURN_ON:
  tabstop 2
  insertmode off
  map l `tab'
  map h `backtab'
  map k `up'
  map j `down'
  map 1 ``X' tab'
  map s-1 ``X' backtab backtab'
  map c-1 ``X' backtab down'
  map a-1 ``X' backtab up'
  map 0 ``o' tab'
  map s-0 ``o' backtab backtab'
  map c-0 ``o' backtab down'
  map a-0 ``o' backtab up'

Not implemented in DME:
  map space ``o' tab'
  map s-space ``o' backtab backtab'
  map c-space ``o' backtab down'
  map a-space ``o' backtab up'

 *  Bsource these lines (after the label) to restore the editor environment.

TURN_OFF:
  tabstop 4
  insertmode on
  unmap l
  unmap h
  unmap k
  unmap j
  unmap 1
  unmap s-1
  unmap c-1
  unmap a-1
  unmap 0
  unmap s-0
  unmap c-0
  unmap a-0

Not implemented in DME:
  unmap space
  unmap s-space
  unmap c-space
  unmap a-space

 *  If you use this feature often, you could put an identifier before each
 *  section and map some other key to find it, `block' X lines below it,
 *  and then bsource them -- ie switch between modes with a single key.
 *  What the heck, I'm already typing:

  map cs-t `insertmode on ` BOOKMARK ' top find `TURN_ON:' down unblock block repeat 13 `down' block bsource top find `BOOKMARK' left del while cu `del' del'
  map ca-t `insertmode on ` BOOKMARK ' top find `TURN_OFF:' down unblock block repeat 13 `down' block bsource top find `BOOKMARK' left del while cu `del' del'

 *  One final caution, you should put the two lines above in your .edrc since
 *  otherwise the editor may find the wrong occurrence of `BOOKMARK' when it
 *  tries to restore your place. Otherwise I _think_ the macros are
 *  completely bulletproof.
 */

#undef word
#undef byte
#undef X
#undef o

main(argc, argv)    /* short program to verify the macros work */
int argc;
char *argv[];
{
    int x;

    for (x=0; x<16; x++)
    {
	printf("%x\n",bitimage[x]); /* binary constants easier to read! */
    }
}


-- 
"Listen fathead, the ONE thing we DON'T need is some trigger-happy lunatic
 in charge... No I didn't mean you Mr. President... Yes sir, I'm sure you
 do get a lot of that sort of thing."
				-- Judge Harold T. Stone

john13@garfield.UUCP (John Russell) (12/14/87)

In article <4290@garfield.UUCP> john13@garfield.UUCP (John Russell) writes:
>
>main(argc, argv)    /* short program to verify the macros work */

Oops, I should have mentioned -- I compiled with integers defaulting to
16 bits, be careful if you start printf'ing or moving numbers defined this
way that the compiler is expecting the same length value you're giving it.
You may have to cast the individual words to longs in the small example
program.

John
-- 
"Listen fathead, the ONE thing we DON'T need is some trigger-happy lunatic
 in charge... No I didn't mean you Mr. President... Yes sir, I'm sure you
 do get a lot of that sort of thing."
				-- Judge Harold T. Stone