BLB: Difference between revisions

From MultimediaWiki
Jump to navigation Jump to search
No edit summary
(Fixed the information about the archive and resource entry formats.)
Line 12: Line 12:
  struct BLBHeader
  struct BLBHeader
  {
  {
   char szID[4];
   DWORD id1;
   BYTE bID;
   WORD id2;
  BYTE bUnknown;
   WORD extDataSize;
   WORD wDataSize;
   DWORD fileSize;
   DWORD dwFileSize;
   DWORD fileCount;
   DWORD dwNumber;
  };
  };


''szID'' -- string ID is always "\x40\x49\x00\x02".
''id1'' -- is always 0x02004940.


''bID'' -- byte ID is always 0x07.
''bID'' -- is always 0x07.


''wDataSize'' -- the size of data section of BLB file (see below).
''extDataSize'' -- the size of data section of BLB file (see below).


''dwFileSize'' -- the size of BLB file.
''fileSize'' -- the size of BLB file.


''dwNumber'' -- the number of files stored in BLB file.
''fileCount'' -- the number of files stored in BLB file.


After the header comes the array of (''dwNumber'') file IDs. Each file ID is a
After the header comes the array of (''fileCount'') file IDs. Each file ID is a
DWORD identifying a file in BLB archive.
DWORD identifying a file in BLB archive.


After the file IDs array comes the array of (''dwNumber'') directory entries.
After the file IDs array comes the array of (''fileCount'') resource entries.
Each directory entry contains the info on a file in BLB archive. Each such
Each resource entry contains the info on a file in BLB archive. Each such
entry has the following format:
entry has the following format:


  struct BLBDirEntry
  struct BLBDirEntry
  {
  {
   BYTE bType;
   BYTE type;
   BYTE bAction;
   BYTE comprType;
   WORD wDataIndex;
   WORD extDataIndex;
   DWORD dwUnknown;
   DWORD timeStamp;
   DWORD dwStart;
   DWORD offset;
   DWORD dwFileID;
   DWORD diskSize;
   DWORD dwOutSize;
   DWORD size;
  };
  };


''bType'' -- the type of the file:
''type'' -- the type of the file:
  0x07 -- sound effect,
0x02 -- sprite/graphic file
  0x08 -- music,
0x03 -- palette file
  0x0A -- video file (SMK -- Smacker video, www.smacker.com),
  0x07 -- sound effect
there're some more types, but their purpose is not so evident (e.g. 0x02
  0x08 -- music
seems to be graphic file type).
  0x0A -- video file (SMK -- Smacker video, www.smacker.com)
there're some more types, which are still to be figured out.


''bAction'' -- defines the action which should be performed for the file:
''comprType'' -- defines the compression state of the file:
  0x01 -- none: the file is non-compressed, no additional actions are required,
  0x01 -- the file is not compressed, and can be used as-is,
  0x03 -- decompress: the file is PKWARE-compressed (see below),
  0x03 -- the file is compressed using the PKWare DCL (see below),
  0x65 -- fake: the file is fake, that is no file is really present (see below).
  0x65 -- the file is a dummy, that is no file is really present (see below).


''wDataIndex'' -- the index into file data array (see below) for the byte
''extDataIndex'' -- the index into file data array (see below) for the byte
correspondent to the file.
correspondent to the file.


''dwStart'' -- the starting position of the file relative to the beginning of the
''offset'' -- the position of the file relative to the beginning of the
BLB archive.
BLB archive.


''dwFileID'' -- this field is only relevant for fake files: fake files directory
''diskSize'' -- the size of the file as it is found in the BLB archive. For non-compressed files this is the same as ''size''.
entries are just placeholders, there's no real file in the archive for the
fake file directory entry, but such entry points to some other file (perhaps,
in other BLB archive) with the file ID equal to (dwFileID) which should be
used instead of the correspondent fake file. So, fake file is a kind of alias
for other (non-fake) file. Note, that, in principle, fake file may be an
alias for another fake file, etc., but finally there should be non-fake file
in the chain of such redirections.


