Parsen einer .w3g Datei - long int returnt -858993460



  • Hi!

    Ich versuche Warcraft III Replay files auszulesen.
    Folgende kleine Anleitung zum Header einer solchen Datei:

    offset | size/type | Description
    -------+-----------+-----------------------------------------------------------
    0x0000 | 28 chars  | zero terminated string "Warcraft III recorded game\0x1A\0"
    0x001c |  1 dword  | fileoffset of first compressed data block (header size)
           |           |  0x40 for WarCraft III with patch <= v1.06
           |           |  0x44 for WarCraft III patch >= 1.07 and TFT replays
    0x0020 |  1 dword  | overall size of compressed file
    0x0024 |  1 dword  | replay header version:
           |           |  0x00 for WarCraft III with patch <= 1.06
           |           |  0x01 for WarCraft III patch >= 1.07 and TFT replays
    0x0028 |  1 dword  | overall size of decompressed data (excluding header)
    0x002c |  1 dword  | number of compressed data blocks in file
    0x0030 |  n bytes  | SubHeader (see section 2.1 and 2.2)
    
    Overall header size for version 1 is 0x44 bytes.
    

    Das ist's schon.
    Für das DWORD hab ich long int genommen (little endian...).
    Das einzige was passt ist meine Headline (die 28 chars). Der Rest returnt eben dieses -858993460 bzw. hex: cccccccc

    Hier mein Code:

    struct Header
     {
         // BITMAPFILEHEADER
    	 char[28] headline;
         dword fileoffset;
         dword sizeoffile;
         dword repheaderversion;
         dword sizeofdata;
    	 dword numcompresseddatablocks;
    	 byte subheader;
    };
    */
    #include <stdio.h>
    #include <iostream>
    
    #define DWORD 4
    
    typedef struct
    {
    	char hline[28];
    	long int fo;
    	long int sof;
    	long int rhv;
    	long int sod;
    	long int ncdb;
    
    }wtry;
    
    int main(int ac, char**av)
    {
    	wtry w3g;
    	//printf("%d\n", 0x0020-0x001c);
    	FILE * pFile;
    	pFile = fopen("name.w3g", "r");
    	if(pFile==NULL) perror ("Datei nicht gefunden");
    
    	//fseek(pFile, 0, SEEK_BEGIN);
    	fread(&w3g,1,28,pFile);
    	printf("HEADLINE: %s\n",(char *)(&w3g.hline));
    
            //now reading from the file!!!!
    	fread(&w3g.fo,sizeof(long int),1,pFile);
    	fread(&w3g.sof,sizeof(long int),1,pFile);
    	fread(&w3g.rhv,sizeof(long int),1,pFile);
    	fread(&w3g.sod,sizeof(long int),1,pFile);
    	fread(&w3g.ncdb,sizeof(long int),1,pFile);
    	//		printf("FILEOFFSET: %s\n",w3g.fileoffset);
    	printf("FILEOFFSET li: %ld\n",w3g.fo);
    	printf("FILEOFFSET li: %ld\n",w3g.sof);
    	printf("FILEOFFSET li: %ld\n",w3g.rhv);
    	printf("FILEOFFSET li: %ld\n",w3g.sod);
    	printf("FILEOFFSET li: %ld\n",w3g.ncdb);
    	printf("FILEOFFSET li: %ld\n THE NUMBERS IN HEX: \n",w3g.rhv);
    	printf("FILEOFFSET: %x\n",w3g.fo);
    	printf("FILEOFFSET: %x\n",w3g.sof);
    	printf("FILEOFFSET: %x\n",w3g.rhv);
    	printf("FILEOFFSET: %x\n",w3g.sod);
    	printf("FILEOFFSET: %x\n",w3g.ncdb);
    	system("pause");
    	return 0;
    

    Hoffe jemand kann mir helfen

    mfg XaTrIxX



  • Ich habe mir mal eine w3g-Datei aus dem Internet heruntergeladen.
    Soweit funktioniert deine Funktion bei mir schon.

    Warum verwendest du long int anstelle von unsigned int?

    Hier mal ein paar Verbesserungen:

    #include <stdio.h> 
    
    typedef unsigned int dword;
    
    typedef struct {
        char hline[28];
        dword fo;
        dword sof;
        dword rhv;
        dword sod;
        dword ncdb;
    } wtry;
    
    int main(void)
    {
        wtry w3g;
        FILE * pFile;
        pFile = fopen("ts2.w3g", "r");
    
        if (pFile==NULL) perror ("Datei nicht gefunden");
    
    /* Eine Möglichkeit die Daten einzulesen
        fread(&w3g,1,28,pFile);
        fread(&w3g.fo,sizeof(dword),1,pFile);
        fread(&w3g.sof,sizeof(dword),1,pFile);
        fread(&w3g.rhv,sizeof(dword),1,pFile);
        fread(&w3g.sod,sizeof(dword),1,pFile);
        fread(&w3g.ncdb,sizeof(dword),1,pFile);
    */
    
        /* Alternativ geht das auch so */
        fread(&w3g, sizeof(wtry), 1, pFile);
    
        printf("Headerline               : %s\n", w3g.hline);
        printf("fileoffset               : %10u   0x%x\n",w3g.fo, w3g.fo);
        printf("size of compressed file  : %10u   0x%x\n",w3g.sof, w3g.sof);
        printf("replay header version    : %10u   0x%x\n",w3g.rhv, w3g.rhv);
        printf("size of decompressed data: %10u   0x%x\n",w3g.sod, w3g.sod);
        printf("number of compressed data: %10u   0x%x\n",w3g.ncdb, w3g.ncdb);
    
        return 0;
    }
    

    Gruß mcr



  • Die Datei muß binär geöffnet werden :

    pFile = fopen("ts2.w3g", "rb");
    

    Sonst liest fread nur bis zur ersten \0 und bleibt dort "stecken".



  • merker schrieb:

    Die Datei muß binär geöffnet werden :

    pFile = fopen("ts2.w3g", "rb");
    

    Sonst liest fread nur bis zur ersten \0 und bleibt dort "stecken".

    Stimmt, die Datei sollte binär geöffnet werden. Das hatte ich auch
    zwischenzeitig so geändert gehabt. Aber der Code oben funktioniert
    bei mir auch so bei folgendem Beispiel Header:

    0000:0000 57 61 72 63 72 61 66 74 20 49 49 49 20 72 65 63 Warcraft III rec
    0000:0010 6f 72 64 65 64 20 67 61 6d 65 1a 00 44 00 00 00 orded game..D...
    0000:0020 6c b2 00 00 01 00 00 00 b2 b3 01 00 0e 00 00 00 l�......��......
    0000:0030 50 58 33 57 14 00 00 00 a4 17 00 80 69 41 05 00 PX3W....�...iA..
    0000:0040 2a 63 6c 9e 5a 0d 00 20 71 7f 2d 6e 78 01 8c 59 *cl.Z.. q.-nx..Y
    0000:0050 09 5c 54 d5 1a 3f 33 73 15 54 0c cc 64 d3 b8 c3 .\T�?3s.T.�Ӹ�
    

    Ausgabe des Programms:

    Headerline               : Warcraft III recorded game
    fileoffset               :         68   0x44
    size of compressed file  :      45676   0xb26c
    replay header version    :          1   0x1
    size of decompressed data:     111538   0x1b3b2
    number of compressed data:         14   0xe
    

    Wie du siehst, bleibt fread nicht beim '\0' hängen.

    Man-Pages zu fopen:

    Der String mode kann auch das Zeichen ``b'' enthalten, entweder als ein
           drittes  Zeichen  oder  als ein Zeichen in einem der oben beschriebenen
           Zwei-Zeichen-Strings.    Dies   ist   ausschlieBlich    Aus    Kompati-
           bilitatsgrunden zu ANSI C3.159-1989 (``ANSI C'') und hat keinen Effekt;
           das ``b'' wird ignoriert.  Linux verhalt sich evtl. nicht so.
    

    Ok, danach sollte für Ansi-C mit "rb" die Datei geöffnet werden. Dies erklärt
    dann auch, warum es bei mir geklappt hat. 😉

    Gruß mcr



  • wow, hätte ECHT nicht gedacht, dass mir dazu jemand hilft. ein großes danke. Unsigned int, alles klar.

    //Edit:
    code getestet und geht gar nicht....ich versuchs später im linux nochmal...

    So jetzt habe ich den header, aber das file geht ja noch weiter, da stehen nämlich echt massig infos drinnen.
    das nächste wär der Subheader.

    Da steht jetzt aber nicht drinnen, ob der direkt im Anschluss kommt.
    und überhaupt, soll ich dafür eine neue struct bauen? (Für header version 0 und 1 schauen die subheader anders aus)

    Dazu müsste ich wissen, was ein Word ist, wahrscheinlich sowas wie short int schätze ich.

    Hier wieder eine Kurzinfo

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    2.1 [SubHeader] for header version 0
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    
    This header was used for all replays saved with WarCraft III patch version
    v1.06 and below.
    
    offset | size/type | Description
    -------+-----------+-----------------------------------------------------------
    0x0000 |  1  word  | unknown (always zero so far)
    0x0002 |  1  word  | version number (corresponds to patch 1.xx)
    0x0004 |  1  word  | build number (see section 2.3)
    0x0006 |  1  word  | flags
           |           |   0x0000 for single player games
           |           |   0x8000 for multiplayer games (LAN or Battle.net)
    0x0008 |  1 dword  | replay length in msec
    0x000C |  1 dword  | CRC32 checksum for the header
           |           | (the checksum is calculated for the complete header
           |           |  including this field which is set to zero)
    
    Overall header size for version 0 is 0x40 bytes.
    
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    2.2 [SubHeader] for header version 1
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    
    This header is used for all replays saved with WarCraft III patch version
    v1.07 and above.
    
    offset | size/type | Description
    -------+-----------+-----------------------------------------------------------
    0x0000 |  1 dword  | version identifier string reading:
           |           |  'WAR3' for WarCraft III Classic
           |           |  'W3XP' for WarCraft III Expansion Set 'The Frozen Throne'
           |           | (note that this string is saved in little endian format
           |           |  in the replay file)
    0x0004 |  1 dword  | version number (corresponds to patch 1.xx so far)
    0x0008 |  1  word  | build number (see section 2.3)
    0x000A |  1  word  | flags
           |           |   0x0000 for single player games
           |           |   0x8000 for multiplayer games (LAN or Battle.net)
    0x000C |  1 dword  | replay length in msec
    0x0010 |  1 dword  | CRC32 checksum for the header
           |           | (the checksum is calculated for the complete header
           |           |  including this field which is set to zero)
    
    Overall header size for version 1 is 0x44 bytes.
    


  • Was geht denn bei dem von mir geposteten Code nicht?

    Ich würde für jeden SubHeader einen neuen Struct anlegen und dann in Abhängigkeit von w3g.rhv entweder den einen oder den anderen einlesen.
    Das Einlesen geht dann analog zur von mir geposten Funktion.

    Als Datentyp würde ich einen unsigned short für word nehmen.

    Ein wenig Problematisch ist dann noch der "version identifier string reading".

    Ok, dann will ich mal nicht so sein. Hier diese Auflösung:

    char visr[5] = {0};
            int i;
            for (i=0; i<4; ++i) visr[i] = ((char*) &sub.visr)[3-i];
            printf("Version id string        : %10s   0x%x\n", visr, sub.visr);
    

    sub ist bei mir von typ subheader_1 und hat an erster Stelle den Eintrag: dword visr;

    Falls du damit Probleme hast, kannst du dich ja noch mal melden.

    Gruß mcr

    PS: was möchtest du eigentlich mit deinem Programm bezwecken?

    Die Ausgabe von meinem Programm:

    Headerline               : Warcraft III recorded game
    fileoffset               :         68   0x44
    size of compressed file  :      45676   0xb26c
    replay header version    :          1   0x1
    size of decompressed data:     111538   0x1b3b2
    number of compressed data:         14   0xe
    --------- Subheader 1 ----------------
    Version id string        :       W3XP   0x57335850
    Version number           :         20   0x14
    Build number             :       6052   0x17a4
    flags                    : 0x8000
    replay length            :     344425   0x54169
    crc32                    : 0x9e6c632a
    

    Test datei: s.o.



  • Hi!

    ich schau das morgen genauer an.

    Bezwecken möcht ich damit ein Analyseprogramm.

    Eine .w3g Datei ist eine Wiederholungsdatei zum erneuten Anschauens eines Spiels.

    Man kann durch das Parsen aber ohne das Spiel zu öffnen Infos rausholen wie: Spielernamen, Spielname, Wer hat welche Aktionen gemacht, Chatlog...alles möglich.

    mfg XaTrIxX


Log in to reply