/// <summary> /// ME3Explorer intercepting function to build the token list. As tokens are read the tokens list will be updated. /// This method is used to prevent significant modifications to ReadNextInternal() (originally ReadNext) /// </summary> /// <returns></returns> public BytecodeToken ReadNext(bool dontAddToken = false) { ME1OpCodes b = (ME1OpCodes)_reader.ReadByte(); _reader.BaseStream.Position--; if (OpCodesThatReturnNextToken.Contains(b)) { BytecodeToken t = new BytecodeToken("", (int)_reader.BaseStream.Position); t.OpCode = b; ReadTokens.Add(t); } //if (b == ME1OpCodes.EX_Skip) //{ // Debugger.Break(); //} //Debug.WriteLine("Read bytecode " + ((byte)b).ToString("X2") + " " + b + " at " + _reader.BaseStream.Position.ToString("X8")); BytecodeToken bct = ReadNextInternal(); //Debug.WriteLine("Bytecode finished: " + ((byte)b).ToString("X2") + " " + b + " from " + _reader.BaseStream.Position.ToString("X8")); if (!OpCodesThatReturnNextToken.Contains(b)) { bct.OpCode = b; ReadTokens.Add(bct); } return(bct); }
private BytecodeToken ReadNextInternal() { int readerpos = (int)_reader.BaseStream.Position; ME1OpCodes b = (ME1OpCodes)_reader.ReadByte(); switch (b) { case ME1OpCodes.EX_LocalVariable: case ME1OpCodes.EX_InstanceVariable: case ME1OpCodes.EX_NativeParm: return(ReadRef(r => r.ObjectName.Instanced)); case ME1OpCodes.EX_DefaultVariable: return(ReadRef(r => $"Default.{r.ObjectName.Instanced}")); case ME1OpCodes.EX_Return: { BytecodeToken returnValue = ReadNext(); return(new ReturnToken(returnValue, readerpos)); } case ME1OpCodes.EX_Assert: { _reader.ReadInt16(); _reader.ReadByte(); return(WrapNextBytecode(c => new BytecodeToken($"assert({c})", readerpos))); } case ME1OpCodes.EX_Switch: { byte b1 = _reader.ReadByte(); BytecodeToken switchExpr = ReadNext(); return(new SwitchToken(switchExpr.ToString(), switchExpr, readerpos)); } case ME1OpCodes.EX_Case: { short offset = _reader.ReadInt16(); if (offset == -1) { return(new DefaultToken(readerpos)); } BytecodeToken caseExpr = ReadNext(); return(new CaseToken(caseExpr.ToString(), readerpos)); } case ME1OpCodes.EX_Jump: { int offset = _reader.ReadInt16(); return(new UncondJumpToken(offset, readerpos)); } case ME1OpCodes.EX_JumpIfNot: { short offset = _reader.ReadInt16(); BytecodeToken condition = ReadNext(); if (IsInvalid(condition)) { return(WrapErrToken("if (!" + condition, condition)); } return(new JumpIfNotToken(offset, condition, readerpos)); } case ME1OpCodes.EX_LabelTable: { var token = new LabelTableToken(readerpos); while (true) { string labelName = ReadName(); if (labelName == "None") { break; } int offset = _reader.ReadInt32(); token.AddLabel(labelName, offset); } return(token); } case ME1OpCodes.EX_GotoLabel: return(WrapNextBytecode(op => Token("goto " + op, readerpos))); case ME1OpCodes.EX_Self: return(Token("self", readerpos)); case ME1OpCodes.EX_Skip: _reader.ReadInt16(); //Returning readnext causes a new token to be read return(ReadNext()); case ME1OpCodes.EX_EatReturnValue: _reader.ReadInt32(); return(ReadNext()); case ME1OpCodes.EX_Nothing: return(new NothingToken(readerpos)); case ME1OpCodes.EX_Stop: _reader.ReadInt16(); return(new NothingToken(readerpos)); case ME1OpCodes.EX_IntZero: return(Token("0", readerpos)); case ME1OpCodes.EX_IntOne: return(Token("1", readerpos)); case ME1OpCodes.EX_True: return(Token("true", readerpos)); case ME1OpCodes.EX_False: return(Token("false", readerpos)); case ME1OpCodes.EX_NoObject: case ME1OpCodes.EX_EmptyDelegate: return(Token("None", readerpos)); case ME1OpCodes.EX_Let: case ME1OpCodes.EX_LetBool: case ME1OpCodes.EX_LetDelegate: BytecodeToken lhs = ReadNext(); if (IsInvalid(lhs)) { return(lhs); } BytecodeToken rhs = ReadNext(); if (IsInvalid(rhs)) { return(WrapErrToken(lhs + " = " + rhs, rhs)); } return(Token(lhs + " = " + rhs, readerpos)); case ME1OpCodes.EX_IntConst: return(Token(_reader.ReadInt32().ToString(), readerpos)); case ME1OpCodes.EX_FloatConst: return(Token(_reader.ReadSingle().ToString(), readerpos)); case ME1OpCodes.EX_StringConst: { var s = ReadAsciiz().Replace("\n", "\\n").Replace("\t", "\\t"); return(Token($"\"{s}\"", readerpos)); } case ME1OpCodes.EX_ByteConst: case ME1OpCodes.EX_IntConstByte: return(Token(_reader.ReadByte().ToString(), readerpos)); case ME1OpCodes.EX_ObjectConst: { int objectIndex = _reader.ReadInt32(); var item = _package.GetEntry(objectIndex); if (item == null) { return(ErrToken("Unresolved class item " + objectIndex)); } return(Token($"{item.ClassName}'{item.ObjectName.Instanced}'", readerpos)); } case ME1OpCodes.EX_NameConst: return(Token($"'{ReadName()}'", readerpos)); case ME1OpCodes.EX_EndFunctionParms: return(new EndParmsToken(")", readerpos)); case ME1OpCodes.EX_ClassContext: case ME1OpCodes.EX_Context: { var context = ReadNext(); if (IsInvalid(context)) { return(context); } int exprSize = _reader.ReadInt16(); int bSize = _reader.ReadByte(); var value = ReadNext(); if (IsInvalid(value)) { return(WrapErrToken($"{context}.{value}", value)); } return(Token($"{context}.{value}", readerpos)); } case ME1OpCodes.EX_InterfaceContext: return(ReadNext()); case ME1OpCodes.EX_FinalFunction: { int functionIndex = _reader.ReadInt32(); var item = _package.GetEntry(functionIndex); if (item == null) { return(ErrToken("Unresolved function item " + item)); } string functionName = item.ObjectName.Instanced; return(ReadCall(functionName)); } case ME1OpCodes.EX_PrimitiveCast: { var prefix = _reader.ReadByte(); var v = ReadNext(); return(v); } case ME1OpCodes.EX_VirtualFunction: return(ReadCall(ReadName())); case ME1OpCodes.EX_GlobalFunction: return(ReadCall("Global." + ReadName())); case ME1OpCodes.EX_BoolVariable: return(ReadNext()); case ME1OpCodes.EX_ByteToInt: int objectRefIdx = _reader.ReadInt32(); if (_package.IsEntry(objectRefIdx)) { return(Token($"ByteToInt({_package.getObjectName(objectRefIdx)})", readerpos)); } else { return(Token($"ByteToInt(Unknown reference {objectRefIdx})", readerpos)); } case ME1OpCodes.EX_DynamicCast: { int typeIndex = _reader.ReadInt32(); var item = _package.GetEntry(typeIndex); return(WrapNextBytecode(op => Token($"{item.ObjectName.Instanced}({op})", readerpos))); } case ME1OpCodes.EX_Metacast: { int typeIndex = _reader.ReadInt32(); var item = _package.GetEntry(typeIndex); if (item == null) { return(ErrToken("Unresolved class item " + typeIndex)); } return(WrapNextBytecode(op => Token($"Class<{item.ObjectName.Instanced}>({op})", readerpos))); } case ME1OpCodes.EX_StructMember: { var field = ReadRef(); var structType = ReadRef(); int wSkip = _reader.ReadInt16(); var token = ReadNext(); if (IsInvalid(token)) { return(token); } return(Token($"{token}.{field.ObjectName.Instanced}", readerpos)); } case ME1OpCodes.EX_ArrayElement: case ME1OpCodes.EX_DynArrayElement: { var index = ReadNext(); if (IsInvalid(index)) { return(index); } var array = ReadNext(); if (IsInvalid(array)) { return(array); } return(Token($"{array}[{index}]", readerpos)); } case ME1OpCodes.EX_DynArrayLength: return(WrapNextBytecode(op => Token($"{op}.Length", readerpos))); case ME1OpCodes.EX_StructCmpEq: return(CompareStructs("==")); case ME1OpCodes.EX_StructCmpNe: return(CompareStructs("!=")); case ME1OpCodes.EX_EndOfScript: return(new EndOfScriptToken(readerpos)); case ME1OpCodes.EX_EmptyParmValue: case ME1OpCodes.EX_GoW_DefaultValue: return(new DefaultValueToken("", readerpos)); case ME1OpCodes.EX_DefaultParmValue: { var size = _reader.ReadInt16(); var offset = _reader.BaseStream.Position; var defaultValueExpr = ReadNext(); _reader.BaseStream.Position = offset + size; return(new DefaultParamValueToken(defaultValueExpr.ToString(), readerpos)); } case ME1OpCodes.EX_LocalOutVariable: int valueIndex = _reader.ReadInt32(); var packageItem = _package.GetEntry(valueIndex); if (packageItem == null) { return(ErrToken("Unresolved package item " + packageItem)); } return(Token(packageItem.ObjectName.Instanced, readerpos)); case ME1OpCodes.EX_Iterator: var expr = ReadNext(); int loopEnd = _reader.ReadInt16(); if (IsInvalid(expr)) { return(WrapErrToken("foreach " + expr, expr)); } return(new ForeachToken(loopEnd, expr, readerpos)); case ME1OpCodes.EX_IteratorPop: return(new IteratorPopToken(readerpos)); case ME1OpCodes.EX_IteratorNext: return(new IteratorNextToken(readerpos)); case ME1OpCodes.EX_New: var outer = ReadNext(); if (IsInvalid(outer)) { return(outer); } var name = ReadNext(); if (IsInvalid(name)) { return(name); } var flags = ReadNext(); if (IsInvalid(flags)) { return(flags); } var cls = ReadNext(); if (IsInvalid(cls)) { return(cls); } return(Token($"new({JoinTokens(outer, name, flags, cls)})", readerpos)); case ME1OpCodes.EX_VectorConst: var f1 = _reader.ReadSingle(); var f2 = _reader.ReadSingle(); var f3 = _reader.ReadSingle(); return(Token($"vect({f1},{f2},{f3})", readerpos)); case ME1OpCodes.EX_RotationConst: var i1 = _reader.ReadInt32(); var i2 = _reader.ReadInt32(); var i3 = _reader.ReadInt32(); return(Token($"rot({i1},{i2},{i3})", readerpos)); case ME1OpCodes.EX_InterfaceCast: { var interfaceName = ReadRef(); return(WrapNextBytecode(op => Token($"{interfaceName.ObjectName.Instanced}({op})", readerpos))); } case ME1OpCodes.EX_Conditional: { var condition = ReadNext(); if (IsInvalid(condition)) { return(condition); } var trueSize = _reader.ReadInt16(); var pos = _reader.BaseStream.Position; var truePart = ReadNext(); if (IsInvalid(truePart)) { return(WrapErrToken($"{condition} ? {truePart}", truePart)); } if (_reader.BaseStream.Position != pos + trueSize) { return(ErrToken("conditional true part size mismatch")); } var falseSize = _reader.ReadInt16(); pos = _reader.BaseStream.Position; var falsePart = ReadNext(); if (IsInvalid(truePart)) { return(WrapErrToken($"{condition} ? {truePart} : {falsePart}", falsePart)); } Debug.Assert(_reader.BaseStream.Position == pos + falseSize); return(Token($"{condition} ? {truePart} : {falsePart}", readerpos)); } case ME1OpCodes.EX_DynArrayFind: return(ReadDynArray1ArgMethod("Find")); case ME1OpCodes.EX_DynArrayFindStruct: return(ReadDynArray2ArgMethod("Find", true)); case ME1OpCodes.EX_DynArrayRemove: return(ReadDynArray2ArgMethod("Remove", false)); case ME1OpCodes.EX_DynArrayInsert: return(ReadDynArray2ArgMethod("Insert", false)); case ME1OpCodes.EX_DynArrayAddItem: return(ReadDynArray1ArgMethod("AddItem")); case ME1OpCodes.EX_DynArrayRemoveItem: return(ReadDynArray1ArgMethod("RemoveItem")); case ME1OpCodes.EX_DynArrayInsertItem: return(ReadDynArray2ArgMethod("InsertItem", true)); case ME1OpCodes.EX_DynArrayIterator: { var array = ReadNext(); if (IsInvalid(array)) { return(array); } var iteratorVar = ReadNext(); if (IsInvalid(iteratorVar)) { return(iteratorVar); } _reader.ReadInt16(); var endOffset = _reader.ReadInt16(); return(new ForeachToken(endOffset, array, iteratorVar, readerpos)); } case ME1OpCodes.EX_DelegateProperty: case ME1OpCodes.EX_InstanceDelegate: return(Token(ReadName(), readerpos)); case ME1OpCodes.EX_DelegateFunction: { var receiver = ReadNext(); if (IsInvalid(receiver)) { return(receiver); } var methodName = ReadName(); if (receiver.ToString().StartsWith("__") && receiver.ToString().EndsWith("__Delegate")) { return(ReadCall(methodName)); } return(ReadCall(receiver + "." + methodName)); } case ME1OpCodes.EX_EqualEqual_DelDel: case ME1OpCodes.EX_EqualEqual_DelFunc: return(CompareDelegates("==")); case ME1OpCodes.EX_NotEqual_DelDel: return(CompareDelegates("!=")); default: if ((int)b >= 0x60) { return(ReadNativeCall((byte)b)); } return(ErrToken("// unknown bytecode " + ((byte)b).ToString("X2"), (int)b)); } }
private void hb1_SelectionChanged(object sender, EventArgs e) { if (!TokenChanging) { HexBoxSelectionChanging = true; int start = (int)ScriptEditor_Hexbox.SelectionStart; int len = (int)ScriptEditor_Hexbox.SelectionLength; int size = (int)ScriptEditor_Hexbox.ByteProvider.Length; //TODO: Optimize this so this is only called when data has changed byte[] currentData = (ScriptEditor_Hexbox.ByteProvider as DynamicByteProvider).Bytes.ToArray(); try { if (currentData != null && start != -1 && start < size) { string s = $"Byte: {currentData[start]}"; //if selection is same as size this will crash. if (start <= currentData.Length - 4) { int val = BitConverter.ToInt32(currentData, start); s += $", Int: {val}"; s += $", Float: {BitConverter.ToSingle(currentData, start)}"; if (CurrentLoadedExport.FileRef.isName(val)) { s += $", Name: {CurrentLoadedExport.FileRef.getNameEntry(val)}"; } if (CurrentLoadedExport.FileRef.Game == MEGame.ME1) { ME1OpCodes m = (ME1OpCodes)currentData[start]; s += $", OpCode: {m}"; } if (CurrentLoadedExport.FileRef.getEntry(val) is IEntry ent) { string type = ent is IExportEntry ? "Export" : "Import"; if (ent.ObjectName == CurrentLoadedExport.ObjectName) { s += $", {type}: {ent.GetFullPath}"; } else { s += $", {type}: {ent.ObjectName}"; } } } s += $" | Start=0x{start.ToString("X8")} "; if (len > 0) { s += $"Length=0x{len.ToString("X8")} "; s += $"End=0x{(start + len - 1).ToString("X8")}"; } StatusBar_LeftMostText.Text = s; } else { StatusBar_LeftMostText.Text = "Nothing Selected"; } } catch (Exception) { } //Find which decompiled script block the cursor belongs to ListBox selectedBox = null; List <ListBox> allBoxesToUpdate = new List <ListBox>(new ListBox[] { Function_ListBox, Function_Header, Function_Footer }); if (start >= 0x20 && start < CurrentLoadedExport.DataSize - 6) { Token token = null; foreach (object o in DecompiledScriptBlocks) { if (o is Token x && start >= x.pos && start < (x.pos + x.raw.Length)) { token = x; break; } } if (token != null) { Function_ListBox.SelectedItem = token; Function_ListBox.ScrollIntoView(token); } BytecodeSingularToken bst = TokenList.FirstOrDefault(x => x.StartPos == start); if (bst != null) { Tokens_ListBox.SelectedItem = bst; Tokens_ListBox.ScrollIntoView(bst); } selectedBox = Function_ListBox; } if (start >= 0x0C && start < 0x20) { //header int index = (start - 0xC) / 4; Function_Header.SelectedIndex = index; selectedBox = Function_Header; } if (start > CurrentLoadedExport.DataSize - 6) { //footer //yeah yeah I know this is very specific code. if (start == CurrentLoadedExport.DataSize - 6 || start == CurrentLoadedExport.DataSize - 5) { Function_Footer.SelectedIndex = 0; } else { Function_Footer.SelectedIndex = 1; } selectedBox = Function_Footer; } //deselect the other boxes if (selectedBox != null) { allBoxesToUpdate.Remove(selectedBox); } allBoxesToUpdate.ForEach(x => x.SelectedIndex = -1); HexBoxSelectionChanging = false; } }