Logo Search packages:      
Sourcecode: allegro4.2 version File versions  Download package

datafile.c

/*         ______   ___    ___ 
 *        /\  _  \ /\_ \  /\_ \ 
 *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___ 
 *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
 *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
 *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
 *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
 *                                           /\____/
 *                                           \_/__/
 *
 *      Datafile reading routines.
 *
 *      By Shawn Hargreaves.
 *
 *      Elias Pschernig made load_datafile_object() handle properties.
 *
 *      See readme.txt for copyright information.
 */


#include <string.h>

#include "allegro.h"
#include "allegro/internal/aintern.h"



static void unload_midi(MIDI *m);
static void initialise_datafile(DATAFILE *data);



/* hack to let the grabber prevent compiled sprites from being compiled */
int _compile_sprites = TRUE;

/* flag to detect whether compiled datafiles are constructed:
 *  A runtime flag is required because the shared version of the library may
 *  have to deal both with executables that use constructors and with
 *  executables that don't.
 */
static int constructed_datafiles = FALSE;

static void (*datafile_callback)(DATAFILE *) = NULL;



/* load_st_data:
 *  I'm not using this format any more, but files created with the old
 *  version of Allegro might have some bitmaps stored like this. It is 
 *  the 4bpp planar system used by the Atari ST low resolution mode.
 */
static void load_st_data(unsigned char *pos, long size, PACKFILE *f)
{
   int c;
   unsigned int d1, d2, d3, d4;

   size /= 8;           /* number of 4 word planes to read */

   while (size) {
      d1 = pack_mgetw(f);
      d2 = pack_mgetw(f);
      d3 = pack_mgetw(f);
      d4 = pack_mgetw(f);
      for (c=0; c<16; c++) {
       *(pos++) = ((d1 & 0x8000) >> 15) + ((d2 & 0x8000) >> 14) +
                ((d3 & 0x8000) >> 13) + ((d4 & 0x8000) >> 12);
       d1 <<= 1;
       d2 <<= 1;
       d3 <<= 1;
       d4 <<= 1; 
      }
      size--;
   }
}



/* read_block:
 *  Reads a block of size bytes from a file, allocating memory to store it.
 */
static void *read_block(PACKFILE *f, int size, int alloc_size)
{
   void *p;

   p = malloc(MAX(size, alloc_size));
   if (!p) {
      *allegro_errno = ENOMEM;
      return NULL;
   }

   pack_fread(p, size, f);

   if (pack_ferror(f)) {
      free(p);
      return NULL;
   }

   return p;
}



/* read_bitmap:
 *  Reads a bitmap from a file, allocating memory to store it.
 */
static BITMAP *read_bitmap(PACKFILE *f, int bits, int allowconv)
{
   int x, y, w, h, c, r, g, b, a;
   int destbits, rgba;
   unsigned short *p16;
   uint32_t *p32;
   BITMAP *bmp;

   if (bits < 0) {
      bits = -bits;
      rgba = TRUE;
   }
   else
      rgba = FALSE;

   if (allowconv)
      destbits = _color_load_depth(bits, rgba);
   else
      destbits = 8;

   w = pack_mgetw(f);
   h = pack_mgetw(f);

   bmp = create_bitmap_ex(MAX(bits, 8), w, h);
   if (!bmp) {
      *allegro_errno = ENOMEM;
      return NULL;
   }

   switch (bits) {

      case 4:
       /* old format ST data */
       load_st_data(bmp->dat, w*h/2, f);
       break;

      case 8:
       /* 256 color bitmap */
       pack_fread(bmp->dat, w*h, f);

       break;

      case 15:
       /* 15bit hicolor */
       for (y=0; y<h; y++) {
          p16 = (uint16_t *)bmp->line[y];

          for (x=0; x<w; x++) {
             c = pack_igetw(f);
             r = _rgb_scale_5[(c >> 11) & 0x1F]; /* stored as 16 bit */
             g = _rgb_scale_6[(c >> 5) & 0x3F];
             b = _rgb_scale_5[c & 0x1F];
             p16[x] = makecol15(r, g, b);
          }
       }
       break;

      case 16:
       /* 16bit hicolor */
       for (y=0; y<h; y++) {
          p16 = (uint16_t *)bmp->line[y];

          for (x=0; x<w; x++) {
             c = pack_igetw(f);
             r = _rgb_scale_5[(c >> 11) & 0x1F];
             g = _rgb_scale_6[(c >> 5) & 0x3F];
             b = _rgb_scale_5[c & 0x1F];
             p16[x] = makecol16(r, g, b);
          }
       }
       break;

      case 24:
       /* 24bit truecolor */
       for (y=0; y<h; y++) {
          for (x=0; x<w; x++) {
             r = pack_getc(f);
             g = pack_getc(f);
             b = pack_getc(f);

             if (rgba)
              pack_getc(f);

             c = makecol24(r, g, b);
             WRITE3BYTES(bmp->line[y] + (x * 3), c);
          }
       }
       break;

      case 32:
       /* 32bit rgba */
       for (y=0; y<h; y++) {
          p32 = (uint32_t *)bmp->line[y];

          for (x=0; x<w; x++) {
             r = pack_getc(f);
             g = pack_getc(f);
             b = pack_getc(f);

             if (rgba)
              a = pack_getc(f);
             else
              a = 0;

             p32[x] = makeacol32(r, g, b, a);
          }
       }
       break;

   }

   if (bits != destbits) {
      BITMAP *tmp = bmp;
      bmp = create_bitmap_ex(destbits, w, h);
      if (!bmp) {
       *allegro_errno = ENOMEM;
       return NULL;
      }
      blit(tmp, bmp, 0, 0, 0, 0, bmp->w, bmp->h);
      destroy_bitmap(tmp);
   }

   return bmp;
}



/* read_font_fixed:
 *  Reads a fixed pitch font from a file. This format is no longer used.
 */
static FONT *read_font_fixed(PACKFILE *pack, int height, int maxchars)
{
   FONT *f = NULL;
   FONT_MONO_DATA *mf = NULL;
   FONT_GLYPH **gl = NULL;
   
   int i = 0;
   
   f = malloc(sizeof(FONT));
   mf = malloc(sizeof(FONT_MONO_DATA));
   gl = malloc(sizeof(FONT_GLYPH *) * maxchars);
   
   if (!f || !mf || !gl) {
      free(f);
      free(mf);
      free(gl);
      *allegro_errno = ENOMEM;
      return NULL;
   }
   
   f->data = mf;
   f->height = height;
   f->vtable = font_vtable_mono;
   
   mf->begin = ' ';
   mf->end = ' ' + maxchars;
   mf->next = NULL;
   mf->glyphs = gl;
   
   memset(gl, 0, sizeof(FONT_GLYPH *) * maxchars);
   
   for (i = 0; i < maxchars; i++) {
      FONT_GLYPH *g = malloc(sizeof(FONT_GLYPH) + height);
      
      if (!g) {
       destroy_font(f);
       *allegro_errno = ENOMEM;
       return NULL;
      }
      
      gl[i] = g;
      g->w = 8;
      g->h = height;
      
      pack_fread(g->dat, height, pack);
   }
   
   return f;
}



