Page 1 of 1

Lithtech Engine, Combat Arms

Posted: Mon Nov 30, 2009 4:04 pm
by evilpie
Hello forum,

my first post :).
I want to open .rez files of Combat Arms, but i could not found any documentation about Lithtech on your page, so i tried it myself.

I created this struct for 010 Editor, but for some reason it messes up after the 3 file.

Code: Select all

struct FILE
{
    char Header[136];
    char Unknown[75];
    int  AdressFileNames;
    FSeek (AdressFileNames);
    int Unknown;
    while (1)
    {
        struct FileInfo
        {
            int Adress;
            int Unknown1;
            int Unknown2;
            int Unknown3;
            char FileExt[8];
            char FileName[8];
        } info;
        if (Strlen (info.FileName) == 0)
            break;
    }
} file;
Cheers Evilpie

Re: Lithtech Engine, Combat Arms

Posted: Mon Nov 30, 2009 5:35 pm
by evilpie
I found my mistake, for some reason they always add 5 x 0x00-bytes behinde the null-terimnated filname.
I also made my first quickbms script :)

Note: This seems not to be the common rez file type, its only usable with combat arms, furthermore i only tested it with the eu version.

Code: Select all

IDString "\x26\x23RezMgr Version 1 Copyright (C) 1995 MONOLITH INC.           "

GoTo 211
GET offset LONG
GoTo offset
Get unknown LONG

For
	Get FileOffset LONG
	Get FileSize LONG
	Get unkown1 LONG
	Get unkown2 LONG
	Get FileExt STRING
	Get unkown3 LONG
	Get FileName STRING
	Get unkown4 LONG
	Get unkown5 BYTE
	
	If FileName == ""
		Break
	Endif
	
	
	String FileName += .
	String FileName += FileExt
	
	Log FileName FileOffset FileSize
Next

Re: Lithtech Engine, Combat Arms

Posted: Mon Nov 30, 2009 9:18 pm
by Mr.Mouse

Re: Lithtech Engine, Combat Arms

Posted: Mon Nov 30, 2009 9:36 pm
by evilpie
Attention, this really differs from the link posted "char {127} - Description/Header ", their are some extra bytes. But the rest should be the same.

Re: Lithtech Engine, Combat Arms

Posted: Sun May 07, 2017 2:13 am
by LiamMitchell
Template for 010 Hex Editor.
(I can't put it on the wiki sadly)

Code: Select all

//--------------------------------------
//--- 010 Editor v8.0 Binary Template
//
// File: Lithtech REZ File Version 1
// Author: MegaByte
// Revision: 1
// Purpose: To understand REZ Files.
//--------------------------------------
// TODO: Detect empty areas.
// TODO: Identify more parts of the Archive.
enum <unsigned int> EntryType { EntryType_File, EntryType_Directory };

local int newVersion = 1;

char[] Strrev(char input[]) {
    local char temp;
    local int len = Strlen(input);
    char output[len];
    local int halfLen = len/2;
    local int i, k;
    for(i = 0,k=len-1 ; i < halfLen+1; i++,k--)
    {
        output[k] = input[i];
        output[i] = input[k];
    }
    return output;
}

typedef struct {
    unsigned int ID;
    char Ext[8];
    string Name;
    char Pad[2];

    if (Length > 0) {
        local int oldPosition = FTell();
        FSeek(Offset);
        byte Data[Length];
        FSeek(oldPosition);
    }

} RezFileEntry <size=SizeRezFileEntry,
                name=RezFileEntry_GetName>;

char[] RezFileEntry_GetName( RezFileEntry& r )
{
    return r.Name + "." + Strrev(r.Ext);
}
int SizeRezFileEntry( RezFileEntry &r )
{
    return 14 + // Base Size + 1 byte pad.
        ReadStringLength( startof(r) + 13 , header.Max_FileName ); // Read Name length.
}

struct RezEntry;

typedef struct {
    char Name[header.Max_DirectoryName];

    // Note: May have to use a stack here if a rez file has multiple directories inside each other, not sure on scoping of local variables.
    if (Length > 0) {
        local int oldPosition = FTell();
        FSeek(Offset);
    
        // Read this directories file entries.
        while(FTell() < Offset + Length) {
            RezEntry entries <optimize=false>;
        }

        FSeek(oldPosition);
    }
} RezDirectoryEntry <size=SizeRezDirectoryEntry,
                     name=RezDirectoryEntry_GetName>;

string RezDirectoryEntry_GetName( RezDirectoryEntry& r ) {
    return r.Name;
}

int SizeRezDirectoryEntry( RezDirectoryEntry &r )
{
    return ReadStringLength( startof(r) , header.Max_DirectoryName ); // Read Name length.
}


struct RezEntry {
    EntryType Type;
    unsigned int Offset;
    unsigned int Length;
    time_t Date;

    if (Type == EntryType_File) {
        RezFileEntry file;
    } else if (Type == EntryType_Directory) {
        RezDirectoryEntry directory;
    } else {
        Warning("Unhandled RezEntry file type.");
    }

};

struct REZ {
    byte num; // 38
    byte num2; // 35
    // TODO: Assert values.

    if (num == 13 && num2 == 10) {
        newVersion = 0;
    } else if (num == 38 && num2 == 35) {
        newVersion = 1;
    } else {
        Warning( "Unknown Version encountered. Halt!" );
        return -1;
    }

    char CreatedBy[60];

    if (Strncmp(CreatedBy, "RezMgr Version 1 ", 17) != 0) {
        Warning("Expecting RezMgr Version 1 in header.");
    }
    
    byte num3;
    byte num4;
    char Description[60];

    if (newVersion) {
        FSeek(195);
    } else {
        FSeek(127);
    }


    struct Header {
        unsigned int Start_Vars;
        unsigned int Root_Offset;
        unsigned int Offset_Length;
        unsigned int Blank1;
        unsigned int Index_Offset;
        time_t Date;
        unsigned int Blank2;
        unsigned int Max_DirectoryName;
        unsigned int Max_FileName;
        unsigned int Blank;
        unsigned int Start;
    } header;

    FSeek(file.header.Root_Offset);

    RezEntry rootEntry;

} file < bgcolor=0xFF00FF>;
I also figured out the decryption / encryption for Attributes.rez :)