Jump to content

LEGO Racers 2 / Drome Archive Format


JrMasterModelBuilder
 Share

Recommended Posts

JrMasterModelBuilder

I can now 100% confirm that ('DataB' when using the inf tool) the second "uint32 {4}" is the decompressed file size and 'DataB' of COMPRESS.INF is the compressed file size.

Also I believe the compression is some form of RLE compression.

Out of curiosity, how do you know this?

RLE compressions is just index based, right? Or is there more to it than that?

Link to comment
Share on other sites

  • 3 months later...
JrMasterModelBuilder

In my boredom on my lunch break at work today, I wrote this Python script to disect the gamedata.gtc files and extract them into their individual blocks of data as referenced by compress.inf. compress.inf references every single byte of gamedata.gtc * in a list of blocks, some compressed, some not **.

* Drome's GTC has 128 ASCII bytes at the end:

xa37dd45ffe100bfffcc9753aabac325f07cb3fa231144fe2e33ae4783feead2b8a73ff021fac326df0ef9753ab9cdf6573ddff0312fab0b0ff39779eaff312x
Except for the x's, it's also only hex characters. Perhaps it is a checksum? ** These blocks that aren't compressed are all the same size (131072 bytes [to find them after disection, search for files with "131072_131072" in the name]) and perhaps account for more than 1 file which might explain why there are more files listed in filelist.inf than compress.inf Anyway, here's the Python script to break down the GTC files. It automatically adapts between the LR2 and LDR formats.

#Copyright (C) JrMasterModelBuilder


import os


def disect(path):


	def uint32(data, offset):

		return data[offset] + (data[offset+1] * 256) + (data[offset+2] * 65536) + (data[offset+3] * 16777216)


	#Read in the files.

	f = open(path + os.sep + "gamedata.gtc", "rb")

	GTC = f.read()

	f.close()


	f = open(path + os.sep + "compress.inf", "rb")

	CMP = f.read()

	f.close()


	#Create a folder to save the disected files to.

	dissectPath = path + os.sep + "dissect" + os.sep

	if not os.path.exists(dissectPath):

		os.makedirs(dissectPath)


	print("Dissecting, please wait.")


	#Check if the compress.inf file is LEGO Racers 2 or LEGO Drome Racers

	if uint32(CMP, 8) == uint32(CMP, 20):

		mode = "LR2"

	else:

		mode = "LDR"


	#Loop through the compress.inf file, saving the data out of gamedata.gtc.

	offset = 0

	counter = 0	

	CMP_len = len(CMP)

	while(offset < CMP_len):

		dataA = uint32(CMP, offset)#Offset

		dataB = uint32(CMP, offset+4)#Compressed size

		dataC = uint32(CMP, offset+8)#Uncompressed size


		#Create name based on file data.

		if mode == "LR2":

			name = (dissectPath + str(counter) + "_" + str(dataA) + "_" + str(dataB)  + "_" + str(dataC) + "_" + str(uint32(CMP, offset+12)) + "_") + str(uint32(CMP, offset+16))

			offset += 20

		else:

			name = dissectPath + str(counter) + "_" + str(dataA) + "_" + str(dataB)  + "_" + str(dataC)

			offset += 12


		#Write bytes to file.

		f = open(name, "wb")

		f.write(GTC[dataA:dataA+dataC])

		f.close()


		counter += 1


	print("Dissecting complete. " + str(counter+1) + " files extracted.")	



disect("ENTER_PATH_TO_FOLDER_WITH_GAMEDATA.GTC_AND_COMPRESS.INF_HERE")


Link to comment
Share on other sites

@JMMB I have no idea what any of that means (:P), but this is awesome! :D Is there anything a non-programmer can do to help with the GTC? I only have LR2, BTW.

Also, is this anything like the INF Tool Cyrem made?

Link to comment
Share on other sites

JrMasterModelBuilder

@JMMB I have no idea what any of that means ( :P), but this is awesome! :D Is there anything a non-programmer can do to help with the GTC? I only have LR2, BTW.

Also, is this anything like the INF Tool Cyrem made?