/* read_font_prop:
 *  Reads a proportional font from a file. This format is no longer used.
 */
static FONT *read_font_prop(PACKFILE *pack, int maxchars)
{
   FONT *f = NULL;
   FONT_COLOR_DATA *cf = NULL;
   BITMAP **bits = NULL;
   int i = 0, h = 0;
   
   f = malloc(sizeof(FONT));
   cf = malloc(sizeof(FONT_COLOR_DATA));
   bits = malloc(sizeof(BITMAP *) * maxchars);
   
   if (!f || !cf || !bits) {
      free(f);
      free(cf);
      free(bits);
      *allegro_errno = ENOMEM;
      return NULL;
   }
   
   f->data = cf;
   f->vtable = font_vtable_color;
   
   cf->begin = ' ';
   cf->end = ' ' + maxchars;
   cf->next = NULL;
   cf->bitmaps = bits;
   
   memset(bits, 0, sizeof(BITMAP *) * maxchars);
   
   for (i = 0; i < maxchars; i++) {
      if (pack_feof(pack)) break;
      
      bits[i] = read_bitmap(pack, 8, FALSE);
      if (!bits[i]) {
       destroy_font(f);
       return NULL;
      }
      
      if (bits[i]->h > h) h = bits[i]->h;
   }
   
   while (i < maxchars) {
      bits[i] = create_bitmap_ex(8, 8, h);
      if (!bits[i]) {
       destroy_font(f);
       *allegro_errno = ENOMEM;
       return NULL;
      }
      
      clear_bitmap(bits[i]);
      i++;
   }
   
   f->height = h;
   
   return f;
}



/* read_font_mono:
 *  Helper for read_font, below
 */
static FONT_MONO_DATA *read_font_mono(PACKFILE *f, int *hmax)
{
   FONT_MONO_DATA *mf = NULL;
   int max = 0, i = 0;
   FONT_GLYPH **gl = NULL;
   
   mf = malloc(sizeof(FONT_MONO_DATA));
   if (!mf) {
      *allegro_errno = ENOMEM;
      return NULL;
   }
   
   mf->begin = pack_mgetl(f);
   mf->end = pack_mgetl(f) + 1;
   mf->next = NULL;
   max = mf->end - mf->begin;
   
   mf->glyphs = gl = malloc(sizeof(FONT_GLYPH *) * max);
   if (!gl) {
      free(mf);
      *allegro_errno = ENOMEM;
      return NULL;
   }
   
   for (i = 0; i < max; i++) {
      int w, h, sz;
      
      w = pack_mgetw(f);
      h = pack_mgetw(f);
      sz = ((w + 7) / 8) * h;
      
      if (h > *hmax) *hmax = h;
      
      gl[i] = malloc(sizeof(FONT_GLYPH) + sz);
      if (!gl[i]) {
       while (i) {
          i--;
          free(mf->glyphs[i]);
       }
       free(mf);
       free(mf->glyphs);
       *allegro_errno = ENOMEM;
       return NULL;
      }
      
      gl[i]->w = w;
      gl[i]->h = h;
      pack_fread(gl[i]->dat, sz, f);
   }
   
   return mf;
}



/* read_font_color:
 *  Helper for read_font, below.
 */
static FONT_COLOR_DATA *read_font_color(PACKFILE *pack, int *hmax, int depth)
{
   FONT_COLOR_DATA *cf = NULL;
   int max = 0, i = 0;
   BITMAP **bits = NULL;
   
   cf = malloc(sizeof(FONT_COLOR_DATA));
   if (!cf) {
      *allegro_errno = ENOMEM;
      return NULL;
   }
   
   cf->begin = pack_mgetl(pack);
   cf->end = pack_mgetl(pack) + 1;
   cf->next = NULL;
   max = cf->end - cf->begin;

   cf->bitmaps = bits = malloc(sizeof(BITMAP *) * max);
   if (!bits) {
      free(cf);
      *allegro_errno = ENOMEM;
      return NULL;
   }

   for (i = 0; i < max; i++) {
      /* Do not allow colour conversions for 8 bit bitmaps, but require it for
       * all other colour depths.
       */
      bits[i] = read_bitmap(pack, depth, depth!=8);
      if (!bits[i]) {
       while (i) {
          i--;
          destroy_bitmap(bits[i]);
       }
       free(bits);
       free(cf);
       *allegro_errno = ENOMEM;
       return 0;
      }
      
      if (bits[i]->h > *hmax) 
       *hmax = bits[i]->h;
   }

   return cf;
}



/* read_font:
 *  Reads a new style, Unicode format font from a file.
 */
static FONT *read_font(PACKFILE *pack)
{
   FONT *f = NULL;
   int num_ranges = 0;
   int height = 0;
   int depth;

   f = malloc(sizeof(FONT));
   if (!f) {
      *allegro_errno = ENOMEM;
      return NULL;
   }

   f->data = NULL;

   num_ranges = pack_mgetw(pack);
   while (num_ranges--) {
      depth = pack_getc(pack);
      if (depth == 1 || depth == 255) {
       FONT_MONO_DATA *mf = 0, *iter = (FONT_MONO_DATA *)f->data;
       
       f->vtable = font_vtable_mono;

       mf = read_font_mono(pack, &height);
       if (!mf) {
          destroy_font(f);
          return NULL;
       }

       if (!iter)
          f->data = mf;
       else {
          while (iter->next) iter = iter->next;
          iter->next = mf;
       }
      } 
      else {
       FONT_COLOR_DATA *cf = NULL, *iter = (FONT_COLOR_DATA *)f->data;
         
         /* Older versions of Allegro use `0' to indicate a colour font */
         if (depth == 0)
            depth = 8;

       f->vtable = font_vtable_color;

       cf = read_font_color(pack, &height, depth);
       if (!cf) {
          destroy_font(f);
          return NULL;
       }

       if (!iter) 
          f->data = cf;
       else {
          while (iter->next) iter = iter->next;
          iter->next = cf;
       }
      }
   }

   f->height = height;
   return f;
}



