-
-
Save anonymous/7332f966c4f4d5e26d5e to your computer and use it in GitHub Desktop.
C4Group reader in Java, still needs Packing/Unpacking but has the main magic done
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package de.beheh.lorry; | |
import java.io.BufferedInputStream; | |
import java.io.ByteArrayInputStream; | |
import java.io.ByteArrayOutputStream; | |
import java.io.DataInputStream; | |
import java.io.File; | |
import java.io.FileInputStream; | |
import java.io.FileNotFoundException; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.util.BitSet; | |
import java.util.Date; | |
import java.util.zip.Inflater; | |
/** | |
* | |
* @author benedict | |
*/ | |
public class C4Group { | |
/* C4Group Constants */ | |
private static final int C4GROUP_HEADER_LENGTH = 204; | |
private static final int C4GROUP_VERSION1 = 0x01; | |
private static final int C4GROUP_VERSION2 = 0x02; | |
private static final int INFLATE_BUFFER_SIZE = 1024; | |
/* C4Group Pointer*/ | |
File group; | |
DataInputStream groupStream; | |
/* C4GroupHeader Values */ | |
String groupAuthor = null; | |
int groupChildCount = 0; | |
int groupCreation = 0; | |
Date groupModified = null; | |
boolean groupIsOriginal = false; | |
/** | |
* | |
* @param path | |
* @throws FileNotFoundException | |
*/ | |
public C4Group(String path) throws FileNotFoundException { | |
this(new File(path)); | |
} | |
/** | |
* | |
* @param group | |
* @throws FileNotFoundException | |
*/ | |
public C4Group(File group) throws FileNotFoundException { | |
this.group = group; | |
groupStream = new DataInputStream(new BufferedInputStream(new FileInputStream(group))); | |
try { | |
if(groupStream.read() != 0x1e || groupStream.read() != 0x8c) { | |
throw new Exception("file is not a c4group"); | |
} | |
/* Gzip header */ | |
groupStream.read(); //compression method | |
BitSet flags = ByteConverter.byteToBitSet((byte) groupStream.read()); //flags | |
groupStream.readInt(); | |
readBytes(groupStream, 1); //xfl | |
groupStream.readByte(); //os, should be 11 = ntfs for c4groups | |
/* deflated Body */ | |
Inflater inflater = new Inflater(true); | |
ByteArrayOutputStream inflatedData = new ByteArrayOutputStream(); | |
while(!inflater.finished()) { | |
while(inflater.needsInput()) { | |
byte[] buffer = new byte[INFLATE_BUFFER_SIZE]; | |
groupStream.mark(1024); | |
groupStream.read(buffer); | |
inflater.setInput(buffer); | |
} | |
byte[] inflatedBuffer = new byte[INFLATE_BUFFER_SIZE]; | |
int length = inflater.inflate(inflatedBuffer); | |
inflatedData.write(inflatedBuffer, 0, length); | |
} | |
int remaining = inflater.getRemaining(); | |
inflater.end(); | |
//FileOutputStream f = new FileOutputStream("/home/benedict/c4group.hex"); | |
//f.write(scramble(inflatedData.toByteArray())); | |
LittleEndianDataInputStream groupData = new LittleEndianDataInputStream(new ByteArrayInputStream(scramble(inflatedData.toByteArray()))); | |
inflatedData.close(); | |
/* Gzip footer */ | |
groupStream.reset(); | |
groupStream.skip(INFLATE_BUFFER_SIZE - remaining); | |
//@TODO footer | |
groupStream.close(); | |
/* C4GroupHeader */ | |
if(!new String(readBytes(groupData, 25)).equals("RedWolf Design GrpFolder ")) { | |
throw new Exception("invalid c4group version"); | |
} | |
groupData.skip(3); //reserved | |
int groupVersion1 = groupData.readLittleEndianInt(); | |
int groupVersion2 = groupData.readLittleEndianInt(); | |
if(groupVersion1 != C4GROUP_VERSION1 || groupVersion2 != C4GROUP_VERSION2) { | |
throw new Exception("incorrect c4group version (found " + groupVersion1 + "." + groupVersion2 + ", expected " + C4GROUP_VERSION1 + "." + C4GROUP_VERSION2 + ")"); | |
} | |
groupChildCount = groupData.readLittleEndianInt(); | |
groupAuthor = new String(readBytes(groupData, 32)); | |
groupData.skip(32); //reserved | |
groupModified = new Date((long) groupData.readLittleEndianInt() * 1000); | |
groupIsOriginal = (groupData.readLittleEndianInt() == 1234567) ? true : false; | |
groupData.skip(92); //reserved | |
/*for(int i = 0; i < groupChildCount; i++) { | |
System.out.println(new String(readBytes(groupData, 257))); | |
readBytes(groupData, 59); | |
}*/ | |
groupData.close(); | |
} catch(Exception ex) { | |
ex.printStackTrace(System.err); | |
} | |
} | |
/** | |
* Scrambles the according to the Clonk source code. | |
* | |
* @param input the input to scramble | |
* @return the scrambled bytes | |
*/ | |
private byte[] scramble(byte[] input) { | |
int i; | |
byte tmp; | |
for(i = 0; i < C4GROUP_HEADER_LENGTH; i++) { | |
input[i] ^= 237; | |
} | |
for(i = 0; (i + 2) < C4GROUP_HEADER_LENGTH; i += 3) { | |
tmp = input[i]; | |
input[i] = input[i + 2]; | |
input[i + 2] = tmp; | |
} | |
return input; | |
} | |
public String getAuthor() { | |
return groupAuthor; | |
} | |
public boolean isOriginal() { | |
return groupIsOriginal; | |
} | |
private byte[] readBytes(InputStream read, int length) throws IOException { | |
byte[] bytes = new byte[length]; | |
for(int i = 0; i < length; i++) { | |
bytes[i] = (byte) read.read(); | |
} | |
return bytes; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment