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
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.