/* read_palette:
 *  Reads a palette from a file.
 */
static RGB *read_palette(PACKFILE *f, int size)
{
   RGB *p;
   int c, x;

   p = malloc(sizeof(PALETTE));
   if (!p) {
      *allegro_errno = ENOMEM;
      return NULL;
   }

   for (c=0; c<size; c++) {
      p[c].r = pack_getc(f) >> 2;
      p[c].g = pack_getc(f) >> 2;
      p[c].b = pack_getc(f) >> 2;
   }

   x = 0;
   while (c < PAL_SIZE) {
      p[c] = p[x];
      c++;
      x++;
      if (x >= size)
       x = 0;
   }

   return p;
}



/* read_sample:
 *  Reads a sample from a file.
 */
static SAMPLE *read_sample(PACKFILE *f)
{
   signed short bits;
   SAMPLE *s;

   s = malloc(sizeof(SAMPLE));
   if (!s) {
      *allegro_errno = ENOMEM;
      return NULL;
   }

   bits = pack_mgetw(f);

   if (bits < 0) {
      s->bits = -bits;
      s->stereo = TRUE;
   }
   else {
      s->bits = bits;
      s->stereo = FALSE;
   }

   s->freq = pack_mgetw(f);
   s->len = pack_mgetl(f);
   s->priority = 128;
   s->loop_start = 0;
   s->loop_end = s->len;
   s->param = 0;

   if (s->bits == 8) {
      s->data = read_block(f, s->len * ((s->stereo) ? 2 : 1), 0);
   }
   else {
      s->data = malloc(s->len * sizeof(short) * ((s->stereo) ? 2 : 1));
      if (s->data) {
       int i;

       for (i=0; i < (int)s->len * ((s->stereo) ? 2 : 1); i++) {
          ((unsigned short *)s->data)[i] = pack_igetw(f);
       }

       if (pack_ferror(f)) {
          free(s->data);
          s->data = NULL;
       }
      }
   }
   if (!s->data) {
      free(s);
      return NULL;
   }

   LOCK_DATA(s, sizeof(SAMPLE));
   LOCK_DATA(s->data, s->len * ((s->bits==8) ? 1 : sizeof(short)) * ((s->stereo) ? 2 : 1));

   return s;
}



/* read_midi:
 *  Reads MIDI data from a datafile (this is not the same thing as the 
 *  standard midi file format).
 */
static MIDI *read_midi(PACKFILE *f)
{
   MIDI *m;
   int c;

   m = malloc(sizeof(MIDI));
   if (!m) {
      *allegro_errno = ENOMEM;
      return NULL;
   }

   for (c=0; c<MIDI_TRACKS; c++) {
      m->track[c].len = 0;
      m->track[c].data = NULL;
   }

   m->divisions = pack_mgetw(f);

   for (c=0; c<MIDI_TRACKS; c++) {
      m->track[c].len = pack_mgetl(f);
      if (m->track[c].len > 0) {
       m->track[c].data = read_block(f, m->track[c].len, 0);
       if (!m->track[c].data) {
          unload_midi(m);
          return NULL;
       }
      }
   }

   LOCK_DATA(m, sizeof(MIDI));

   for (c=0; c<MIDI_TRACKS; c++) {
      if (m->track[c].data) {
       LOCK_DATA(m->track[c].data, m->track[c].len);
      }
   }

   return m;
}



/* read_rle_sprite:
 *  Reads an RLE compressed sprite from a file, allocating memory for it. 
 */
static RLE_SPRITE *read_rle_sprite(PACKFILE *f, int bits)
{
   int x, y, w, h, c, r, g, b, a;
   int destbits, size, rgba;
   RLE_SPRITE *s;
   BITMAP *b1, *b2;
   unsigned int eol_marker;
   signed short s16;
   signed short *p16;
   int32_t *p32;

   if (bits < 0) {
      bits = -bits;
      rgba = TRUE;
   }
   else
      rgba = FALSE;

   w = pack_mgetw(f);
   h = pack_mgetw(f);
   size = pack_mgetl(f);

   s = malloc(sizeof(RLE_SPRITE) + size);
   if (!s) {
      *allegro_errno = ENOMEM;
      return NULL;
   }

   s->w = w;
   s->h = h;
   s->color_depth = bits;
   s->size = size;

   switch (bits) {

      case 8:
       /* easy! */
       pack_fread(s->dat, size, f);
       break;

      case 15:
      case 16:
       /* read hicolor data */
       p16 = (signed short *)s->dat;
       eol_marker = (bits == 15) ? MASK_COLOR_15 : MASK_COLOR_16;

       for (y=0; y<h; y++) {
          s16 = pack_igetw(f);

          while ((unsigned short)s16 != MASK_COLOR_16) {
             if (s16 < 0) {
              /* skip count */
              *p16 = s16;
              p16++;
             }
             else {
              /* solid run */
              x = s16;
              *p16 = s16;
              p16++;

              while (x-- > 0) {
                 c = pack_igetw(f);
                 r = _rgb_scale_5[(c >> 11) & 0x1F];
                 g = _rgb_scale_6[(c >> 5) & 0x3F];
                 b = _rgb_scale_5[c & 0x1F];
                 *p16 = makecol_depth(bits, r, g, b);
                 p16++;
              }
             }

             s16 = pack_igetw(f);
          }

          /* end of line */
          *p16 = eol_marker;
          p16++;
       }
       break;

      case 24:
      case 32:
       /* read truecolor data */
       p32 = (int32_t *)s->dat;
       eol_marker = (bits == 24) ? MASK_COLOR_24 : MASK_COLOR_32;

       for (y=0; y<h; y++) {
          c = pack_igetl(f);

          while ((uint32_t)c != MASK_COLOR_32) {
             if (c < 0) {
              /* skip count */
              *p32 = c;
              p32++;
             }
             else {
              /* solid run */
              x = c;
              *p32 = c;
              p32++;

              while (x-- > 0) {
                 r = pack_getc(f);
                 g = pack_getc(f);
                 b = pack_getc(f);

                 if (rgba)
                  a = pack_getc(f);
                 else
                  a = 0;

                 *p32 = makeacol_depth(bits, r, g, b, a);

                 p32++;
              }
             }

             c = pack_igetl(f);
          }

          /* end of line */
          *p32 = eol_marker;
          p32++;
       }
       break;
   }

   destbits = _color_load_depth(bits, rgba);

   if (destbits != bits) {
      b1 = create_bitmap_ex(bits, s->w, s->h);
      if (!b1) {
       destroy_rle_sprite(s);
       *allegro_errno = ENOMEM;
       return NULL;
      }

      clear_to_color(b1, bitmap_mask_color(b1));
      draw_rle_sprite(b1, s, 0, 0);

      b2 = create_bitmap_ex(destbits, s->w, s->h);
      if (!b2) {
       destroy_rle_sprite(s);
       destroy_bitmap(b1);
       *allegro_errno = ENOMEM;
       return NULL;
      }

      blit(b1, b2, 0, 0, 0, 0, s->w, s->h);

      destroy_rle_sprite(s);
      s = get_rle_sprite(b2);

      destroy_bitmap(b1);
      destroy_bitmap(b2);
   }

   return s;
}



