package tk.captainsplexx.Maths; import java.nio.ByteOrder; import java.util.ArrayList; import tk.captainsplexx.Resource.FileHandler; import tk.captainsplexx.Resource.FileSeeker; import tk.captainsplexx.Resource.CAS.CasDataReader; public class Patcher { public static byte[] getPatchedData(byte[] decompressedBase, byte[] delta){ if (decompressedBase.length == 0 || delta.length == 0){ System.err.println("Could not patch data, because of 0 length."); return null; } /*FileHandler.writeFile("output/debug/patchType2_base", decompressedBase); FileHandler.writeFile("output/debug/patchType2_delta", delta); */ int type = 0; int procSize = 0; int patchedSize = 0; int offset = 0; int removeBytes = 0; int addBytes = 0; FileSeeker baseSeeker = new FileSeeker("BASE in PATCHER"); FileSeeker deltaSeeker = new FileSeeker("DELTA in PATCHER"); ArrayList<Byte> patchedData = new ArrayList<>(); type = FileHandler.readShort(delta, deltaSeeker, ByteOrder.BIG_ENDIAN);// Type 0x2000 if its not compressed. 0x1000 if its compressed. if (type==0x1000){ int numEntries = FileHandler.readShort(delta, deltaSeeker, ByteOrder.BIG_ENDIAN); byte[] compressedDelta = null; for (int i=0; i<numEntries; i++){ /*get entry information*/ offset = FileHandler.readShort(delta, deltaSeeker, ByteOrder.BIG_ENDIAN); removeBytes = FileHandler.readShort(delta, deltaSeeker, ByteOrder.BIG_ENDIAN); if (deltaSeeker.hasError()){return null;} /*fill up to offset*/ while(baseSeeker.getOffset()<offset){ patchedData.add(FileHandler.readByte(decompressedBase, baseSeeker)); if (baseSeeker.hasError()){return null;} } /*take a look into block logic to obtain the compressed size*/ deltaSeeker.seek(6);//4 bytes decompressed size, 2 bytes type compressedDelta = new byte[FileHandler.readShort(delta, deltaSeeker, ByteOrder.BIG_ENDIAN)+8/*compressed size is without header, so add decompsize, type and compressedsize to it!*/]; if (deltaSeeker.hasError()){return null;} /*go back the beginning of the block logic and fill up the byte array*/ deltaSeeker.seek(-8); int seekerOffset = deltaSeeker.getOffset(); for (int ix=0; ix<compressedDelta.length; ix++){ int index = ix+seekerOffset; compressedDelta[ix] = delta[index]; deltaSeeker.seek(1); } /*decompress the extracted block logic and add it to return data.*/ byte[] rawBlock = CasDataReader.convertToRAWData(compressedDelta); if (rawBlock==null||!FileHandler.addBytes(rawBlock, patchedData)){return null;} /*skip bytes from base, defined by entry information*/ baseSeeker.seek(removeBytes); } return FileHandler.convertFromList(patchedData); }else if (type==0x2000){ procSize = FileHandler.readShort(delta, deltaSeeker, ByteOrder.BIG_ENDIAN); patchedSize = FileHandler.readShort(delta, deltaSeeker, ByteOrder.BIG_ENDIAN); // (CONTAINS PATCHED SIZE) int procOffset = deltaSeeker.getOffset(); byte basedata = 0; byte deltadata = 0; //fill spaces - patch data while(deltaSeeker.getOffset()<procOffset+procSize){ //*MAY USING LEB128 (DOES EVEN BIG_END. ENCODING EXIST ?)*// offset = FileHandler.readShort(delta, deltaSeeker, ByteOrder.BIG_ENDIAN)&0xFFFF; removeBytes = FileHandler.readByte(delta, deltaSeeker)&0xFF; addBytes = FileHandler.readByte(delta, deltaSeeker)&0xFF; //System.out.println("Offset: "+offset+" Rem: "+removeBytes+" Add: "+addBytes); //filldata up to offset while(baseSeeker.getOffset()<offset){ basedata = FileHandler.readByte(decompressedBase, baseSeeker); if (!baseSeeker.hasError()){ patchedData.add(basedata); }else{ System.err.println("Error while patching, can't fill up bytes. (maybe out of bounds)"); dump(decompressedBase, delta); return null; } } //remove baseSeeker.seek(removeBytes); //add for (int patchIndex=0; patchIndex<addBytes; patchIndex++){ deltadata = FileHandler.readByte(delta, deltaSeeker); if (!deltaSeeker.hasError()){ patchedData.add(deltadata); }else{ dump(decompressedBase, delta); System.err.println("Error while patching, can't get delta bytes. (maybe out of bounds)"); return null; } } } //fill up left over data if (patchedData.size()<patchedSize){ if (baseSeeker.getOffset() < decompressedBase.length){ while (baseSeeker.getOffset() < decompressedBase.length){ basedata = FileHandler.readByte(decompressedBase, baseSeeker); if (!baseSeeker.hasError()){ patchedData.add(basedata); }else{ System.err.println("Error while patching, can't fill up the ---leftover--- bytes. (maybe out of bounds)"); dump(decompressedBase, delta); return null; } } }else{ dump(decompressedBase, delta); System.err.println("Patched size is smaller as given one :( ["+patchedData.size()+"/"+patchedSize+"]"); return null; } } if (baseSeeker.hasError() || deltaSeeker.hasError()){ dump(decompressedBase, delta); return null; } return FileHandler.convertFromList(patchedData); } System.out.println("Type "+type+" is not known inside Patcher!"); return null; } static private void dump(byte[] decompressedBase, byte[] delta){ FileHandler.writeFile("output/debug/base_in_patcher", decompressedBase); FileHandler.writeFile("output/debug/delta_in_patcher", delta); } }