LBX is a container format created and use by the development company SimTex. It was first used in a used in a demo called Star Lords, which gave rise to Master of Orion. Later SimTex games also used the format: Master of Magic, Master of Orion 2, and 1830: Railroads & Robber Barons. The format usually contains multiple files, typically uncompressed. Though it uses a short integer to store the number of files in the header, there is only enough room to store 252 files in the offset area. It often doesn't store file names, or any reliable indication of what the contained files are for (the game is expected to know their purpose internally.) Therefore, while it is not overly difficult to pack or unpack an LBX archive, modding the game requires further knowledge of what each individual .LBX is supposed to contain.
Certain .LBX files in Master of Orion 2 are not actually .LBX archives, but rather renamed video files, so be sure to check the signature.
The header of the format is as follows:
|0||0x00||UINT16LE||Number of files in archive|
|2||0x02||BYTE||Signature (AD FE 00 00)|
|6||0x06||UINT16LE||Information about the contents|
|8||0x08||UINT32LE||Offset to file (repeats for each file stored in the LBX)|
|(last offset)||UINT32LE||Offset to end of LBX|
It is not unusual for there to be some rubbish data in between the header/index and the packaged data.
File names and descriptions may or may not follow, and even if they do exist, there may not be as many as in the offset list. File names are fixed at 8 chars, null terminated, and descriptions are 22 chars, null terminated. File names begin at offset 512 (0x200 hex) and they will last until the first file starts:
This FreeBASIC program will extract all of the files from an LBX group, and intelligently adds file names if they exist.
#include "file.bi" ' Specify the SimTex LBX file here: Dim As String LBXFileName = "portrait.lbx" Open LBXFileName For Binary As #1 ' Verify the format's magic word. Dim As UShort FileCount Dim As String MagicWord = Space(4) Dim As UShort Info Get #1, , FileCount Get #1, , MagicWord Get #1, , Info If FileCount < 1 Then Print "Contains no files.": End End If If MagicWord <> Chr(173) + Chr(254) + Chr(0) + Chr(0) Then Print "Not a SimTex .LBX file.": End End If ' Header Structure Dim As ULong FileOffsets(1 To FileCount + 1) ' +1 for the end of the file. Dim As String FileNames(1 To FileCount + 1) Dim As String FileDescriptions(1 To FileCount + 1) Dim As UByte Nul Dim As ULong File ' Load the offsets. For File = 1 To FileCount Get #1, , FileOffsets(File) Next File ' Set the last offset to the end of the file. FileOffsets(FileCount + 1) = LOF(1) ' Jump to the start of the file names sections. Seek #1, 513 ' Load the file names and descriptions. Dim As Byte EndofNames = 0 For File = 1 To FileCount ' In the LBX format, not every file has a name. It's not uncommon for there to be 6 files, but only two names. ' Because of this, this trap prevents us from reading any further than the position of the first file. If 512 + (File * 32) > FileOffsets(1) Then ' 512 is the start of the names/desc, 32 is their combined length. EndOfNames = 1 End If If EndOfNames = 0 Then ' There are more names to read. FileNames(File) = Space(8) Get #1, , FileNames(File) Get #1, , Nul ' Throw away the null-terminator. FileDescriptions(File) = Space(22) Get #1, , FileDescriptions(File) Get #1, , Nul ' Throw away the null-terminator. Else ' We've reached the end of the names section, but there may be additional files, so give each a blank name. FileNames(File) = "Unnamed " FileDescriptions(File) = Space(22) End If Next File ' Extract the files. Print "Extracting from " + LBXFileName + "..." Dim As String LBXFolder = Left(LBXFileName, InStr(LBXFileName, ".") - 1) MkDir("./" + LBXFolder) Dim As ULong FileLength Dim As ULong Addition Dim As String OutputFileName, BaseName For File = 1 To FileCount ' Determine the length of the current file by subtracting the start of the file from the next file. FileLength = FileOffsets(File + 1) - FileOffsets(File) ' Get the base name of the file (LBX files often reuse names in the same path). BaseName = Trim(FileNames(File)) If BaseName = "" Then BaseName = Trim(Str(File)) EndIf Print Using " ./\ \/\ \ - \ \ - & bytes"; LBXFolder; BaseName; FileDescriptions(File); FileLength 'Print " ./" + LBXFolder + "/" + BaseName + " - " + FileDescriptions(File) + " - " + Str(FileLength) + " bytes" ' Read the file data from the LBX. Dim FileContents(0 To (FileLength - 1)) As Byte Get #1, FileOffsets(File) + 1, FileContents() ' Check for reusing the same file name. Addition = -1 Do Addition = Addition + 1 OutputFileName = "./" + LBXFolder + "/" + BaseName + IIf(Addition > 0, "-" + Str(Addition), "") Loop While FileExists(OutputFileName) ' Output the contents of the file Open (OutputFileName) For Binary As #2 Put #2, , FileContents() Close #2 Next File Close #1 Print : Print Str(FileCount) + " file(s) extracted."
This group format was reverse engineered by Mysterioso, SaxxonPike, and TheAlmightyGuru. If you find this information helpful in a project you're working on, please give credit where credit is due. (A link back to this wiki would be nice too!)