''dwOutSize'' -- the output size of the file:
''dwOutSize'' -- the output size of the file. For non-compressed files this is the same as ''diskSize'', for compressed files this is the size after is has been decompressed.
for non-compressed files that's just the size of the file,
for PKWARE-compressed files that's the size of decompressed file,
for fake files use the value from the directory entry of the correspondent
non-fake file.


After the array of directory entries comes the data section. This is the array
After the array of resource entries comes the data section. This is the array
of (''wDataSize'') bytes. Let's call these bytes "shifts". The shift value for
of (''extDataSize'') bytes. Let's call these bytes "shifts". The shift value for
the file may be obtained by getting the byte with index (''wDataIndex'') (see above)
the file may be obtained by getting the byte with index (''extDataIndex'') (see above)
from the file data array (indices are zero-based). If the index value is too
from the file data array (indices are zero-based). If the index value is too
large (not less than data section size (''wDataSize'')), the shift value should
large (not less than data section size (''extDataSize'')), the shift value should
be set to default (0xFF).
be set to default (0xFF).



Revision as of 21:15, 28 August 2013

Credit

The information on this page was originally based on one of the many format documents written up by Valery V. Anisimovsky, available on wotsit.org and many other sites across the internet.

BLB Resource Files

All game files of The Neverhood are stored in BLB resource files. Each BLB file has the following header:

struct BLBHeader
{
 DWORD	id1;
 WORD	id2;
 WORD	extDataSize;
 DWORD fileSize;
 DWORD fileCount;
};

id1 -- is always 0x02004940.

bID -- is always 0x07.

extDataSize -- the size of data section of BLB file (see below).

fileSize -- the size of BLB file.

fileCount -- the number of files stored in BLB file.

After the header comes the array of (fileCount) file IDs. Each file ID is a DWORD identifying a file in BLB archive.

After the file IDs array comes the array of (fileCount) resource entries. Each resource entry contains the info on a file in BLB archive. Each such entry has the following format:

struct BLBDirEntry
{
 BYTE	type;
 BYTE	comprType;
 WORD	extDataIndex;
 DWORD timeStamp;
 DWORD offset;
 DWORD diskSize;
 DWORD size;
};

type -- the type of the file:

0x02 -- sprite/graphic file
0x03 -- palette file
0x07 -- sound effect
0x08 -- music
0x0A -- video file (SMK -- Smacker video, www.smacker.com)

there're some more types, which are still to be figured out.

comprType -- defines the compression state of the file:

0x01 -- the file is not compressed, and can be used as-is,
0x03 -- the file is compressed using the PKWare DCL (see below),
0x65 -- the file is a dummy, that is no file is really present (see below).

extDataIndex -- the index into file data array (see below) for the byte correspondent to the file.

offset -- the position of the file relative to the beginning of the BLB archive.

diskSize -- the size of the file as it is found in the BLB archive. For non-compressed files this is the same as size.

dwOutSize -- the output size of the file. For non-compressed files this is the same as diskSize, for compressed files this is the size after is has been decompressed.

After the array of resource entries comes the data section. This is the array of (extDataSize) bytes. Let's call these bytes "shifts". The shift value for the file may be obtained by getting the byte with index (extDataIndex) (see above) from the file data array (indices are zero-based). If the index value is too large (not less than data section size (extDataSize)), the shift value should be set to default (0xFF).

After the file data section come files contained in BLB archive.

Decompression of PKWARE-compressed Files

I will not describe here the algorithm of PKWARE decompression. What I'll explain is the easy way you may use to access PKWARE-compressed files via PKWARE's library PKWARE.DLL. This library is supplied with GAP's BLB RF plug-in (see below).

Here's the sample C code (using Win32 API):

