Game Programming with DGJPP
Graphics by Lord Azathoth

Packing a Lot of Files in One
When programming a small game with few graphics and few sound effects, we have a lot of different files (.PCX, .WAV, ..) to use. How about use only one file?

How about packing
The target of the 'packer' is very simple: insert all the different sorts of files (images, sounds, ..) in only one file. So we can use a file with a lot of records with variable size to contain all the data. I think to have a header of the file like this:

struct PACKHEADER {
   char  type[2];           // Signature of the packer. Must be 'PK'
   BYTE  version;           // Version of the pack
   DWORD offset;            // Offset of the data from the beginning of the file
   DWORD counter;           // Number of record in the file
   char  autor[10];         // Autor of the pack
   char  program[15];       // Title of the program that use the pack
   char  fill[FILL_LENGTH]; // Fill to 64 bytes
};
The offset and the fill fields are used to reserve space for future implementations of the packer.

For the data we can use a record like this (followed by the data itself):


struct DATAHEADER {
   char  name[15]; 	// Name of the data
   BYTE  type; 		// Type of data
   WORD  counter; 	// Number of records
   DWORD size; 		// Size of the data
};
With name we can identify the data informations in the file. This field can't be duplicated! The type field identify the type of data that follow the record ( image, sound, game level, ..). The counter field contain the number of records registered in the data. For have the size of one record, divide size by counter.

Insert and delete records
For insert data in the file we should read all the records and check if another record with the same name is present for prevent duplications. We need the name, a pointer to the data and the size of the data information for insert a record in the packer. There are a good implementation of the insert algorithm:

// Insert general data information
BOOL pack_insert_data(char *filename, char *name, int size, void *data)
{
   BOOL ret;
   FILE *stream;
   int position;
   struct PACKHEADER packheader;
   struct DATAHEADER dataheader;

   // Open the file and check the signature
   if((stream=fopen(filename, "rb+"))==NULL) return(PACK_OPEN);
   if(fread(&packheader, sizeof(struct PACKHEADER), 1, stream)!=1) {
      fclose(stream);
      return(PACK_READ);
   }
   if(packheader.type[0]!='P'||packheader.type[1]!='K') {
      fclose(stream);
      return(PACK_INVALID);
   }

   // Look for records with the same name
   if(strlen(name)>14) name[14]='\x0';
   for(;;) {
      position=filelength(fileno(stream));
      if(fread(&dataheader, sizeof(struct DATAHEADER), 1, stream)!=1) break;
      if(!strcmp(dataheader.name, name)) {
         fclose(stream);
         return(PACK_DUP);
      }

      // Ignore the data
      fseek(stream, dataheader.size, SEEK_CUR);
   }

   fflush(stream);
   fseek(stream, filelength(fileno(stream)), SEEK_SET);
   // Fill the DATAHEADER structure and write it to the file
   strncpy(dataheader.name, name, 14); dataheader.name[14]='\x0';
   dataheader.type=TYPE_IMAGES;
   dataheader.counter=0;
   dataheader.size=size;
   if(fwrite(&dataheader, sizeof(struct DATAHEADER), 1, stream)!=1) {
      fclose(stream);
      return(PACK_WRITE);
   }

   // Write the data
   if(fwrite(data, size, 1, stream)!=1) {
      fclose(stream);
      return(PACK_WRITE);
   }

   // Update the packheader
   packheader.counter++;
   fseek(stream, 0, SEEK_SET);
   if(fwrite(&packheader, sizeof(struct PACKHEADER), 1, stream)!=1) {
      fclose(stream);
      return(PACK_WRITE);
   }

   fclose(stream);
   return(PACK_OK);
}
For deleting a record we should use a swap file where we copy all the records without the one that we want to delete. Look the demo program for the code implementation.




[main] [prec] [next] [email]

Site Made and Maintained by The Dark Angel <DarkAngel@tin.it>
My ICQ Number is 2063026
You Visited This Page times


This page hosted by Geocities Icon Get your own Free Home Page