Unfortunately, I'm still trying to figure out what there is a programmer can do next. This file format continues to baffle me at every turn. I still have no idea how the pointers in filelist.inf actually point to anything and these 131072 byte chunks/files are very peculiar (they are also the largest files contained in the GTC). Logically, it shouldn't be possible to compress every single one of the ~4,000 files in the archive, so it would seem probable that they are somehow the files that aren't compressed. How on earth they would all be the same size however, makes this all very strange. Plus, there are still more files referenced by filelist.inf than compress.inf, which makes me think that they somehow account for multiple files. Of course, if any of this is true, this is by no means an efficient way of accomplishing anything (even obfuscation).

If I come up with anything, I'll post it here.

What it does is sort-of like what Cyrem's tools does for the compress.inf files except that instead of listing out the integers, it slices up the binary data in gamedata.gtc then names them according to the integers that referenced them.

Link to comment
Share on other sites

JrMasterModelBuilder' timestamp='1338944485' post='72908']

Plus, there are still more files referenced by filelist.inf than compress.inf

This is where I began to find it harder.

Link to comment
Share on other sites

JrMasterModelBuilder

I have managed to extract some of the uncompressed files packed into the Drome archive.

Check it out (they're the menu option select and cancel sound effects):

GAME DATASOUNDSSELECT.AIF

GAME DATASOUNDSCANCEL.AIF

Here's what I've learned:

GAME DATASOUNDSSELECT.AIF & GAME DATASOUNDSCANCEL.AIF are both contained in byte block 12 (0 indexed, so the 13th block or the 1st uncompressed block) referenced by compress.inf. They start with the header FORM and are normal AIF files (the OS X Terminal file command describes them as "IFF data, AIFF audio"). Their exact offsets and sizes in gamedata.gtc are:

NAME - OFFSET - SIZE

GAME DATASOUNDSSELECT.AIF - 487424 - 60362

GAME DATASOUNDSCANCEL.AIF - 548864 - 27028

A quick comparison between filelist.inf shows some interesting information:

File Path - Data A - Data B

GAME DATASOUNDSSELECT.AIF - 1613824 - 60362

GAME DATASOUNDSCANCEL.AIF - 1675264 - 27028

Between the 2 files, there are 1087 0xC7 bytes, exactly the number of bytes filelist.inf skips over in it's pointers (1613824 + 60362 + 1078 = 1675264).

This means that Data B represents the file size of the file. However, Data A doesn't point directly to the file in the compressed GTC. Here's how the file appears to be constructed prior to compression.

[FILEBYTES]

[A bunch of 0xC7 bytes]

[FILEBYTES]

[A bunch of 0xC7 bytes]

[FILEBYTES]

[A bunch of 0xC7 bytes]

...

...

...

Then, all of that gets compressed down in block of 131072 bytes (which is the true uncompressed size of each block referenced by compress.inf) and merged together.

Now here is my proof for this theory. filelist.inf puts GAME DATASOUNDSSELECT.AIF at offset 1613824, but the actual file location is much sooner. This is because the 12 blocks before the block SELECT.AIF is in are compressed, making it appear sooner in the compressed gamedata.gtc. If those 12 blocks were 131072 in size, and we added SELECT.AIF's offset from the start of the uncompressed block it appears in, that would calculate out as follows:

131072 * 12 = 1572864 + 40960 = 1613824

Which is the exact same place filelist.inf said it would be.

So, this means that, in order for us to properly extract all of the files, we will need to first decompress every one of the compressed blocks back up to their original 131072 byte size, merge them together (as files sometimes span more than 1 block), then extract them from the information in filelist.inf.

Of course, decompressing them is easier to say than to do, but we now know that each block is compressed separately and the size they should be when decompressed. My dissection tool above breaks each of these blocks down into separate files which should make this process easier.

On the plus side, we now know for certain that we won't need to make a recompressor. We also know that at least some of the files are normal files. I can confirm that the AIF files are true AIF files, and that the IFL files are plain Windows style line feed text files. It's reasonable to assume that more of the files aren't custom files like in LEGO Racers.

I don't foresee having time to try to crack the compression algorithm in the near future, so if anyone else wants to give it a go, feel free!

Link to comment
Share on other sites

Fluffy Cupcake

That... was understandable yet still went over my head due to my lack of knowledge on this stuff. Nice work, hopefully someone can make progress with this.

Link to comment
Share on other sites

 Share

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.