public void PrintDebug(bool verbose = false) { if (verbose) { Console.WriteLine($"{nameof(ByteBitPos)} : {ByteBitPos}"); Console.WriteLine($"{nameof(BitLength)} : {BitLength}"); Console.WriteLine($"{nameof(ImplementationType)} : {ImplementationType}"); Console.WriteLine($"{nameof(ImplementationUpper)} : 0x{ImplementationUpper:X}"); Console.WriteLine($"{nameof(Name_CTF)} : {Name_CTF}"); Console.WriteLine($"{nameof(Description_CTF)} : {Description_CTF}"); Console.WriteLine($"{nameof(ReadAccessLevel)} : {ReadAccessLevel}"); Console.WriteLine($"{nameof(WriteAccessLevel)} : {WriteAccessLevel}"); Console.WriteLine($"{nameof(ByteOrder)} : {ByteOrder}"); Console.WriteLine($"{nameof(RawBitLength)} : {RawBitLength}"); Console.WriteLine($"{nameof(IttOffset)} : {IttOffset}"); Console.WriteLine($"{nameof(InfoPoolIndex)} : {InfoPoolIndex}"); Console.WriteLine($"{nameof(MeaningB)} : {MeaningB}"); Console.WriteLine($"{nameof(MeaningC)} : {MeaningC}"); Console.WriteLine($"{nameof(CCFHandle)} : {CCFHandle}"); Console.WriteLine($"{nameof(VarcodeDumpSize)} : {VarcodeDumpSize}"); Console.WriteLine($"{nameof(VarcodeDump)} : {BitUtility.BytesToHex(VarcodeDump)}"); Console.WriteLine($"{nameof(SubfragmentCount)} : {SubfragmentCount}"); Console.WriteLine($"{nameof(SubfragmentFileOffset)} : 0x{SubfragmentFileOffset:X}"); Console.WriteLine($"{nameof(Qualifier)} : {Qualifier}"); } else { Console.WriteLine($"{Qualifier}%{ByteBitPos}%{BitLength}%[{ImplementationUpper:X}/{ImplementationLower:X}]"); } }
public void BitRoundtripTest() { byte[] bitarray = new byte[] { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, }; byte[] testByteArray = BitUtility.BitArrayToByteArray(bitarray, false); Console.WriteLine($"test in 1: {BitUtility.BytesToBitString(testByteArray)}"); Console.WriteLine($"test in 1: {BitUtility.BytesToHex(testByteArray)}"); foreach (byte b in bitarray) { Console.Write(b); } Console.WriteLine(); byte[] testBitArray = BitUtility.ByteArrayToBitArray(testByteArray, false); testByteArray = BitUtility.BitArrayToByteArray(testBitArray); Console.WriteLine($"test in 2: {BitUtility.BytesToBitString(testByteArray)}"); Console.WriteLine($"test in 2: {BitUtility.BytesToHex(testByteArray)}"); foreach (byte b in testBitArray) { Console.Write(b); } Console.WriteLine(); }
private void PrintDebug(bool verbose = false) { if (verbose) { Console.WriteLine("------------- subfragment ------------- "); Console.WriteLine($"{nameof(Name_CTF)}, {Name_CTF}"); Console.WriteLine($"{nameof(Dump)}, {BitUtility.BytesToHex(Dump)}"); Console.WriteLine($"{nameof(Description_CTF)}, {Description_CTF}"); Console.WriteLine($"{nameof(NameCTFResolved)}, {NameCTFResolved}"); Console.WriteLine($"{nameof(QualifierUsuallyDisabled)}, {QualifierUsuallyDisabled}"); Console.WriteLine($"{nameof(Unk3)}, {Unk3}"); Console.WriteLine($"{nameof(Unk4)}, {Unk4}"); Console.WriteLine($"{nameof(SupplementKey)}, {SupplementKey}"); } else { Console.WriteLine($">> {BitUtility.BytesToHex(Dump)} : {NameCTFResolved}"); } }
public void PrintDebug() { Console.WriteLine($"{nameof(Qualifier)} : {Qualifier}"); Console.WriteLine($"{nameof(BitPosition)} : {BitPosition}"); Console.WriteLine($"{nameof(ModeConfig)} : 0x{ModeConfig:X}"); Console.WriteLine($"Mode H : 0x{ModeConfig & 0xFF0:X}, L : 0x{ModeConfig & 0xF:X}"); Console.WriteLine($"{nameof(SizeInBits)} : 0x{SizeInBits:X}"); Console.WriteLine($"{nameof(Name_CTF)} : {Name_CTF}"); Console.WriteLine($"{nameof(Name_CTF)} : {Language.GetString(Name_CTF)}"); Console.WriteLine($"{nameof(Unk1)} : {Unk1}"); Console.WriteLine($"{nameof(Unk2)} : {Unk2}"); Console.WriteLine($"{nameof(AlternativeBitWidth)} : {AlternativeBitWidth}"); Console.WriteLine($"{nameof(IITOffset)} : {IITOffset}"); Console.WriteLine($"{nameof(InfoPoolIndex)} : {InfoPoolIndex}"); Console.WriteLine($"{nameof(PresPoolIndex)} : {PresPoolIndex}"); Console.WriteLine($"{nameof(Field1E)} : {Field1E}"); Console.WriteLine($"{nameof(SystemParam)} : {SystemParam}"); // Console.WriteLine($"{nameof(noIdea_T)} : {language.GetString(noIdea_T)}"); Console.WriteLine($"{nameof(Dump)} : {BitUtility.BytesToHex(Dump)}"); Console.WriteLine("---------------"); }
public void PrintDebug() { Console.WriteLine($"ComParam: id {ComParamIndex} ({ParamName}), v {ComParamValue} 0x{ComParamValue:X8} SI_Index:{SubinterfaceIndex} | parentIndex:{ParentInterfaceIndex} 5:{Unk5} DumpSize:{DumpSize} D: {BitUtility.BytesToHex(Dump)}"); Console.WriteLine($"Pos 0x{BaseAddress:X}"); }
public DSCContext(byte[] dscContainerBytes) { const int fnTableEntrySize = 50; using (BinaryReader reader = new BinaryReader(new MemoryStream(dscContainerBytes))) { reader.BaseStream.Seek(0x10, SeekOrigin.Begin); int fnTableOffset = reader.ReadInt32(); // @ 0x10, originally i16 int numberOfFunctions = reader.ReadInt16(); // @ 0x14 int dscOffsetA = reader.ReadInt32(); // @ 0x16, originally i16 int caesarHash = reader.ReadInt16(); // @ 0x1A, size is u32? int idk_field_1c = reader.ReadInt16(); // ?? @ 1C, padding int globalVarAllocSize = reader.ReadInt16(); // @ 1E int idk_field_20 = reader.ReadInt16(); // ?? @ 20, padding int globalVariablesBufferPtr = reader.ReadInt32(); // ?? @ 22 int globalVariablesCount = reader.ReadInt16(); // ?? @ 26 int globalVariablesIdk1 = reader.ReadInt32(); // ?? @ 28 int globalVariablesIdk2 = reader.ReadInt16(); // ?? @ 2C int globalVariablesPreinitBufferPtr = reader.ReadInt32(); // ?? @ 2E int globalVariablesBytesToRead = reader.ReadInt16(); // ?? @ 32 byte[] globalVarByteBuffer = new byte[globalVarAllocSize]; Console.WriteLine($"{nameof(dscOffsetA)} : {dscOffsetA} (0x{dscOffsetA:X})\n"); Console.WriteLine($"{nameof(caesarHash)} : {caesarHash} (0x{caesarHash:X})\n"); Console.WriteLine($"{nameof(globalVarAllocSize)} : {globalVarAllocSize} (0x{globalVarAllocSize:X})\n"); Console.WriteLine($"{nameof(globalVariablesBufferPtr)} : {globalVariablesBufferPtr} (0x{globalVariablesBufferPtr:X})"); Console.WriteLine($"{nameof(globalVariablesCount)} : {globalVariablesCount} (0x{globalVariablesCount:X})\n"); Console.WriteLine($"{nameof(globalVariablesIdk1)} : {globalVariablesIdk1} (0x{globalVariablesIdk1:X})"); Console.WriteLine($"{nameof(globalVariablesIdk2)} : {globalVariablesIdk2} (0x{globalVariablesIdk2:X})\n"); Console.WriteLine($"{nameof(globalVariablesPreinitBufferPtr)} : {globalVariablesPreinitBufferPtr} (0x{globalVariablesPreinitBufferPtr:X})"); Console.WriteLine($"{nameof(globalVariablesBytesToRead)} : {globalVariablesBytesToRead} (0x{globalVariablesBytesToRead:X})\n"); // assemble global vars: MIGlobalVarBuild (parent: MIInterpreterRun) int gvBytesRemaining = globalVariablesBytesToRead; reader.BaseStream.Seek(globalVariablesPreinitBufferPtr, SeekOrigin.Begin); while (gvBytesRemaining > 0) { int gvAddress = reader.ReadInt16(); int gvSize = reader.ReadByte(); byte[] gvData = reader.ReadBytes(gvSize); Console.WriteLine($"GV Fill: 0x{gvAddress:X} ({gvSize} bytes) : {BitUtility.BytesToHex(gvData)}"); Buffer.BlockCopy(gvData, 0, globalVarByteBuffer, gvAddress, gvSize); gvBytesRemaining -= gvSize; gvBytesRemaining -= 3; } if (gvBytesRemaining != 0) { throw new Exception("Global variable preinit has leftover data in the read cursor"); } // CreateGlobalVar for (int gvIndex = 0; gvIndex < globalVariablesCount; gvIndex++) { /* * guesses: * base * 1 -> char * 2 -> word * 3 -> dword * * * derived * 1 -> native * 2 -> array * 3 -> pointer * */ reader.BaseStream.Seek(globalVariablesBufferPtr + (gvIndex * 12), SeekOrigin.Begin); int varName = reader.ReadInt32(); DSCBasicType baseType = (DSCBasicType)reader.ReadInt16(); DSCDerivedType derivedType = (DSCDerivedType)reader.ReadInt16(); int arraySize = reader.ReadInt16(); int positionInGlobalBuffer = reader.ReadInt16(); reader.BaseStream.Seek(varName, SeekOrigin.Begin); string varNameResolved = CaesarReader.ReadStringFromBinaryReader(reader, CaesarReader.DefaultEncoding); int dataSizeInBytes = GetDscTypeSize((int)baseType, (int)derivedType); if (derivedType == DSCDerivedType.Array) { dataSizeInBytes *= arraySize; } byte[] varBytes = new byte[dataSizeInBytes]; Buffer.BlockCopy(globalVarByteBuffer, positionInGlobalBuffer, varBytes, 0, dataSizeInBytes); Console.WriteLine($"\nVar: {baseType}/{derivedType} [{arraySize}] @ {positionInGlobalBuffer} : {varNameResolved}"); Console.WriteLine($"{BitUtility.BytesToHex(varBytes)}"); // actual insertion into global var list is in MIGlobalVarCallback, stored in interpreter's ->GlobalVarList } for (int fnIndex = 0; fnIndex < numberOfFunctions; fnIndex++) { long fnBaseAddress = fnTableEntrySize * fnIndex + fnTableOffset; reader.BaseStream.Seek(fnBaseAddress, SeekOrigin.Begin); int fnIdentifier = reader.ReadInt16(); // @ 0 int fnNameOffset = reader.ReadInt32(); // @ 2 // not exactly sure if int32 is right -- the first fn's ep looks incorrect in both cases. // 16 bit would limit the filesize to ~32KB which seems unlikely int fnEntryPoint = reader.ReadInt32(); // @ 6 //int fnEntryPoint = reader.ReadInt16(); // @ 6 //int fnIdkIsThisStandalone = reader.ReadInt16(); // @ 6 reader.BaseStream.Seek(fnBaseAddress + 38, SeekOrigin.Begin); int inputParamOffset = reader.ReadInt32(); // @ 38 int inputParamCount = reader.ReadInt16(); // @ 42 int outputParamOffset = reader.ReadInt32(); // @ 44 int outputParamCount = reader.ReadInt16(); // @ 48 reader.BaseStream.Seek(fnNameOffset, SeekOrigin.Begin); string fnName = CaesarReader.ReadStringFromBinaryReader(reader); Console.WriteLine($"Fn: {fnName} Ordinal: {fnIdentifier} EP: 0x{fnEntryPoint:X}, InParam: {inputParamCount} @ 0x{inputParamOffset:X}, OutParam: {outputParamCount} @ 0x{outputParamOffset}"); // the EP points to an int16 to initialize the stack height // after the EP, the raw bytecode can be directly interpreted } } }
public string InterpretData(byte[] inBytes, DiagPreparation inPreparation, bool describe = true) { // might be relevant: DMPrepareSingleDatum, DMPresentSingleDatum bool isDebugBuild = false; #if DEBUG isDebugBuild = true; #endif string descriptionPrefix = describe ? $"{DescriptionString}: " : ""; byte[] workingBytes = inBytes.Skip(inPreparation.BitPosition / 8).Take(TypeLength_1A).ToArray(); bool isEnumType = (EnumType_1E == 0) && ((Type_1C == 1) || (ScaleCountMaybe > 1)); // hack: sometimes hybrid types (regularly parsed as an scaled value if within bounds) are misinterpreted as pure enums // this is a temporary fix for kilometerstand until there's a better way to ascertain its type // this also won't work on other similar cases without a unit string e.g. error instance counter (Häufigkeitszähler) if (DisplayedUnitString == "km") { isEnumType = false; } if (workingBytes.Length != TypeLength_1A) { return($"InBytes [{BitUtility.BytesToHex(workingBytes)}] length mismatch (expecting {TypeLength_1A})"); } // handle booleans first since they're the edge case where they can cross byte boundaries if (inPreparation.SizeInBits == 1) { int bytesToSkip = (int)(inPreparation.BitPosition / 8); int bitsToSkip = inPreparation.BitPosition % 8; byte selectedByte = inBytes[bytesToSkip]; int selectedBit = (selectedByte >> bitsToSkip) & 1; if (isEnumType && (Scales.Count > selectedBit)) { return($"{descriptionPrefix}{Language.GetString(Scales[selectedBit].EnumDescription)} {DisplayedUnitString}"); } else { return($"{descriptionPrefix}{selectedBit} {DisplayedUnitString}"); } } // everything else should be aligned to byte boundaries if (inPreparation.BitPosition % 8 != 0) { return("BitOffset was outside byte boundary (skipped)"); } int dataType = GetDataType(); int rawIntInterpretation = 0; string humanReadableType = $"UnhandledType:{dataType}"; string parsedValue = BitUtility.BytesToHex(workingBytes, true); if ((dataType == 6 || (dataType == 20))) { // parse as a regular int (BE) for (int i = 0; i < workingBytes.Length; i++) { rawIntInterpretation <<= 8; rawIntInterpretation |= workingBytes[i]; } humanReadableType = "IntegerType"; parsedValue = rawIntInterpretation.ToString(); if (dataType == 20) { humanReadableType = "ScaledType"; double valueToScale = rawIntInterpretation; // if there's only one scale, use it as-is // if there's more than one, use the first scale as an interim solution; // the results of stacking scales does not make sense // there might be a better, non-hardcoded (0) solution to this, and perhaps with a sig-fig specifier valueToScale *= Scales[0].MultiplyFactor; valueToScale += Scales[0].AddConstOffset; parsedValue = valueToScale.ToString("0.000000"); } } else if (dataType == 18) { humanReadableType = "HexdumpType"; } else if (dataType == 17) { humanReadableType = "StringType"; parsedValue = Encoding.UTF8.GetString(workingBytes); } if (isEnumType) { // discovered by @VladLupashevskyi in https://github.com/jglim/CaesarSuite/issues/27 // if an enum is specified, the inclusive upper bound and lower bound will be defined in the scale object bool useNewInterpretation = false; foreach (Scale scale in Scales) { if ((scale.EnumUpBound > 0) || (scale.EnumLowBound > 0)) { useNewInterpretation = true; break; } } if (useNewInterpretation) { foreach (Scale scale in Scales) { if ((rawIntInterpretation >= scale.EnumLowBound) && (rawIntInterpretation <= scale.EnumUpBound)) { return($"{descriptionPrefix}{Language.GetString(scale.EnumDescription)} {DisplayedUnitString}"); } } } else { // original implementation, probably incorrect if (rawIntInterpretation < Scales.Count) { return($"{descriptionPrefix}{Language.GetString(Scales[rawIntInterpretation].EnumDescription)} {DisplayedUnitString}"); } } return($"{descriptionPrefix}(Enum not found) {DisplayedUnitString}"); // this bit below for troubleshooting problematic presentations /* * if (rawIntInterpretation < Scales.Count) * { * return $"{descriptionPrefix}{Language.GetString(Scales[rawIntInterpretation].EnumDescription)} {DisplayedUnitString}"; * } * else * { * // seems like an enum-like value broke * return $"{descriptionPrefix}{Language.GetString(Scales[0].EnumDescription)} {DisplayedUnitString} [!]"; * } */ } else { if (isDebugBuild) { return($"{descriptionPrefix}{parsedValue} {DisplayedUnitString} ({humanReadableType})"); } else { return($"{descriptionPrefix}{parsedValue} {DisplayedUnitString}"); } } }
public string InterpretData(byte[] inBytes, DiagPreparation inPreparation) { // might be relevant: DMPrepareSingleDatum, DMPresentSingleDatum byte[] workingBytes = inBytes.Skip(inPreparation.BitPosition / 8).Take(TypeLength_1a).ToArray(); if (workingBytes.Length != TypeLength_1a) { return($"InBytes [{BitUtility.BytesToHex(workingBytes)}] length mismatch (expecting {TypeLength_1a})"); } // handle booleans first since they're the edge case where they can cross byte boundaries if (inPreparation.SizeInBits == 1) { int bytesToSkip = (int)(inPreparation.BitPosition / 8); int bitsToSkip = inPreparation.BitPosition % 8; byte selectedByte = inBytes[bytesToSkip]; int selectedBit = (selectedByte >> bitsToSkip) & 1; return($"{DescriptionString}: {selectedBit} {DisplayedUnitString} (BitType)"); } // everything else should be aligned to byte boundaries if (inPreparation.BitPosition % 8 != 0) { return("BitOffset was outside byte boundary (skipped)"); } int dataType = GetDataType(); string humanReadableType = $"UnhandledType:{dataType}"; string parsedValue = BitUtility.BytesToHex(workingBytes, true); if ((dataType == 6 || (dataType == 20))) { // parse as a regular int (BE) int result = 0; for (int i = 0; i < workingBytes.Length; i++) { result <<= 8; result |= workingBytes[i]; } humanReadableType = "IntegerType"; parsedValue = result.ToString(); if (dataType == 20) { humanReadableType = "ScaledType"; double valueToScale = result; foreach (Scale scale in Scales) { valueToScale *= scale.MultiplyFactor; valueToScale += scale.AddConstOffset; } parsedValue = valueToScale.ToString("0.000000"); } } else if (dataType == 18) { humanReadableType = "HexdumpType"; } else if (dataType == 17) { humanReadableType = "StringType"; parsedValue = Encoding.UTF8.GetString(workingBytes); } return($"{DescriptionString}: {parsedValue} {DisplayedUnitString} ({humanReadableType})"); }
public string InterpretData(byte[] inBytes, DiagPreparation inPreparation, bool describe = true) { // might be relevant: DMPrepareSingleDatum, DMPresentSingleDatum bool isDebugBuild = false; #if DEBUG isDebugBuild = true; #endif string descriptionPrefix = describe ? $"{DescriptionString}: " : ""; byte[] workingBytes = inBytes.Skip(inPreparation.BitPosition / 8).Take(TypeLength_1A).ToArray(); bool isEnumType = (EnumType_1E == 0) && ((Type_1C == 1) || (ScaleCountMaybe > 1)); if (workingBytes.Length != TypeLength_1A) { return($"InBytes [{BitUtility.BytesToHex(workingBytes)}] length mismatch (expecting {TypeLength_1A})"); } // handle booleans first since they're the edge case where they can cross byte boundaries if (inPreparation.SizeInBits == 1) { int bytesToSkip = (int)(inPreparation.BitPosition / 8); int bitsToSkip = inPreparation.BitPosition % 8; byte selectedByte = inBytes[bytesToSkip]; int selectedBit = (selectedByte >> bitsToSkip) & 1; if (isEnumType && (Scales.Count > selectedBit)) { return($"{descriptionPrefix}{Language.GetString(Scales[selectedBit].EnumDescription)} {DisplayedUnitString}"); } else { return($"{descriptionPrefix}{selectedBit} {DisplayedUnitString}"); } } // everything else should be aligned to byte boundaries if (inPreparation.BitPosition % 8 != 0) { return("BitOffset was outside byte boundary (skipped)"); } int dataType = GetDataType(); int rawIntInterpretation = 0; string humanReadableType = $"UnhandledType:{dataType}"; string parsedValue = BitUtility.BytesToHex(workingBytes, true); if ((dataType == 6 || (dataType == 20))) { // parse as a regular int (BE) for (int i = 0; i < workingBytes.Length; i++) { rawIntInterpretation <<= 8; rawIntInterpretation |= workingBytes[i]; } humanReadableType = "IntegerType"; parsedValue = rawIntInterpretation.ToString(); if (dataType == 20) { humanReadableType = "ScaledType"; double valueToScale = rawIntInterpretation; // if there's only one scale, use it as-is // if there's more than one, use the first scale as an interim solution; // the results of stacking scales does not make sense // there might be a better, non-hardcoded (0) solution to this, and perhaps with a sig-fig specifier valueToScale *= Scales[0].MultiplyFactor; valueToScale += Scales[0].AddConstOffset; parsedValue = valueToScale.ToString("0.000000"); } } else if (dataType == 18) { humanReadableType = "HexdumpType"; } else if (dataType == 17) { humanReadableType = "StringType"; parsedValue = Encoding.UTF8.GetString(workingBytes); } if (isEnumType && (rawIntInterpretation < Scales.Count)) { return($"{descriptionPrefix}{Language.GetString(Scales[rawIntInterpretation].EnumDescription)} {DisplayedUnitString}"); // this bit below for troubleshooting problematic presentations /* * if (rawIntInterpretation < Scales.Count) * { * return $"{descriptionPrefix}{Language.GetString(Scales[rawIntInterpretation].EnumDescription)} {DisplayedUnitString}"; * } * else * { * // seems like an enum-like value broke * return $"{descriptionPrefix}{Language.GetString(Scales[0].EnumDescription)} {DisplayedUnitString} [!]"; * } */ } else { if (isDebugBuild) { return($"{descriptionPrefix}{parsedValue} {DisplayedUnitString} ({humanReadableType})"); } else { return($"{descriptionPrefix}{parsedValue} {DisplayedUnitString}"); } } }