/* read_compiled_sprite:
 *  Reads a compiled sprite from a file, allocating memory for it.
 */
static COMPILED_SPRITE *read_compiled_sprite(PACKFILE *f, int planar, int bits)
{
   BITMAP *b;
   COMPILED_SPRITE *s;

   b = read_bitmap(f, bits, TRUE);
   if (!b)
      return NULL;

   if (!_compile_sprites)
      return (COMPILED_SPRITE *)b;

   s = get_compiled_sprite(b, planar);
   if (!s)
      *allegro_errno = ENOMEM;

   destroy_bitmap(b);

   return s;
}



/* read_old_datafile:
 *  Helper for reading old-format datafiles (only needed for backward
 *  compatibility).
 */
static DATAFILE *read_old_datafile(PACKFILE *f, void (*callback)(DATAFILE *))
{
   DATAFILE *dat;
   int size;
   int type;
   int c;

   size = pack_mgetw(f);
   if (size == EOF) {
      pack_fclose(f);
      return NULL;
   }

   dat = malloc(sizeof(DATAFILE)*(size+1));
   if (!dat) {
      pack_fclose(f);
      *allegro_errno = ENOMEM;
      return NULL;
   }

   for (c=0; c<=size; c++) {
      dat[c].type = DAT_END;
      dat[c].dat = NULL;
      dat[c].size = 0;
      dat[c].prop = NULL;
   }

   *allegro_errno = 0;

   for (c=0; c<size; c++) {

      type = pack_mgetw(f);

      switch (type) {

       case V1_DAT_FONT: 
       case V1_DAT_FONT_8x8: 
          dat[c].type = DAT_FONT;
          dat[c].dat = read_font_fixed(f, 8, OLD_FONT_SIZE);
          dat[c].size = 0;
          break;

       case V1_DAT_FONT_PROP:
          dat[c].type = DAT_FONT;
          dat[c].dat = read_font_prop(f, OLD_FONT_SIZE);
          dat[c].size = 0;
          break;

       case V1_DAT_BITMAP:
       case V1_DAT_BITMAP_256:
          dat[c].type = DAT_BITMAP;
          dat[c].dat = read_bitmap(f, 8, TRUE);
          dat[c].size = 0;
          break;

       case V1_DAT_BITMAP_16:
          dat[c].type = DAT_BITMAP;
          dat[c].dat = read_bitmap(f, 4, FALSE);
          dat[c].size = 0;
          break;

       case V1_DAT_SPRITE_256:
          dat[c].type = DAT_BITMAP;
          pack_mgetw(f);
          dat[c].dat = read_bitmap(f, 8, TRUE);
          dat[c].size = 0;
          break;

       case V1_DAT_SPRITE_16:
          dat[c].type = DAT_BITMAP;
          pack_mgetw(f);
          dat[c].dat = read_bitmap(f, 4, FALSE);
          dat[c].size = 0;
          break;

       case V1_DAT_PALETTE:
       case V1_DAT_PALETTE_256:
          dat[c].type = DAT_PALETTE;
          dat[c].dat = read_palette(f, PAL_SIZE);
          dat[c].size = sizeof(PALETTE);
          break;

       case V1_DAT_PALETTE_16:
          dat[c].type = DAT_PALETTE;
          dat[c].dat = read_palette(f, 16);
          dat[c].size = 0;
          break;

       case V1_DAT_SAMPLE:
          dat[c].type = DAT_SAMPLE;
          dat[c].dat = read_sample(f);
          dat[c].size = 0;
          break;

       case V1_DAT_MIDI:
          dat[c].type = DAT_MIDI;
          dat[c].dat = read_midi(f);
          dat[c].size = 0;
          break;

       case V1_DAT_RLE_SPRITE:
          dat[c].type = DAT_RLE_SPRITE;
          dat[c].dat = read_rle_sprite(f, 8);
          dat[c].size = 0;
          break;

       case V1_DAT_FLI:
          dat[c].type = DAT_FLI;
          dat[c].size = pack_mgetl(f);
          dat[c].dat = read_block(f, dat[c].size, 0);
          break;

       case V1_DAT_C_SPRITE:
          dat[c].type = DAT_C_SPRITE;
          dat[c].dat = read_compiled_sprite(f, FALSE, 8);
          dat[c].size = 0;
          break;

       case V1_DAT_XC_SPRITE:
          dat[c].type = DAT_XC_SPRITE;
          dat[c].dat = read_compiled_sprite(f, TRUE, 8);
          dat[c].size = 0;
          break;

       default:
          dat[c].type = DAT_DATA;
          dat[c].size = pack_mgetl(f);
          dat[c].dat = read_block(f, dat[c].size, 0);
          break;
      }

      if (*allegro_errno) {
       if (!dat[c].dat)
          dat[c].type = DAT_END;
       unload_datafile(dat);
       pack_fclose(f);
       return NULL;
      }

      if (callback)
       callback(dat+c);
   }

   return dat;
}



/* load_data_object:
 *  Loads a binary data object from a datafile.
 */
static void *load_data_object(PACKFILE *f, long size)
{
   return read_block(f, size, 0);
}



/* load_font_object:
 *  Loads a font object from a datafile.
 */
static void *load_font_object(PACKFILE *f, long size)
{
   short height = pack_mgetw(f);

   if (height > 0)
      return read_font_fixed(f, height, LESS_OLD_FONT_SIZE);
   else if (height < 0)
      return read_font_prop(f, LESS_OLD_FONT_SIZE);
   else
      return read_font(f);
}



/* load_sample_object:
 *  Loads a sample object from a datafile.
 */
static void *load_sample_object(PACKFILE *f, long size)
{
   return read_sample(f);
}



/* load_midi_object:
 *  Loads a midifile object from a datafile.
 */
static void *load_midi_object(PACKFILE *f, long size)
{
   return read_midi(f);
}



/* load_bitmap_object:
 *  Loads a bitmap object from a datafile.
 */