// decompression function -- returns zero on success
DWORD (__cdecl *Uncompress)
(
 char	*outputBuffer,
 DWORD *pOutSize,
 char	*inputBuffer,
 DWORD  dwSize
);

// first, load the library
HINSTANCE hDllInst=LoadLibrary("pkware.dll");

// get the decompression function address
Uncompress=(DWORD (__cdecl *)(char*, DWORD*, char*, DWORD))GetProcAddress(hDllInst,"Uncompress");

// decompress file -- it's assumed here that input buffer contains compressed
// file loaded from BLB archive and output buffer is allocated and has proper
// size (that is, (dwOutSize) value from the corresponding directory entry)
Uncompress(outputBuffer,&dwOutSize,inputBuffer,dwSize);

// now (outputBuffer) contains decompressed file and (dwOutSize) is set to
// decompressed file size (you should use directory entry value of output
// size for output buffer allocation)

BLBSFX Sound and Music Files

As was pointed out above, files with type bytes 0x07 and 0x08 are sound and music files. All of them are of the same format which I refer to as BLBSFX. BLBSFX file has no header, it's just compressed (or non-compressed) waveform stream. All sound/music files in The Neverhood are 16-bit mono 22050 Hz. If the shift value for the BLBSFX file is 0xFF, the file in not compressed and in this case, it's just PCM waveform stream (signed 16-bit). Otherwise, if the shift byte differs from 0xFF, BLBSFX file is compressed using DW ADPCM compression algorithm. Refer to the following section for the description of DW ADPCM decompression scheme. Note that most of sound files in The Neverhood are PKWARE-compressed, that is you should first decompress them (e.g. using PKWARE.DLL and the approach described above) and then apply DW ADPCM decompression scheme (if needed). All music files are not PKWARE-compressed, but most of them are DW ADPCM compressed.

DW ADPCM Decompression Algorithm

During the decompression SHORT variable should be maintained. Decompression uses shift value, so it should be obtained first.

Here's the code which decompresses DW ADPCM compressed BLBSFX file:

BYTE  bShift; // shift value
char *inputBuffer[dwSize];

SHORT iCurValue;
DWORD i;

iCurValue=0x0000;

for (i=0;i<dwSize;i++)
{
 iCurValue+=(signed short)inputBuffer[i];
 Output(iCurValue<<bShift);
}

Output() is just a placeholder for any action you would like to perform for decompressed sample value.

BLB Image Files

The images used in the BLB file seem to be of several different types types. One type is a 256 color bitmap, using a color palette, the other seems to be a varient of RGB332. Both files use the following 3 word header and are little endian. There is at least one other format which I have not investigated yet.

struct BLBImageFileHeader
{
 WORD	bFileType; //1A = Paletted, 12 = RGB332? 17 = Unknown.
 WORD	bXRes;
 WORD	bYRes;
};

bXRes contains the X resolution (in pixels) of the image bYRes contains the Y resolution (in pixels) of the image

Paletted graphic files

For graphics with a palette, there then follows a 256 item long array, containing the color palette used in the image.

struct BLBImageFilePaletteItem
{
 BYTE bRedValue
 BYTE bGreenValue
 BYTE bBlueValue
 BYTE bPadding //always zero.
}

The total size of the header+palette is 1030 bytes.

Then comes the pixel data. This should be exactly XRes*YRes bytes. Each byte is an index for the palette, and the color from the palette is then used to color that pixel. I.e. A pixel value of 2A means that the pixel color is that of the 42nd element in the palette array.

Non paletted graphic files

As mentioned earlier, these seem to be some form of RGB332, so far the author has been unsuccessful in converting them to bitmaps with correct color information. Seems more likely that this is paletted using the Safety Palette present in Windows.

After the header, there is simply an array of bytes of size equal to XRes*YRes that contain the value for each pixel in the file. This is assumed by the author to be RGB332 or a varient thereof, but the values could also be indexes to a windows default palette.

PC Games Using BLB

The Neverhood