ShadowFlare's Realm
http://sfsrealm.hopto.org/cgi-bin/yabb2/YaBB.pl
ShadowFlare's Realm Forums >> Program Development >> Decompress with Java
http://sfsrealm.hopto.org/cgi-bin/yabb2/YaBB.pl?num=1223061012

Message started by Sanix on Oct 3rd, 2008, 8:10pm

Title: Decompress with Java
Post by Sanix on Oct 3rd, 2008, 8:10pm

Hi, I tried to decompress the 3.0 Data Block Header in Java.

But I get the exception "unknown compression method". Now to make sure, that I extracted the correct data:

It's a 1.22 replay with a 1.0 Header. So the 3.0 header starts at 0x44 Bytes. The compressed data length is 2703. So is it correct to decompress all bytes from 0x4C Bytes to 0x4C Bytes to 0x4C Bytes + 2703?

Title: Re: Decompress with Java
Post by Sanix on Oct 4th, 2008, 7:02pm

Can please anyone confirm, that this is correct? I tried another zlib library and got the same error, so I'm wondering, if I misunderstood the manual.

Title: Re: Decompress with Java
Post by Anomandaris. on Oct 7th, 2008, 11:46pm

Java libraries are ok with decopressing data. I had some problems too, but finally managed to do it. You probably wrongly interpreted Data Block Header


Code:
offset | size/type | Description
-------+-----------+-----------------------------------------------------------
0x0000 |  1  word  | size n of compressed data block (excluding header)
0x0002 |  1  word  | size of decompressed data block (currently 8k)
0x0004 |  1 dword  | unknown (probably checksum)
0x0008 |  n bytes  | compressed data (decompress using zlib)

first 2 words and 1 dword (8 bytes in total) doesn't belong to compressed data, you must start decompressing starting from 9th byte. And each block you decompress as separete piece of compressed data.

You can check how I did it in my parser


Code:
package anom.w3ganalizer;

import java.io.IOException;
import java.io.InputStream;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
import java.util.zip.ZipException;

/**
* This is input stream to read packed data in zlib format from replay file.
* It can read whole packed data from replay file starting from first block header's first byte.
*  
* @author Anomandaris
*
*/
public class W3GZLibFilterInputStream extends InputStream {

     private InputStream in;
     private byte[] dData;
     private int position = 0;
     private int cLength;
     private int dLength;
     private long currBlock = 0;
     private long maxBlock;
     
     /**
      * Creates new instance of stream, that will read packed data from given source stream
      * @param in stream with packed data
      * @param maxBlock number of packed blocks in stream
      */
     public W3GZLibFilterInputStream(InputStream in, long maxBlock){
           this.in = in;
           this.maxBlock = maxBlock;
     }
     
     /**
      * Returns one byte (value 0 - 255) of unpacked data, or -1 if end of stream is reached
      */
     public int read() throws IOException {
           if(position == 0) {
                 if(currBlock == maxBlock) {
                       return -1;
                 }
                 DataParser p = new DataParser(in);
                 cLength = p.getWord();                         // reads word from in
                 dLength = p.getWord();                        // reads word from in
                 p.skip(4);                                          // reads 4 bytes from in
                 byte[] cData = new byte[cLength];
                 dData = new byte[dLength];
                 int l = in.read(cData, 0, cLength);
                 if(l != cLength)
                       throw new IOException(String.format("Needs to read %d compressed bytes from input, but only %d available", cLength, l));
                 Inflater inflater = new Inflater(false);
                 inflater.setInput(cData, 0, cLength);
                 try {
                       l = inflater.inflate(dData, 0, dLength);
                 } catch (DataFormatException e) {
                       throw new ZipException("Invalid data");
                 }
                 if(l != dLength)
                       throw new ZipException(String.format("Inflated %d bytes instead of %d", l, dLength));      
           }
           int ret = dData[position];
           position++;
           if(position == dLength)
                 position = 0;
           if(ret < 0)
                 ret = 256 + ret;
           return ret;
     }      
}      

Title: Re: Decompress with Java
Post by Serrin on Nov 15th, 2008, 3:12pm

Hi,
I'm currently trying to write a parser myself and i'm a little confused by the length of the compressed data. It should be located at 0x44 bytes, right (latest version wc3 rep file)? But the word there is 0xAC0B, and the next word is 0x0020. That doesn't make sense, does it?
A word is two Bytes here, right? So the target Bytes for the compressed size would be Bytes numero 68 and 69!?
Somehow i think i got wrong  ::)

Title: Re: Decompress with Java
Post by Serrin on Nov 15th, 2008, 7:38pm

Ah i found the mistake. Didn't know that the right byte of a word corresponds to the "high" value.

ShadowFlare's Realm » Powered by YaBB 2.2.1!
YaBB © 2000-2008. All Rights Reserved.