static void *load_bitmap_object(PACKFILE *f, long size)
{
   short bits = pack_mgetw(f);

   return read_bitmap(f, bits, TRUE);
}



/* load_rle_sprite_object:
 *  Loads an RLE sprite object from a datafile.
 */
static void *load_rle_sprite_object(PACKFILE *f, long size)
{
   short bits = pack_mgetw(f);

   return read_rle_sprite(f, bits);
}



/* load_compiled_sprite_object:
 *  Loads a compiled sprite object from a datafile.
 */
static void *load_compiled_sprite_object(PACKFILE *f, long size)
{
   short bits = pack_mgetw(f);

   return read_compiled_sprite(f, FALSE, bits);
}



/* load_xcompiled_sprite_object:
 *  Loads a mode-X compiled object from a datafile.
 */
static void *load_xcompiled_sprite_object(PACKFILE *f, long size)
{
   short bits = pack_mgetw(f);

   return read_compiled_sprite(f, TRUE, bits);
}



/* unload_sample: 
 *  Destroys a sample object.
 */
static void unload_sample(SAMPLE *s)
{
   if (s) {
      if (s->data) {
       UNLOCK_DATA(s->data, s->len * ((s->bits==8) ? 1 : sizeof(short)) * ((s->stereo) ? 2 : 1));
       free(s->data);
      }

      UNLOCK_DATA(s, sizeof(SAMPLE));
      free(s);
   }
}



/* unload_midi: 
 *  Destroys a MIDI object.
 */
static void unload_midi(MIDI *m)
{
   int c;

   if (m) {
      for (c=0; c<MIDI_TRACKS; c++) {
       if (m->track[c].data) {
          UNLOCK_DATA(m->track[c].data, m->track[c].len);
          free(m->track[c].data);
       }
      }

      UNLOCK_DATA(m, sizeof(MIDI));
      free(m);
   }
}



/* load_object:
 *  Helper to load an object from a datafile and store it in 'obj'.
 *  Returns 0 on success and -1 on failure.
 */
static int load_object(DATAFILE *obj, PACKFILE *f, int type)
{
   PACKFILE *ff;
   int d, i;

   /* load actual data */
   ff = pack_fopen_chunk(f, FALSE);

   if (ff) {
      d = ff->normal.todo;

      /* look for a load function */
      for (i=0; i<MAX_DATAFILE_TYPES; i++) {
       if (_datafile_type[i].type == type) {
          obj->dat = _datafile_type[i].load(ff, d);
          goto Found;
       }
      }

      /* if not found, load binary data */
      obj->dat = load_data_object(ff, d);

    Found:
      pack_fclose_chunk(ff);

      if (!obj->dat)
       return -1;

      obj->type = type;
      obj->size = d;
      return 0;
   }

   return -1;
}



/* _load_property:
 *  Helper to load a property from a datafile and store it in 'prop'.
 *  Returns 0 on success and -1 on failure.
 */
int _load_property(DATAFILE_PROPERTY *prop, PACKFILE *f)
{
   int type, size;
   char *p;

   type = pack_mgetl(f);
   size = pack_mgetl(f);

   prop->type = type;
   prop->dat = malloc(size+1); /* '1' for end-of-string delimiter */
   if (!prop->dat) {
      *allegro_errno = ENOMEM;
      pack_fseek(f, size);
      return -1;
   }

   /* read the property */
   pack_fread(prop->dat, size, f);
   prop->dat[size] = 0;

   /* convert to current encoding format if needed */
   if (need_uconvert(prop->dat, U_UTF8, U_CURRENT)) {
      int length = uconvert_size(prop->dat, U_UTF8, U_CURRENT);
      p = malloc(length);
      if (!p) {
       *allegro_errno = ENOMEM;
       return -1;
      }

      do_uconvert(prop->dat, U_UTF8, p, U_CURRENT, length);
      free(prop->dat);
      prop->dat = p;
   }

   return 0;
}



/* _add_property:
 *  Helper to add a new property to a property list. Returns 0 on
 *  success or -1 on failure.
 */
int _add_property(DATAFILE_PROPERTY **list, DATAFILE_PROPERTY *prop)
{
   DATAFILE_PROPERTY *iter;
   int length = 0;

   ASSERT(list);
   ASSERT(prop);

   /* find the length of the list */
   if (*list) {
      iter = *list;
      while (iter->type != DAT_END) {
       length++;
       iter++;
      }
   }

   /* grow the list */
   *list = _al_sane_realloc(*list, sizeof(DATAFILE_PROPERTY)*(length+2));
   if (!(*list)) {
      *allegro_errno = ENOMEM;
      return -1;
   }

   /* copy the new property */
   (*list)[length] = *prop;

   /* set end-of-array marker */
   (*list)[length+1].type = DAT_END;
   (*list)[length+1].dat = NULL;

   return 0;
}



/* _destroy_property_list:
 *  Helper to destroy a property list.
 */
void _destroy_property_list(DATAFILE_PROPERTY *list)
{
   int c;

   for (c=0; list[c].type != DAT_END; c++) {
      if (list[c].dat)
       free(list[c].dat);
   }

   free(list);
}



/* load_file_object:
 *  Loads a datafile object.
 */
static void *load_file_object(PACKFILE *f, long size)
{
   DATAFILE *dat;
   DATAFILE_PROPERTY prop, *list;
   int count, c, type, failed;

   count = pack_mgetl(f);

   dat = malloc(sizeof(DATAFILE)*(count+1));
   if (!dat) {
      *allegro_errno = ENOMEM;
      return NULL;
   }

   list = NULL;
   failed = FALSE;

   /* search the packfile for properties or objects */
   for (c=0; c<count;) {
      type = pack_mgetl(f);

      if (type == DAT_PROPERTY) {
       if ((_load_property(&prop, f) != 0) || (_add_property(&list, &prop) != 0)) {
          failed = TRUE;
          break;
       }
      }
      else {
       if (load_object(&dat[c], f, type) != 0) {
          failed = TRUE;
          break;
       }

       /* attach the property list to the object */
       dat[c].prop = list;
       list = NULL;

       if (datafile_callback)
          datafile_callback(dat+c);

       c++;
      }
   }

   /* set end-of-array marker */
   dat[c].type = DAT_END;
   dat[c].dat = NULL;

   /* destroy the property list if not assigned to an object */
   if (list)
      _destroy_property_list(list);

   /* gracefully handle failure */
   if (failed) {
      unload_datafile(dat);
      free(dat);
      dat = NULL;
   }

   return dat;
}



/* load_datafile:
 *  Loads an entire data file into memory, and returns a pointer to it. 
 *  On error, sets errno and returns NULL.
 */
