package tk.captainsplexx.Resource.EBX; import java.nio.ByteOrder; import java.util.ArrayList; import java.util.HashMap; import tk.captainsplexx.Resource.FileHandler; import tk.captainsplexx.Resource.FileSeeker; public class EBXCreator { private EBXHeader header; private ArrayList<Byte> headerBytes; // private FileSeeker headerByteSeeker; private ArrayList<EBXExternalGUID> externalGUIDs; private ArrayList<Byte> externalGUIDBytes; // private FileSeeker externalGUIDByteSeeker; private ArrayList<String> names; private ArrayList<Byte> nameBytes; // private FileSeeker nameByteSeeker; private ArrayList<EBXFieldDescriptor> fieldDescriptors; private ArrayList<Byte> fieldDescriptorBytes; // private FileSeeker fieldDescriptorByteSeeker; private ArrayList<EBXComplexDescriptor> complexDescriptors; private ArrayList<Byte> complexDescriptorBytes; // private FileSeeker complexDescriptorByteSeeker; private ArrayList<EBXInstanceRepeater> instanceRepeaters; private ArrayList<Byte> instanceRepeaterBytes; // private FileSeeker instanceRepeaterByteSeeker; private ArrayList<EBXArrayRepeater> arrayRepeaters; private ArrayList<Byte> arrayRepeaterBytes; // private FileSeeker arrayRepeaterByteSeeker; private ArrayList<String> strings; private ArrayList<Byte> stringBytes; // private FileSeeker stringByteSeeker; private ArrayList<Byte> payloadData; // private FileSeeker payloadDataSeeker; private ArrayList<Byte> arrayPayloadData; private ArrayList<ArrayList<Byte>> finalDataArrays; private ArrayList<Byte> filler = new ArrayList<>(); private ArrayList<String> internalGUIDs; private boolean firstRun = true; public void init(){ firstRun = false; finalDataArrays = new ArrayList<>(); headerBytes = new ArrayList<>(); externalGUIDBytes = new ArrayList<>(); nameBytes = new ArrayList<>(); fieldDescriptorBytes = new ArrayList<>(); complexDescriptorBytes = new ArrayList<>(); instanceRepeaterBytes = new ArrayList<>(); arrayRepeaterBytes = new ArrayList<>(); stringBytes = new ArrayList<>(); payloadData = new ArrayList<>(); arrayPayloadData = new ArrayList<>(); header = new EBXHeader(); names = new ArrayList<>(); externalGUIDs = new ArrayList<>(); fieldDescriptors = new ArrayList<>(); complexDescriptors = new ArrayList<>(); instanceRepeaters = new ArrayList<>(); arrayRepeaters = new ArrayList<>(); strings = new ArrayList<>(); internalGUIDs = new ArrayList<>(); } public byte[] createEBX(EBXFile ebxFile){ if (firstRun){ init(); } //TODO if (false&&filler.isEmpty()){ filler.add((byte) 0xAA); filler.add((byte) 0xAA); filler.add((byte) 0xAA); filler.add((byte) 0xAA); filler.add((byte) 0xBB); filler.add((byte) 0xBB); filler.add((byte) 0xBB); filler.add((byte) 0xBB); filler.add((byte) 0xAA); filler.add((byte) 0xAA); filler.add((byte) 0xAA); filler.add((byte) 0xAA); filler.add((byte) 0xBB); filler.add((byte) 0xBB); filler.add((byte) 0xBB); filler.add((byte) 0xBB); } header.setNumGUIDRepeater(0); //NOTE - TRUEFILENAME does actually not exist, it uses the String value of the first 'Name' field in the primaryInstance boolean isPrimaryInstance = true; for (EBXInstance instance : ebxFile.getInstances()){ proccInternalGUID(instance.getGuid());//register guid's first! } for (EBXInstance instance : ebxFile.getInstances()){ if (!proccInstance(instance, isPrimaryInstance)){ System.err.println("Couldn't processing EBXInstance. GUID: "+instance.getGuid()); } isPrimaryInstance = false; } writeFieldDescriptors(); writeComplexDescriptors(); writeInstanceRepeaters(); /*DEBUG*///FileHandler.writeFile("output/ebxInstanceRepeater_part", FileHandler.toByteArray(instanceRepeaterBytes)); writeArrayRepeaters(); writeExternalGUIDs(); writeNames(); /*DEBUG*///FileHandler.writeFile("output/ebxNames_part", FileHandler.toByteArray(nameBytes)); int stringOffset = calcStringOffset(); while (stringOffset%16!=0){//TODO temp testing arrayRepeaterBytes.add((byte) 0x00);//line padding stringOffset = calcStringOffset(); } header.setAbsStringOffset(stringOffset); writeStrings(); payloadData.add((byte) 0x00);//add one line at least ? while (payloadData.size()%16!=0){ payloadData.add((byte) 0x00); } while (arrayPayloadData.size()%16!=0){ arrayPayloadData.add((byte) 0x00); } int fileSize = stringOffset + stringBytes.size() + payloadData.size() + arrayPayloadData.size(); header.setLenStringToEOF(fileSize - stringOffset); header.setLenPayload(payloadData.size()); writeHeader();//needs extend by payload! 4bytes fourCC + 36bytes FileHandler.addBytes(FileHandler.hexStringToByteArray(ebxFile.getGuid()), headerBytes); //+16Bytes GUID for (int i=0; i<8;i++){ headerBytes.add((byte) 0x00);//+8Bytes padding }/*TOTAL HEADER SIZE = 64Bytes*/ finalDataArrays.add(headerBytes); finalDataArrays.add(filler);//TEST finalDataArrays.add(externalGUIDBytes); finalDataArrays.add(filler);//TEST finalDataArrays.add(nameBytes); finalDataArrays.add(filler);//TEST finalDataArrays.add(fieldDescriptorBytes); finalDataArrays.add(filler);//TEST finalDataArrays.add(complexDescriptorBytes); finalDataArrays.add(filler);//TEST finalDataArrays.add(instanceRepeaterBytes); finalDataArrays.add(filler);//TEST finalDataArrays.add(arrayRepeaterBytes); finalDataArrays.add(filler);//TEST finalDataArrays.add(stringBytes); finalDataArrays.add(filler);//TEST finalDataArrays.add(payloadData); finalDataArrays.add(filler);//TEST finalDataArrays.add(arrayPayloadData); byte[] data = FileHandler.toBytes(finalDataArrays); init(); //as cleanUp! return data; } private int calcStringOffset(){ return /*headerBytes.size()*/ 64 + externalGUIDBytes.size() + nameBytes.size() + fieldDescriptorBytes.size() + complexDescriptorBytes.size() + instanceRepeaterBytes.size() + arrayRepeaterBytes.size(); } public boolean proccInstance(EBXInstance ebxInstance, boolean isPrimaryInstance){ while(payloadData.size()%16!=0){//TODO its aligned in original one, how does the size get effected ? payloadData.add((byte) 0x00); } String guid = ebxInstance.getGuid(); if (guid.length()>15){ FileHandler.addBytes(FileHandler.hexStringToByteArray(ebxInstance.getGuid()), payloadData); header.setNumGUIDRepeater(header.getNumGUIDRepeater()+1); } if (!isPrimaryInstance){ for (int i=0; i<8;i++){ payloadData.add((byte) 0x00); } } //obfuscationShift. shift by 8 ?? #alignment 4 instances require subtracting 8 for all field offsets and the complex size short index = proccComplex(ebxInstance.getComplex(), false/*isArrayMember*/, true/*proccFieldDesc*/, false/*hasNoPayload*/); EBXInstanceRepeater repeater = new EBXInstanceRepeater(index, 0); /*sow, id clud be �tha we cud makke a repeatzer 4 eavery one yoooo, in the original one as it always 0. we should be fine with that.*/ instanceRepeaters.add(repeater); return true; } public short proccComplex(EBXComplex ebxComplex, boolean isArrayMember, boolean proccDescriptor, boolean hasNoPayload){ //return index of complex //TODO boolean isAligned = false; while(payloadData.size()%16>=12){//TODO complex gets aligned, but why ? payloadData.add((byte) 0x00); } if (payloadData.size()%16==0){ isAligned = true; } int startOffset = payloadData.size(); int totalSize = 0; //its acc. a short but wanna have a use for secondary size ^__^ for (EBXField field : ebxComplex.getFields()){ int fieldSize = proccField(field, isArrayMember, proccDescriptor, hasNoPayload); if(fieldSize>=0){ totalSize += fieldSize; }else{ System.err.println("Couldn't processing EBXComplex's field! Name: "+field.getFieldDescritor().getName()); } } int payloadTotalSize = payloadData.size()-startOffset; //while(payloadData.size()%16>=12&&payloadTotalSize>=12&&payloadTotalSize<16){<-Worked really well //while((payloadData.size()%16>=12&&payloadTotalSize>=12&&payloadTotalSize<16)||(payloadTotalSize>32&&payloadData.size()%16>=12)){ while((payloadData.size()%16>=12&&payloadTotalSize>=12&&payloadTotalSize<16)||(payloadTotalSize>32&&payloadData.size()%16>=12)){//TODO fields after complex gets SOMETIMES aligned too, but why ? payloadData.add((byte) 0x00); payloadTotalSize++; } return proccComplexDescriptor(ebxComplex.getComplexDescriptor(), ebxComplex.getFields().length, totalSize); } public short proccComplexDescriptor(EBXComplexDescriptor desc, Integer numFields, int totalSize){ //return index //TODO desc.setFieldStartIndex(fieldDescriptors.size()-numFields); desc.setSize((short) totalSize); desc.setSecondarySize((short) (totalSize>>16 & 0xFFFF)); //?? maybe ?? desc.setNumField((char) (numFields & 0xFF)); //PAYLOAD ?? complexDescriptors.add(desc); return (short) (complexDescriptors.size()-1); } public boolean proccFieldDescriptor(EBXFieldDescriptor desc){ //TODO desc.setOffset(offset); obfuscationShift ?? //PAYLOAD ?? fieldDescriptors.add(desc); return true; } public int proccField(EBXField ebxField, boolean isArrayMember, boolean proccDescriptor, boolean hasNoPayload){ ArrayList<Byte> targetList = null; if (isArrayMember){ targetList = arrayPayloadData; }else{ targetList = payloadData; } EBXFieldDescriptor desc = ebxField.getFieldDescritor(); byte[] data = null; if (ebxField.getType()!=null){//if newly added with TreeView, it does not have a type as SHORT) switch (ebxField.getType()) { case ArrayComplex: desc.setType((short) 0x0041); break; case Bool: desc.setType((short) 0xc0ad); break; case Byte: desc.setType((short) 0xc0cd); break; case ChunkGuid: desc.setType((short) 0xC15D); break; case Complex: desc.setType((short) 0x0029);//OR WHATEVER ?? break; case Enum: desc.setType((short) 0x0089); break; case ExternalGuid: desc.setType((short) 0x0035); break; case Float: desc.setType((short) 0xC13D); break; case Guid: desc.setType((short) 0x0035); //same as external ID! break; case Hex8: desc.setType((short) 0x417D); break; case Integer: desc.setType((short) 0xc0fd); break; case Short: desc.setType((short) 0xc0ed); break; case String: desc.setType((short) 0x407D);//OR WHATEVER ?? break; case UInteger: desc.setType((short) 0xc10d); break; case Unknown: desc.setType((short) 0xFFFF);//ERROR break; } } short h = ebxField.getFieldDescritor().getType(); if (h==0xFFFF){ System.err.println("Unknown type!"); //DEFUQ ? }else if(h==(short)0x407D||h==(short)0x409D){ //_________________________________________________________________________________STRING if (ebxField.getValue()!=null){ String val = (String) ebxField.getValue(); if (val.contains("*nullString*")){ data = new byte[] {(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF}; }else{ int relOffset = 0; for (String s : strings){ relOffset += s.length()+1; } strings.add(val); data = FileHandler.toBytes((int) relOffset, ByteOrder.LITTLE_ENDIAN); } FileHandler.addBytes(data, targetList); } }else if(h==(short)0xC13D){//_____________________________________________________________________________________________FLOAT if (ebxField.getValue()!=null){ data = FileHandler.toBytes((float) ebxField.getValue(), ByteOrder.BIG_ENDIAN); FileHandler.addBytes(data, targetList); } }else if(h==(short)0x0029||h==(short)0xd029||h==(short)0x8029){//_______________________________________________________________________COMPLEX //data = new byte[] {0x00, 0x00, 0x00, 0x00}; //FileHandler.addBytes(data, payloadData);//?? what is the value/size ?? //TODO short index = proccComplex(ebxField.getValueAsComplex(), isArrayMember, proccDescriptor, hasNoPayload); if (index==-1){ return -1; } desc.setRef(index); }else if (h==(short)0xC089||h==(short)0x0089){//_________________________________________________________________________________ENUM //TODO NEEDS WORK IN TCF, SELECTED INDEX FAIL. if (ebxField.getValue() instanceof String){ System.err.println("NULL ENUM (STRING)"); EBXComplexDescriptor enumComplexDesc = new EBXComplexDescriptor( "$", //name 0, (char) (0),//numFields <-0 == nullENUM (char) 4,//TODO alignment (short) 0x0,//type (short) 0x0,//size (short)0x0//secondarySize ); complexDescriptors.add(enumComplexDesc);//add directly because proccComplexDescr. contains size methods desc.setRef((short) (complexDescriptors.size()-1));//TODO -1 ?? data = FileHandler.toBytes(0, ByteOrder.LITTLE_ENDIAN); if (ebxField.getValue()!=null){//for hasEmtyPayload FileHandler.addBytes(data, targetList); } }else if(ebxField.getValue() instanceof HashMap<?, ?>){//EBXFieldDescriptor, Boolean HashMap<EBXFieldDescriptor, Boolean> enumList = (HashMap<EBXFieldDescriptor, Boolean>) ebxField.getValue(); int selectedIndex = -1; boolean treeSet = false; for (EBXFieldDescriptor fieldDesc : enumList.keySet()){ String fieldName = fieldDesc.getName(); if (fieldName.contains("_")&&!treeSet){ String treeName = fieldName.replace("_", " ").split(" ")[0]; proccName(treeName); treeSet = true; } //fieldDesc.setOffset(current);//offset does represent the relative index from fieldStartIndex, is already set in loader fieldDescriptors.add(fieldDesc); Boolean selected = enumList.get(fieldDesc); if (selected){ selectedIndex = fieldDesc.getOffset(); } } EBXComplexDescriptor enumComplexDesc = new EBXComplexDescriptor( "$", //name fieldDescriptors.size()-1-enumList.size(),//start index //TODO -1 ?? (char) (enumList.size()&0xFF),//numFields (char) 4,//TODO alignment (short) 0x0,//type (short) 0x0,//size (short)0x0//secondarySize ); complexDescriptors.add(enumComplexDesc);//add directly because proccComplexDescr. contains size methods desc.setRef((short) (complexDescriptors.size()-1)); data = FileHandler.toBytes(selectedIndex, ByteOrder.LITTLE_ENDIAN); if (selectedIndex>=0){//for hasNoPayloadData FileHandler.addBytes(data, targetList); } }else{ System.err.println("ENUM ERROR"); } }else if(h==(short)0x0035){//___________________________________________________________________________________________GUID if (ebxField.getValue()!=null){ String val = (String) ebxField.getValue(); if (val.contains("null")){ data = new byte[] {0x00, 0x00, 0x00, 0x00}; }else if (val.contains(" ")){//External GUID String[] split = val.split(" "); EBXExternalGUID extGUID = new EBXExternalGUID(split[0], split[1]); int index = proccExternalGUID(extGUID); data = FileHandler.toBytes(index+0x80000000/*first bit toggled ;)*/, ByteOrder.LITTLE_ENDIAN); }else{//Internal GUID byte[] internal = FileHandler.hexStringToByteArray(val);// if (internal.length==4){ data = new byte[] { internal[3], internal[2], internal[1], internal[0]//Should be LITTLE_ENDIAN :) }; Integer index = FileHandler.readInt(internal, new FileSeeker()); proccInternalGUID(val); index++;//because 1 is acc. 0 data = FileHandler.toBytes(index, ByteOrder.LITTLE_ENDIAN); //System.err.println("GUID");//i changed the loader so it uses the index as guid :) }else if (internal.length==16){ internal = null; Integer index = proccInternalGUID(val); data = FileHandler.toBytes(index, ByteOrder.LITTLE_ENDIAN); //data for now :) System.err.println("TEST->internal guid with 16 bytes");//TODO TEST internal guid }else{ System.err.println("Invalid Internal GUID - check length!"); } } //data = new byte[] {0x47, 0x55, 0x49, 0x44}; FileHandler.addBytes(data, targetList); } }else if(h==(short)0x0041){//___________________________________________________________________________________________ARRAYCOMPLEX //TODO ARRAYCOMPLEX int startOffset = arrayPayloadData.size(); if (ebxField.getValue() instanceof String){ data = new byte[] {0x00, 0x00, 0x00, 0x00}; }else{ EBXComplex arrayComplex = ebxField.getValueAsComplex(); arrayComplex.getComplexDescriptor().setName("array");//->try this because of treeview converter creates a complex of a complex. short type = 0; if (arrayComplex.getFields().length>0){ type = arrayComplex.getField(0).getFieldDescritor().getType(); } int fieldStartIndex = 0; if (type==0){//type is signed so we would have to cast it to unsigned but...nope System.err.println("TODO: ARRAYCOMPLEX UNDEFINED TYPE"); }else if (type==(short)0x29){//Type of Complex| //TODO are the more type's there using diffrent descriptors for each Member ? fieldStartIndex = fieldDescriptors.size(); //data = FileHandler.toBytes(arrayComplex.getFields().length, ByteOrder.LITTLE_ENDIAN);//test for (EBXField field : arrayComplex.getFields()){ int refIndex = complexDescriptors.size(); /*//TODO*/ //procfield gets procc by proccComplex too! proccField(field, true /*isArrayMember*/, true /*proccFieldDescriptor*/, true /*hasNoPayload*/);//complex does not have payload, only structure! EBXFieldDescriptor memberFieldDesc = new EBXFieldDescriptor("member", type, (short) refIndex, 0, 0); fieldDescriptors.add(memberFieldDesc); } }else{ fieldStartIndex = fieldDescriptors.size(); EBXFieldDescriptor memberMasterFieldDesc = new EBXFieldDescriptor("member", type, (short) 0, 0, 0); fieldDescriptors.add(memberMasterFieldDesc); /*//TODO *///for (EBXField field : arrayComplex.getFields()){ <- This gets done later in the proccComplex! // proccField(field, true /*isArrayMember*/, false /*proccFieldDescriptor*/, hasNoPayload);//only write to arrayPayloadSection. Do NOT proccFieldDescriptor! //} } arrayComplex.getComplexDescriptor().setAlignment((char)0x4); //TODO test alignment arrayComplex.getComplexDescriptor().setType((short)0x41); if (type==(short)0x29){ arrayComplex.getComplexDescriptor().setNumField((char)arrayComplex.getFields().length); }else{ arrayComplex.getComplexDescriptor().setNumField((char) 0);//TODO TEST setNumFields in arrayComplex } arrayComplex.getComplexDescriptor().setSize((short) 0);//TODO arraycomplex calc size arrayComplex.getComplexDescriptor().setFieldStartIndex(fieldStartIndex); /*//TODO*/ short arrayComplexIndex = proccComplex(arrayComplex, true/*isArrayMember*/, false/*proccFieldDesc*/, hasNoPayload); if (type==(short)0x29){//Array of Complex's data = new byte[] {0x00, 0x00, 0x00, 0x00}; }else{ EBXArrayRepeater repeater = new EBXArrayRepeater(startOffset, arrayComplex.getFields().length, arrayComplexIndex /*complexIndex - same as ref*/); arrayRepeaters.add(repeater); data = FileHandler.toBytes(arrayRepeaters.size(), ByteOrder.LITTLE_ENDIAN); } } //data = new byte[] {0x41, 0x72, 0x72, 0x79}; FileHandler.addBytes(data, targetList); }else if(h==(short)0xc0ed){//____________________________________________________________________________________________SHORT if (ebxField.getValue()!=null){ short val = (short) ebxField.getValue(); if (isArrayMember){ data = FileHandler.toBytes(val, ByteOrder.BIG_ENDIAN); }else{//normalPayload short is 4 bytes. defuq... data = FileHandler.toBytes((int) val, ByteOrder.LITTLE_ENDIAN); } FileHandler.addBytes(data, targetList); } }else if(h==(short)0xc10d){//____________________________________________________________________________________________UNSIGNED INTEGER (TREEVIEW VALUE AS LONG) if (ebxField.getValue()!=null){ long val = (Long)ebxField.getValue(); data = FileHandler.toBytes(FileHandler.longToInt(val), ByteOrder.LITTLE_ENDIAN); //TODO TEST FileHandler.addBytes(data, targetList); } }else if(h==(short)0xc0fd){//____________________________________________________________________________________________SIGNED INTEGER if (ebxField.getValue()!=null){ data = FileHandler.toBytes((Integer) ebxField.getValue(), ByteOrder.LITTLE_ENDIAN); FileHandler.addBytes(data, targetList); } }else if (h==(short)0xc0ad){//____________________________________________________________________________________________BOOL if (ebxField.getValue()!=null){ Boolean value = (Boolean) ebxField.getValue(); if (value){ data = new byte[]{0x01}; }else{ data = new byte[]{0x00}; } FileHandler.addBytes(data, targetList); } }else if(h==(short)0xc0cd){//_____________________________________________________________________________________________BYTE if (ebxField.getValue()!=null){ data = new byte[]{(byte) ebxField.getValue()}; FileHandler.addBytes(data, targetList); } }else if (h==(short)0xC15D){//____________________________________________________________________________________________CHUNK GUID if (ebxField.getValue()!=null){ data = FileHandler.hexStringToByteArray((String)ebxField.getValue()); FileHandler.addBytes(data, targetList); } }else if (h==(short)0x417D){//____________________________________________________________________________________________8HEX if (ebxField.getValue()!=null){ data = FileHandler.hexStringToByteArray((String)ebxField.getValue()); FileHandler.addBytes(data, targetList); } }else{ if (ebxField.getValue()!=null){ byte[] typebyte = FileHandler.toBytes(h,ByteOrder.LITTLE_ENDIAN); System.err.println("Type not found: 0x"+FileHandler.bytesToHex(typebyte)); } } if (proccDescriptor){ if (!proccFieldDescriptor(desc)){ return -1; } } if (desc.getName().equals("member")&&fieldDescriptors.size()>1000){ System.err.println("MEMBER!!"); } Integer length = 0; if (data!=null){ length = data.length; } return length; } public int proccName(String name){ //returns FNV_1 hash for (String entryValue : names){ if (name.equals(entryValue)){ //System.out.println(entryValue+" "+EBXHandler.hasher(name.getBytes())); return EBXHandler.hasher(name.getBytes()); } } names.add(name); return EBXHandler.hasher(name.getBytes()); } public int proccExternalGUID(EBXExternalGUID guid){ int index = 0; for (EBXExternalGUID entry : externalGUIDs){ if (guid.getFileGUID().equals(entry.getFileGUID()) && guid.getInstanceGUID().equals(entry.getInstanceGUID())){ return index; } index++; } externalGUIDs.add(guid); return externalGUIDs.size()-1; } public int proccInternalGUID(String internalGUID){ int index = 1;/*we need the index whois starting at 1*/; for (String s : internalGUIDs){ if (s.equalsIgnoreCase(internalGUID)){ return index; } index++; } internalGUIDs.add(internalGUID); return internalGUIDs.size()/*return the index whois starting at 1, so don't sub -1*/; } public void writeHeader(){ FileHandler.addBytes(new byte[]{(byte) 0xCE, (byte) 0xD1, (byte) 0xB2, (byte) 0x0F}, headerBytes); //FourCC _little FileHandler.addBytes(FileHandler.toBytes(header.getAbsStringOffset(), ByteOrder.LITTLE_ENDIAN), headerBytes); //AbsString offset section start FileHandler.addBytes(FileHandler.toBytes(header.getLenStringToEOF(), ByteOrder.LITTLE_ENDIAN), headerBytes); //len from string section to EOF. FileHandler.addBytes(FileHandler.toBytes(header.getNumGUID(), ByteOrder.LITTLE_ENDIAN), headerBytes); //num of external GUIDs (FileGUID|InstanceGUID) FileHandler.addBytes(FileHandler.toBytes((short) header.getNumInstanceRepeater(), ByteOrder.LITTLE_ENDIAN), headerBytes); //num of Instance Repeaters FileHandler.addBytes(FileHandler.toBytes((short) header.getNumGUIDRepeater(), ByteOrder.LITTLE_ENDIAN), headerBytes); //num of InstanceRepeaters with GUID aka. GUIDRepeater FileHandler.addBytes(FileHandler.toBytes((short) header.getUnknown()/*TODO*/, ByteOrder.LITTLE_ENDIAN), headerBytes); FileHandler.addBytes(FileHandler.toBytes((short) header.getNumComplex(), ByteOrder.LITTLE_ENDIAN), headerBytes); //total number of complex entries FileHandler.addBytes(FileHandler.toBytes((short) header.getNumField(), ByteOrder.LITTLE_ENDIAN), headerBytes); //total number of field entries FileHandler.addBytes(FileHandler.toBytes((short) header.getLenName(), ByteOrder.LITTLE_ENDIAN), headerBytes); //len of name FileHandler.addBytes(FileHandler.toBytes(header.getLenString(), ByteOrder.LITTLE_ENDIAN), headerBytes); //len of string FileHandler.addBytes(FileHandler.toBytes(header.getNumArrayRepeater(), ByteOrder.LITTLE_ENDIAN), headerBytes); //total number of array repeater FileHandler.addBytes(FileHandler.toBytes(header.getLenPayload(), ByteOrder.LITTLE_ENDIAN), headerBytes); //len of normal payload - the start of the ARRAY payload section is absStringOffset+lenString+lenPayload } public void writeExternalGUIDs(){ for (EBXExternalGUID guid : externalGUIDs){ FileHandler.addBytes(FileHandler.hexStringToByteArray(guid.getFileGUID()), externalGUIDBytes);//file guid 16 bytes FileHandler.addBytes(FileHandler.hexStringToByteArray(guid.getInstanceGUID()), externalGUIDBytes);//instance guid 16 bytes } header.setNumGUID(externalGUIDs.size()); } public void writeNames(){ //HashMap<Integer, String> sortedMap = new HashMap<Integer, String>(names); for (String s : names){ FileHandler.addBytes(s.getBytes(), nameBytes); nameBytes.add((byte) 0x00);//may not needed, for cancel out. } while (nameBytes.size()%16!=0){ nameBytes.add((byte) 0x00);//line padding. } header.setLenName(nameBytes.size()); } public void writeFieldDescriptors(){ for (EBXFieldDescriptor fdsc : fieldDescriptors){ Integer name = proccName(fdsc.getName()/*MAY NEED TAILING NULL*/); FileHandler.addBytes(FileHandler.toBytes(name, ByteOrder.LITTLE_ENDIAN), fieldDescriptorBytes); //Hashed name as FNV_1 hash with modi. base and modf. FileHandler.addBytes(FileHandler.toBytes((short)fdsc.getType(), ByteOrder.LITTLE_ENDIAN), fieldDescriptorBytes); //type as short FileHandler.addBytes(FileHandler.toBytes((short)fdsc.getRef(), ByteOrder.LITTLE_ENDIAN), fieldDescriptorBytes); //ref as short FileHandler.addBytes(FileHandler.toBytes(fdsc.getOffset(), ByteOrder.LITTLE_ENDIAN), fieldDescriptorBytes); //offset (unsigned) in payload section; replative to the complex containing it. FileHandler.addBytes(FileHandler.toBytes(fdsc.getSecondaryOffset(), ByteOrder.LITTLE_ENDIAN), fieldDescriptorBytes); //2nd'ary offset (unsigned) } header.setNumField(fieldDescriptors.size()); } public void writeComplexDescriptors(){ for (EBXComplexDescriptor cdsc : complexDescriptors){ Integer name = proccName(cdsc.getName()/*MAY NEED TAILING NULL*/); FileHandler.addBytes(FileHandler.toBytes(name, ByteOrder.LITTLE_ENDIAN), complexDescriptorBytes); //Hashed name as FNV_1 hash with modi. base and modf. FileHandler.addBytes(FileHandler.toBytes(cdsc.getFieldStartIndex(), ByteOrder.LITTLE_ENDIAN), complexDescriptorBytes); //the index of the first field belonging to the complex complexDescriptorBytes.add((byte) cdsc.getNumField()); //total number of fields belonging to the complex complexDescriptorBytes.add((byte) cdsc.getAlignment()); //alignment FileHandler.addBytes(FileHandler.toBytes((short)cdsc.getType(), ByteOrder.LITTLE_ENDIAN), complexDescriptorBytes); // type as short FileHandler.addBytes(FileHandler.toBytes((short)cdsc.getSize(), ByteOrder.LITTLE_ENDIAN), complexDescriptorBytes); //total length of the complex in the payload section. FileHandler.addBytes(FileHandler.toBytes((short)cdsc.getSecondarySize(), ByteOrder.LITTLE_ENDIAN), complexDescriptorBytes); //seems deprecated or may for padding. } header.setNumComplex(complexDescriptors.size()); } public void writeInstanceRepeaters(){ for (EBXInstanceRepeater rep : instanceRepeaters){ FileHandler.addBytes(FileHandler.toBytes((short)rep.getComplexIndex(), ByteOrder.LITTLE_ENDIAN), instanceRepeaterBytes); //represents the complex FileHandler.addBytes(FileHandler.toBytes((short)rep.getRepetitions(), ByteOrder.LITTLE_ENDIAN), instanceRepeaterBytes); //total number of repetitions in the complex. } header.setNumInstanceRepeater(instanceRepeaters.size()); } public void writeArrayRepeaters(){ for (EBXArrayRepeater rep : arrayRepeaters){ FileHandler.addBytes(FileHandler.toBytes(rep.getOffset(), ByteOrder.LITTLE_ENDIAN), arrayRepeaterBytes);//offset in array payload section FileHandler.addBytes(FileHandler.toBytes(rep.getRepetitions(), ByteOrder.LITTLE_ENDIAN), arrayRepeaterBytes);//number of array repetitions /*TODO*/ FileHandler.addBytes(FileHandler.toBytes(rep.getComplexIndex(), ByteOrder.LITTLE_ENDIAN), arrayRepeaterBytes);//the complex belonging to the array - not necessary for extraction. } header.setNumArrayRepeater(arrayRepeaters.size()); } public void writeStrings(){ for (String s : strings){ FileHandler.addBytes(s.getBytes(), stringBytes); stringBytes.add((byte) 0x00); } while (stringBytes.size()%16!=0){ stringBytes.add((byte) 0x00);//TODO line padding, add unnecessary extra line } header.setLenString(stringBytes.size()); } }