I have some files with the following extensions: .ENV .LEV .VHC

Those are from a pretty old game (1995) that is abandonware, i wanted to open them for a testing project in Unity, but i don't know what could be the real extension. After using a Hex editor, i can read some pieces of text, but I can't identify anything telling me what was the software used to create the file. I think they are models, maps, and sprites/textures.

Inside the file i found some ".TXT", ".3DW" and ".SPR".

The files are available on dropbox if someone wants to have a look at them.

  • File extensions don't mean too much when they are this generic. What software could have been used for that .TXT file? Well ... is it a plain text file, or is it something entirely else? – usr2564301 Nov 28 '16 at 21:23
  • Use binwalk if lucky you'll find the bmp headers. – tibar Nov 29 '16 at 6:41

If the game is from 1995, it's quite certain that the file format is specific to this game and the game studio that produced it. Game engines like Unity weren't a thing then; Studios wrote their software in C, maybe C++, and invented their own files and packers.

So, the "real" file format is what you're seeing; and the software used to create the file was very probably written specifically for this game and has since been long lost, especially if the game is abandonware which probably means the company behind it went defunct at some time. So, don't expect to be able to find any software these days that can read your files directly.

What you might be able to do is find out how the internal files are packed together and write some C/Perl/Python/... code to extract the .TXT, .3DW and .SPR contents, try software like file and trid if those contents are some generic format (unlikely but at least not impossible), then analyze these individual files in a hex editor to find their structure. But, as malikcjm said, it's very likely that you won't be able to read the files unless you disassemble the game binary to check how the game itself reads them, derive the file format from that, and then write some code yourself to convert that format to something modern.

If you can, you might try uploading the files somewhere and provide a link, as well as tell us which game they are from and who produced it; chances are someone who has seen similar files might recognize them.


When I download the files and compress them, the size of at least the two CITY files doesn't shrink much:

gbl@roran:~/Temp/Winrace$ ls -l
total 788
-rw-r--r-- 1 gbl users  44423 Dec  1 05:10 CITY.ENV
-rw-r--r-- 1 gbl users 242641 Dec  1 05:10 CITY1.LEV
-rw-r--r-- 1 gbl users  52720 Dec  1 05:10 MINI.VHC
-rw-r--r-- 1 gbl users 462848 Dec  1 05:10 WINRACE.EXE
gbl@roran:~/Temp/Winrace$ gzip *
gbl@roran:~/Temp/Winrace$ ls -l
total 472
-rw-r--r-- 1 gbl users  38260 Dec  1 05:10 CITY.ENV.gz
-rw-r--r-- 1 gbl users 223044 Dec  1 05:10 CITY1.LEV.gz
-rw-r--r-- 1 gbl users  26003 Dec  1 05:10 MINI.VHC.gz
-rw-r--r-- 1 gbl users 186138 Dec  1 05:10 WINRACE.EXE.gz

See how the .EXE compresses much better than the CITY* files? So it's likely those files are compressed, but with an algorithm that's a bit weaker than gzip. This would explain why you can't really find useful strings in them as well.

Now, let's check the hex dump of CITY.ENV which begins with:

00000000  43 49 54 59 2e 54 58 54 00 6b 00 00 00 a5 00 00   CITY.TXT.k......
00000010  00 03 fb 0d 0a 01 00 20 20 73 70 6f ff 74 20 31   .......  spo.t 1
00000020  20 52 55 42 42 ef 45 52 46 58 05 00 20 33 2c d7    RUBB.ERFX.. 3,.
00000030  31 37 2c 17 00 30 01 58 44 55 af 53 54 31 5f 14   17,..0.XDU.ST1_.
00000040  30 32 1d 08 35 7e 21 58 42 49 47 53 50 4c 36 08   02..5~!XBIGSPL6.
00000050  da 37 38 32 03 38 32 20 51 08 41 53 41 48 6a 00   .782.82 Q.ASAHj.
00000060  16 18 1c 10 5f 10 61 38 33 6b 08 77 41 52 4b 33   ...._.a83k.wARK3
00000070  20 36 2c 34 7a 10 03 2d 31 41 10 a2 00 43 41 52    6,4z..-1A...CAR
00000080  53 45 4c 2e 52 41 57 00 d2 6c 00 00 00 fd 00 00   SEL.RAW..l......

Obviously, there's a filename CITY.TXT at offset 0000, and another one at offset 007D. So the question is, how does the decoder know how long a file is, and where the next one starts? And how does it know how long the file name is, as they don't all have the same length?

Both of these file names end with a \0, the string terminator in C, so let's just assume this \0 doesn't have another meaning. Next is 6B000000, or 0000006B in little-endian that x86 uses, which is just a bit less than the offset of the next file name. So this might have to do with the compressed length of the file.

Checking this with the next file at 007D, we find a length of 6CD2. Adding the start of the file name to this, we get 6D4D. And indeed, a few bytes behind that, at 6D63, we have

00006d60  03 dd d5 52 55 42 42 45 52 46 58 2e 46 54 00 40   ...RUBBERFX.FT.@

the next filename.

So let's make a table - byte position of filename, filename, integer after filename, sum of byte position and integer, position of next filename, and offset that needs to be added to the sum to reach the next filename:

0000    CITY.TXT        006B    006B    007D    +0012
007D    CARSEL.RAW      6CD2    6D4D    6D63    +0016
6D63    RUBBERFX.FT     0040    6DA3    6DB8    +0015
6DB8    RUBBERFX.3DW    045F    7217    722C    +0015
722C    PSPOTFX2.TM     1CBA    8EE6    8EFA    +0014
8EFA    FDUST1_FX.FT    .....  <-- the first F might be spurious as the next file is DUST1.FX

Obviously, the assumption that these 4 bytes are the length of the compressed bytes seems to be true, even when we don't know yet why the offsets (last column) aren't constant. Doesn't seem like they have to do with the length of the filename either, as the first two differ 2 in length but 4 in the offset, and the 3rd and 4th have the same offset but different lengths.

Next, let's check the bytes behind that length byte and make another table:

0000    CITY.TXT        006B    00A5
007D    CARSEL.RAW      6CD2    FD00
6D63    RUBBERFX.FT     0040    0076
6DB8    RUBBERFX.3DW    045F    0BF0
722C    PSPOTFX2.TM     1CBA    C000

This number is always somewhat larger than the first one. As we already suspect the file is compressed, I'd think that's the uncompressed size.

So you see, you can find out some stuff from just looking at the file itself. However, the question remains why the offsets in table 1 aren't constant, and which type of compression gets used. And, this is where you need a lot of experience and/or luck. Either, you've been using compression programs 20 years ago and remember some of them and their file formats, and this looks just like on of them. (It doesn't, to me, it's neither ARC nor ZIP). Or, you need to disassemble the file and check how the code does it. Unfortunately, I'm afraid there is no other way.

  • Thank you for the detailed answer. After a scan with PEiD it says "Watcom C/C++ EXE Heuristic Mode", maybe I should start trying to disassemble it (I don't really know where to start but Google is my friend). The game is called "Big Red Racing" from Big Red Software. In case someone wants to check the files that I'm referring to, here they are (DropBox). I don't know if I should edit my question with the link to the files, it's my first time here, my apologies. – Jonathan B. Nov 29 '16 at 17:25

Well, it can be a custom format. I use the command FILE in linux to auto identify standard types, or else you can use trid on windows.


If you have this old game binary you could try to disassemble it and look for routines that handle loading files based on extension.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.