DATAFILE *load_datafile(AL_CONST char *filename)
{
   ASSERT(filename);
   return load_datafile_callback(filename, NULL);
}



/* load_datafile_callback:
 *  Loads an entire data file into memory, and returns a pointer to it. 
 *  On error, sets errno and returns NULL.
 */
DATAFILE *load_datafile_callback(AL_CONST char *filename, void (*callback)(DATAFILE *))
{
   PACKFILE *f;
   DATAFILE *dat;
   int type;
   ASSERT(filename);

   f = pack_fopen(filename, F_READ_PACKED);
   if (!f)
      return NULL;

   if ((f->normal.flags & PACKFILE_FLAG_CHUNK) && (!(f->normal.flags & PACKFILE_FLAG_EXEDAT)))
      type = (_packfile_type == DAT_FILE) ? DAT_MAGIC : 0;
   else
      type = pack_mgetl(f);

   if (type == V1_DAT_MAGIC) {
      dat = read_old_datafile(f, callback);
   }
   else if (type == DAT_MAGIC) {
      datafile_callback = callback;
      dat = load_file_object(f, 0);
      datafile_callback = NULL;
   }
   else
      dat = NULL;

   pack_fclose(f);
   return dat; 
}



/* load_datafile_object:
 *  Loads a single object from a datafile.
 */
DATAFILE *load_datafile_object(AL_CONST char *filename, AL_CONST char *objectname)
{
   PACKFILE *f;
   DATAFILE *dat;
   DATAFILE_PROPERTY prop, *list;
   char parent[1024], child[1024], tmp[8];
   char *bufptr, *prevptr, *separator;
   int count, c, type, size, found;

   ASSERT(filename);
   ASSERT(objectname);
  
   /* concatenate to filename#objectname */
   ustrzcpy(parent, sizeof(parent), filename);

   if (ustrcmp(parent, uconvert_ascii("#", tmp)) != 0)
      ustrzcat(parent, sizeof(parent), uconvert_ascii("#", tmp));

   ustrzcat(parent, sizeof(parent), objectname);
   
   /* split into path and actual objectname (for nested files) */
   prevptr = bufptr = parent;
   separator = NULL;
   while ((c = ugetx(&bufptr)) != 0) {
      if ((c == '#') || (c == '/') || (c == OTHER_PATH_SEPARATOR))
       separator = prevptr;

      prevptr = bufptr;
   }
   
   ustrzcpy(child, sizeof(child), separator + uwidth (separator));

   if (separator == parent)
      usetc(separator + uwidth (separator), 0);
   else
      usetc(separator, 0);

   /* open the parent datafile */
   f = pack_fopen(parent, F_READ_PACKED);
   if (!f)
      return NULL;

   if ((f->normal.flags & PACKFILE_FLAG_CHUNK) && (!(f->normal.flags & PACKFILE_FLAG_EXEDAT)))
      type = (_packfile_type == DAT_FILE) ? DAT_MAGIC : 0;
   else
      type = pack_mgetl(f);

   /* only support V2 datafile format */
   if (type != DAT_MAGIC) {
      pack_fclose(f);
      return NULL;
   }

   count = pack_mgetl(f);

   dat = NULL;
   list = NULL;
   found = FALSE;

   /* search the packfile for properties or objects */
   for (c=0; c<count;) {
      type = pack_mgetl(f);

      if (type == DAT_PROPERTY) {
       if ((_load_property(&prop, f) != 0) || (_add_property(&list, &prop) != 0))
          break;

       if ((prop.type == DAT_NAME) && (ustricmp(prop.dat, child) == 0))
          found = TRUE;
      }
      else {
       if (found) {
          /* we have found the object, load it */
          dat = malloc(sizeof(DATAFILE));
          if (!dat) {
             *allegro_errno = ENOMEM;
             break;
          }

          if (load_object(dat, f, type) != 0) {
             free(dat);
             dat = NULL;
             break;
          }

          /* attach the property list to the object */
          dat->prop = list;
          list = NULL;

          break;
       }
       else {
          /* skip an unwanted object */
          size = pack_mgetl(f);
          pack_fseek(f, size+4);  /* '4' for the chunk size */

          /* destroy the property list */
          if (list) {
             _destroy_property_list(list);
             list = NULL;
          }

          c++;
       }
      }
   }

   /* destroy the property list if not assigned to an object */
   if (list)
      _destroy_property_list(list);

   pack_fclose(f);
   return dat;
}



/* _unload_datafile_object:
 *  Helper to destroy a datafile object.
 */
void _unload_datafile_object(DATAFILE *dat)
{
   int i;

   /* destroy the property list */
   if (dat->prop)
      _destroy_property_list(dat->prop);

   /* look for a destructor function */
   for (i=0; i<MAX_DATAFILE_TYPES; i++) {
      if (_datafile_type[i].type == dat->type) {
       if (dat->dat) {
          if (_datafile_type[i].destroy)
             _datafile_type[i].destroy(dat->dat);
          else
             free(dat->dat);
       }
       return;
      }
   }

   /* if not found, just free the data */
   if (dat->dat)
      free(dat->dat);
}



/* unload_datafile:
 *  Frees all the objects in a datafile.
 */
void unload_datafile(DATAFILE *dat)
{
   int i;

   if (dat) {
      for (i=0; dat[i].type != DAT_END; i++)
       _unload_datafile_object(dat+i);

      free(dat);
   }
}



/* unload_datafile_object:
 *  Unloads a single datafile object, returned by load_datafile_object().
 */
void unload_datafile_object(DATAFILE *dat)
{
   if (dat) {
      _unload_datafile_object(dat);
      free(dat);
   }
}



/* find_datafile_object:
 *  Returns a pointer to the datafile object with the given name
 */
DATAFILE *find_datafile_object(AL_CONST DATAFILE *dat, AL_CONST char *objectname)
{
   char name[512];
   int recurse = FALSE;
   int pos, c;
   ASSERT(dat);
   ASSERT(objectname);

   /* split up the object name */
   pos = 0;

   while ((c = ugetxc(&objectname)) != 0) {
      if ((c == '#') || (c == '/') || (c == OTHER_PATH_SEPARATOR)) {
       recurse = TRUE;
       break;
      }
      pos += usetc(name+pos, c);
   }

   usetc(name+pos, 0);

   /* search for the requested object */
   for (pos=0; dat[pos].type != DAT_END; pos++) {
      if (ustricmp(name, get_datafile_property(dat+pos, DAT_NAME)) == 0) {
       if (recurse) {
          if (dat[pos].type == DAT_FILE)
             return find_datafile_object(dat[pos].dat, objectname);
          else
             return NULL;
       }
       else
          return (DATAFILE*)dat+pos;
      }
   }

   /* oh dear, the object isn't there... */
   return NULL; 
}



/* get_datafile_property:
 *  Returns the specified property string for the datafile object, or
 *  an empty string if the property does not exist.
 */
AL_CONST char *get_datafile_property(AL_CONST DATAFILE *dat, int type)
{
   DATAFILE_PROPERTY *prop;
   ASSERT(dat);

   prop = dat->prop;
   if (prop) {
      while (prop->type != DAT_END) {
       if (prop->type == type)
          return (prop->dat) ? prop->dat : empty_string;

       prop++;
      }
   }

   return empty_string;
}



/* fixup_datafile:
 *  For use with compiled datafiles, to initialise them if they are not
 *  constructed and to convert truecolor images into the appropriate
 *  pixel format.
 */
void fixup_datafile(DATAFILE *data)
{
   BITMAP *bmp;
   RLE_SPRITE *rle;
   int i, c, r, g, b, a, x, y;
   int bpp, depth;
   unsigned char *p8;
   unsigned short *p16;
   uint32_t *p32;
   signed short *s16;
   int32_t *s32;
   int eol_marker;
   ASSERT(data);

   /* initialise the datafile if needed */
   if (!constructed_datafiles)
      initialise_datafile(data);

   for (i=0; data[i].type != DAT_END; i++) {

      switch (data[i].type) {

       case DAT_BITMAP:
          /* fix up a bitmap object */
          bmp = data[i].dat;
          bpp = bitmap_color_depth(bmp);

          switch (bpp) {

          #ifdef ALLEGRO_COLOR16

             case 15:
              /* fix up a 15 bit hicolor bitmap */
              if (_color_depth == 16) {
                 GFX_VTABLE *vtable = _get_vtable(16);

                 if (vtable != NULL) {
                  depth = 16;
                  bmp->vtable = vtable;
                 }
                 else
                  depth = 15;
              }
              else
                 depth = 15;

              for (y=0; y<bmp->h; y++) {
                 p16 = (unsigned short *)bmp->line[y];

                 for (x=0; x<bmp->w; x++) {
                  c = p16[x];
                  r = _rgb_scale_5[c & 0x1F];
                  g = _rgb_scale_5[(c >> 5) & 0x1F];
                  b = _rgb_scale_5[(c >> 10) & 0x1F];
                  p16[x] = makecol_depth(depth, r, g, b);
                 }
              }
              break;


             case 16:
              /* fix up a 16 bit hicolor bitmap */
              if (_color_depth == 15) {
                 GFX_VTABLE *vtable = _get_vtable(15);

                 if (vtable != NULL) {
                  depth = 15;
                  bmp->vtable = vtable;
                 }
                 else
                  depth = 16;
              }
              else
                 depth = 16;

              for (y=0; y<bmp->h; y++) {
                 p16 = (unsigned short *)bmp->line[y];

                 for (x=0; x<bmp->w; x++) {
                  c = p16[x];
                  r = _rgb_scale_5[c & 0x1F];
                  g = _rgb_scale_6[(c >> 5) & 0x3F];
                  b = _rgb_scale_5[(c >> 11) & 0x1F];
                  if (_color_conv & COLORCONV_KEEP_TRANS && depth == 15 &&
                     c == 0xf83f) g = 8; /* don't end up as mask color */
                  p16[x] = makecol_depth(depth, r, g, b);
                 }
              }
              break;

          #endif


          #ifdef ALLEGRO_COLOR24

             case 24:
              /* fix up a 24 bit truecolor bitmap */
              for (y=0; y<bmp->h; y++) {
                 p8 = bmp->line[y];

                 for (x=0; x<bmp->w; x++) {
                  c = READ3BYTES(p8+x*3);
                  r = (c & 0xFF);
                  g = (c >> 8) & 0xFF;
                  b = (c >> 16) & 0xFF;
                  WRITE3BYTES(p8+x*3, makecol24(r, g, b));
                 }
              }
              break;

          #endif


          #ifdef ALLEGRO_COLOR32

             case 32:
              /* fix up a 32 bit truecolor bitmap */
              for (y=0; y<bmp->h; y++) {
                 p32 = (uint32_t *)bmp->line[y];

                 for (x=0; x<bmp->w; x++) {
                  c = p32[x];
                  r = (c & 0xFF);
                  g = (c >> 8) & 0xFF;
                  b = (c >> 16) & 0xFF;
                  a = (c >> 24) & 0xFF;
                  p32[x] = makeacol32(r, g, b, a);
                 }
              }
              break;

          #endif

          }
          break;


       case DAT_RLE_SPRITE:
          /* fix up an RLE sprite object */
          rle = data[i].dat;
          bpp = rle->color_depth;

          switch (bpp) {

          #ifdef ALLEGRO_COLOR16

             case 15:
              /* fix up a 15 bit hicolor RLE sprite */
              if (_color_depth == 16) {
                 depth = 16;
                 rle->color_depth = 16;
                 eol_marker = MASK_COLOR_16;
              }
              else {
                 depth = 15;
                 eol_marker = MASK_COLOR_15;
              }

              s16 = (signed short *)rle->dat;

              for (y=0; y<rle->h; y++) {
                 while ((unsigned short)*s16 != MASK_COLOR_15) {
                  if (*s16 > 0) {
                     x = *s16;
                     s16++;
                     while (x-- > 0) {
                        c = *s16;
                        r = _rgb_scale_5[c & 0x1F];
                        g = _rgb_scale_5[(c >> 5) & 0x1F];
                        b = _rgb_scale_5[(c >> 10) & 0x1F];
                        *s16 = makecol_depth(depth, r, g, b);
                        s16++;
                     }
                  }
                  else
                     s16++;
                 }
                 *s16 = eol_marker;
                 s16++;
              }
              break;


             case 16:
              /* fix up a 16 bit hicolor RLE sprite */
              if (_color_depth == 15) {
                 depth = 15;
                 rle->color_depth = 15;
                 eol_marker = MASK_COLOR_15;
              }
              else {
                 depth = 16;
                 eol_marker = MASK_COLOR_16;
              }

              s16 = (signed short *)rle->dat;

              for (y=0; y<rle->h; y++) {
                 while ((unsigned short)*s16 != MASK_COLOR_16) {
                  if (*s16 > 0) {
                     x = *s16;
                     s16++;
                     while (x-- > 0) {
                        c = *s16;
                        r = _rgb_scale_5[c & 0x1F];
                        g = _rgb_scale_6[(c >> 5) & 0x3F];
                        b = _rgb_scale_5[(c >> 11) & 0x1F];
                        *s16 = makecol_depth(depth, r, g, b);
                        s16++;
                     }
                  }
                  else
                     s16++;
                 }
                 *s16 = eol_marker;
                 s16++;
              }
              break;

          #endif


          #ifdef ALLEGRO_COLOR24

             case 24:
              /* fix up a 24 bit truecolor RLE sprite */
              if (_color_depth == 32) {
                 depth = 32;
                 rle->color_depth = 32;
                 eol_marker = MASK_COLOR_32;
              }
              else {
                 depth = 24;
                 eol_marker = MASK_COLOR_24;
              }

              s32 = (int32_t *)rle->dat;

              for (y=0; y<rle->h; y++) {
                 while ((uint32_t)*s32 != MASK_COLOR_24) {
                  if (*s32 > 0) {
                     x = *s32;
                     s32++;
                     while (x-- > 0) {
                        c = *s32;
                        r = (c & 0xFF);
                        g = (c>>8) & 0xFF;
                        b = (c>>16) & 0xFF;
                        *s32 = makecol_depth(depth, r, g, b);
                        s32++;
                     }
                  }
                  else
                     s32++;
                 }
                 *s32 = eol_marker;
                 s32++;
              }
              break;

          #endif


          #ifdef ALLEGRO_COLOR32

             case 32:
              /* fix up a 32 bit truecolor RLE sprite */
              if (_color_depth == 24) {
                 depth = 24;
                 rle->color_depth = 24;
                 eol_marker = MASK_COLOR_24;
              }
              else {
                 depth = 32;
                 eol_marker = MASK_COLOR_32;
              }

              s32 = (int32_t *)rle->dat;

              for (y=0; y<rle->h; y++) {
                 while ((uint32_t)*s32 != MASK_COLOR_32) {
                  if (*s32 > 0) {
                     x = *s32;
                     s32++;
                     while (x-- > 0) {
                        c = *s32;
                        r = (c & 0xFF);
                        g = (c>>8) & 0xFF;
                        b = (c>>16) & 0xFF;
                        if (depth == 32) {
                         a = (c>>24) & 0xFF;
                         *s32 = makeacol32(r, g, b, a);
                        }
                        else
                         *s32 = makecol24(r, g, b);
                        s32++;
                     }
                  }
                  else
                     s32++;
                 }
                 *s32 = eol_marker;
                 s32++;
              }
              break;

          #endif

          }
          break;
      }
   }
}



/* initialise_bitmap:
 *  Helper used by the output from dat2s/c, for fixing up parts
 *  of a BITMAP structure that can't be statically initialised.
 */
static void initialise_bitmap(BITMAP *bmp)
{
   int i;

   for (i=0; _vtable_list[i].vtable; i++) {
      if (_vtable_list[i].color_depth == (int)(uintptr_t)bmp->vtable) {
       bmp->vtable = _vtable_list[i].vtable;
       bmp->write_bank = _stub_bank_switch;
       bmp->read_bank = _stub_bank_switch;
       bmp->seg = _default_ds();
       return;
      }
   }

   ASSERT(FALSE); 
}



/* initialise_datafile:
 *  Helper used by the output from dat2s/c, for fixing up parts
 *  of the data that can't be statically initialised.
 */
static void initialise_datafile(DATAFILE *data)
{
   int c, c2, color_flag;
   FONT *f;
   SAMPLE *s;
   MIDI *m;

   for (c=0; data[c].type != DAT_END; c++) {

      switch (data[c].type) {

       case DAT_FILE:
          initialise_datafile(data[c].dat);
          break;

       case DAT_BITMAP:
          initialise_bitmap((BITMAP *)data[c].dat);
          break;

       case DAT_FONT:
          f = data[c].dat;
          color_flag = (int)(uintptr_t)f->vtable;
          if (color_flag == 1) {
             FONT_COLOR_DATA *cf = (FONT_COLOR_DATA *)f->data;
             while (cf) {
              for (c2 = cf->begin; c2 < cf->end; c2++)
                 initialise_bitmap((BITMAP *)cf->bitmaps[c2 - cf->begin]);
              cf = cf->next;
             }
             f->vtable = font_vtable_color;
          }
          else {
             f->vtable = font_vtable_mono;
          }
          break;

       case DAT_SAMPLE:
          s = data[c].dat;
          LOCK_DATA(s, sizeof(SAMPLE));
          LOCK_DATA(s->data, s->len * ((s->bits==8) ? 1 : sizeof(short)) * ((s->stereo) ? 2 : 1));
          break;

       case DAT_MIDI:
          m = data[c].dat;
          LOCK_DATA(m, sizeof(MIDI));
          for (c2=0; c2<MIDI_TRACKS; c2++) {
             if (m->track[c2].data) {
              LOCK_DATA(m->track[c2].data, m->track[c2].len);
             }
          }
          break;
      }
   }
}



/* _construct_datafile:
 *  Constructor called by the output from dat2s/c.
 */
void _construct_datafile(DATAFILE *data)
{
   /* record that datafiles are constructed */
   constructed_datafiles = TRUE;

   initialise_datafile(data);
}



/* _initialize_datafile_types:
 *  Register my loader functions with the code in dataregi.c.
 */
#ifdef ALLEGRO_USE_CONSTRUCTOR
   CONSTRUCTOR_FUNCTION(void _initialize_datafile_types(void));
#endif

void _initialize_datafile_types(void)
{
   register_datafile_object(DAT_FILE,         load_file_object,             (void (*)(void *data))unload_datafile        );
   register_datafile_object(DAT_FONT,         load_font_object,             (void (*)(void *data))destroy_font           );
   register_datafile_object(DAT_SAMPLE,       load_sample_object,           (void (*)(void *data))unload_sample          );
   register_datafile_object(DAT_MIDI,         load_midi_object,             (void (*)(void *data))unload_midi            );
   register_datafile_object(DAT_BITMAP,       load_bitmap_object,           (void (*)(void *data))destroy_bitmap         );
   register_datafile_object(DAT_RLE_SPRITE,   load_rle_sprite_object,       (void (*)(void *data))destroy_rle_sprite     );
   register_datafile_object(DAT_C_SPRITE,     load_compiled_sprite_object,  (void (*)(void *data))destroy_compiled_sprite);
   register_datafile_object(DAT_XC_SPRITE,    load_xcompiled_sprite_object, (void (*)(void *data))destroy_compiled_sprite);
}


Generated by  Doxygen 1.6.0   Back to index