예제 #1
0
        public static CodeInfo DisassembleCode(GMFileContent content, uint id)
        {
            if (content.General->BytecodeVersion > 0xE)
                throw new InvalidDataException("Cannot disassemble bytecode with version >0xE.");
            if (id >= content.Code->Count)
                throw new ArgumentOutOfRangeException(nameof(id));

            var re = (CodeEntry*)GMFile.PtrFromOffset(content, (&content.Code->Offsets)[id]);
            var len = re->Length;
            var bc = &re->Bytecode;

            var ret = new List<IntPtr>(); // doesn't like T* as type arg

            var l = Utils.PadTo(len, 4);
            AnyInstruction* instr;

            for (uint i = 0; i * 4 < l; /* see loop end */)
            {
                instr = (AnyInstruction*)(bc + i);

                ret.Add((IntPtr)instr);

                i += DisasmExt.Size(instr);
            }

            return new CodeInfo
            {
                Name         = SectionReader.StringFromOffset(content, re->Name),
                Instructions = Utils.MPtrListToPtrArr(ret)
            };
        }
예제 #2
0
        internal GMFile(GMFileContent f)
        {
            Content = f;

            General = SectionReader.GetGeneralInfo(f);
            Options = SectionReader.GetOptionInfo(f);

            Sound        = Utils.UintRange(0, f.Sounds->Count).Select(i => SectionReader.GetSoundInfo(f, i)).ToArray();
            Sprites      = Utils.UintRange(0, f.Sprites->Count).Select(i => SectionReader.GetSpriteInfo(f, i)).ToArray();
            Backgrounds  = Utils.UintRange(0, f.Backgrounds->Count).Select(i => SectionReader.GetBgInfo(f, i)).ToArray();
            Paths        = Utils.UintRange(0, f.Paths->Count).Select(i => SectionReader.GetPathInfo(f, i)).ToArray();
            Scripts      = Utils.UintRange(0, f.Scripts->Count).Select(i => SectionReader.GetScriptInfo(f, i)).ToArray();
            Fonts        = Utils.UintRange(0, f.Fonts->Count).Select(i => SectionReader.GetFontInfo(f, i)).ToArray();
            Objects      = Utils.UintRange(0, f.Objects->Count).Select(i => SectionReader.GetObjectInfo(f, i)).ToArray();
            Rooms        = Utils.UintRange(0, f.Rooms->Count).Select(i => SectionReader.GetRoomInfo(f, i)).ToArray();
            TexturePages = Utils.UintRange(0, f.TexturePages->Count).Select(i => SectionReader.GetTexPageInfo(f, i)).ToArray();
            Code         = Utils.UintRange(0, f.Code->Count).Select(i => Disassembler.DisassembleCode(f, i)).ToArray();
            Strings      = Utils.UintRange(0, f.Strings->Count).Select(i => SectionReader.GetStringInfo(f, i)).ToArray();
            Textures     = Utils.UintRange(0, f.Textures->Count).Select(i => SectionReader.GetTextureInfo(f, i)).ToArray();
            Audio        = Utils.UintRange(0, f.Audio->Count).Select(i => SectionReader.GetAudioInfo(f, i)).ToArray();

            AudioSoundMap = new Dictionary <uint, uint>();
            for (uint i = 0; i < Sound.Length; i++)
            {
                var s = Sound[i];

                if ((s.IsEmbedded || s.IsCompressed) && s.AudioId != -1)
                {
                    AudioSoundMap[(uint)s.AudioId] = i;
                }
            }

            var vars = General.IsOldBCVersion ? SectionReader.GetRefDefs(f, f.Variables) : SectionReader.GetRefDefsWithOthers(f, f.Variables);
            var fns  = General.IsOldBCVersion ? SectionReader.GetRefDefs(f, f.Functions) : SectionReader.GetRefDefsWithLength(f, f.Functions);

            RefData = new RefData
            {
                Variables = vars,
                Functions = fns,

                VarAccessors  = Disassembler.GetReferenceTable(f, vars),
                FuncAccessors = Disassembler.GetReferenceTable(f, fns)
            };
        }
예제 #3
0
        public static SectionHeaders ChunkOf(GMFileContent file, long offset)
        {
            var sorted = file.HeaderOffsets.OrderBy(i => i).ToArray();

            if (sorted.Length == 1)
            {
                return(*(SectionHeaders *)PtrFromOffset(file, sorted[0]));
            }

            for (int i = 0; i < sorted.Length - 1 && sorted[i + 1] != 0; i++)
            {
                if (offset == sorted[i] || offset > sorted[i] && (offset < sorted[i + 1] || sorted[i + 1] == 0))
                {
                    return(*(SectionHeaders *)PtrFromOffset(file, sorted[i]));
                }
            }

            return(SectionHeaders.Form);
        }
예제 #4
0
        // used to prove the chunk order doesn't matter
        unsafe static void SwapChunks(GMFileContent f)
        {
            int EmptyChunkSize = sizeof(SectionUnknown);

            var exntO = (long)f.Extensions - (long)f.RawData.BPtr;
            var tmlnO = (long)f.Timelines - (long)f.RawData.BPtr;

            byte[] extnT = new byte[EmptyChunkSize];

            ILHacks.Cpblk((IntPtr)f.Extensions, extnT, 0, EmptyChunkSize);
            ILHacks.Cpblk((IntPtr)f.Timelines, (IntPtr)f.Extensions, EmptyChunkSize);
            ILHacks.Cpblk(extnT, (IntPtr)f.Timelines, 0, EmptyChunkSize);

            byte[] EVERYTHING = new byte[f.RawData.Size];

            ILHacks.Cpblk(f.RawData.IPtr, EVERYTHING, 0, f.RawData.Size);

            File.WriteAllBytes("data.fake.win", EVERYTHING);
        }
예제 #5
0
        public static Dictionary<IntPtr, int> GetReferenceTable(GMFileContent content, ReferenceDef[] defs)
        {
            var ret = new Dictionary<IntPtr, int>(defs.Length);

            for (int i = 0; i < defs.Length; i++)
            {
                var offTotal = (long)defs[i].FirstOffset;
                var addr     = (AnyInstruction*)GMFile.PtrFromOffset(content, offTotal);

                for (int j = 0; j < defs[i].Occurrences /*&& curOffset != 0*/; j++)
                {
                    ret.Add((IntPtr)addr, i);

                    if (j < defs[i].Occurrences - 1) // at least one more iteration afterwards
                    {
                        var off = ((uint*)addr)[1] & 0x00FFFFFFL;

                        addr = (AnyInstruction*)GMFile.PtrFromOffset(content, offTotal += off); //! '+=', not '+'
                    }
                }
            }

            return ret;
        }
예제 #6
0
        public static Statement[] ParseStatements(GMFileContent content, RefData rdata, CodeInfo code, AnyInstruction*[] instr = null, Stack<Expression> stack = null, List<Expression> dupTars = null)
        {
            //! here be dragons

            stack   = stack   ?? new Stack<Expression>();
            dupTars = dupTars ?? new List <Expression>();
            instr   = instr   ?? code.Instructions;

            if (instr.Length == 0)
                return EmptyStmtArray;

            var stmts = new List<Statement>();

            var firstI = code.Instructions[0];

            //TODO: use locals

            Func<Expression> Pop  = () => stack.Count == 0 ? PopExpr : stack.Pop ();
          //Func<Expression> Peek = () => stack.Count == 0 ? PopExpr : stack.Peek();
            Func<int, IEnumerable<Expression>> PopMany = i =>
            {
                var ret = new List<Expression>();

                for (int j = 0; j < i; j++)
                    ret.Add(Pop());

                return ret;
            };
            #region Action FlushStack = () => { };
            Action FlushStack = () =>
            {
                var readd = new Stack<Expression>();

                //? not sure if this is a good idea (random 'push'es in the wild) (see TODO)
                stmts.AddRange(stack.PopAll().Where(e =>
                {
                    if (dupTars.Contains(e))
                    {
                        readd.Push(e);
                        return false;
                    }

                    return !(e is PopExpression); // 'push pop' is obviously stupid to emit
                }).Reverse().Select(e =>
                    e is UnaryOperatorExpression &&
                            ((UnaryOperatorExpression)e).Operator == UnaryOperator.Duplicate
                        ? (Statement)new DupStatement() : new PushStatement { Expr = e }));

                stack.PushRange(readd);
            };
            #endregion
            Action<Statement> AddStmt = s =>
            {
                FlushStack();

                stmts.Add(s);
            };
            Func<VariableType, Expression[]> TryGetIndices = vt =>
            {
                Expression index = null;

                var dimentions = 0;
                if (vt == VariableType.Array)
                {
                    index = Pop();

                    var arrInd = Pop();

                    if ((arrInd is LiteralExpression) && ((LiteralExpression)arrInd).Value is short)
                    {
                        var s = (short)((LiteralExpression)arrInd).Value;

                        switch (s)
                        {
                            case -1:
                                dimentions = 2;
                                break;
                            case -5:
                                dimentions = 1;
                                break;
                        }
                    }

                    if (dimentions == 0)
                    {
                        stack.Push(arrInd);
                        stack.Push(index);

                        index = null;
                    }
                }

                if (index == null)
                    return null;

                // analyse index for specified dimention
                switch (dimentions)
                {
                    case 2:
                        if (index is BinaryOperatorExpression && ((BinaryOperatorExpression)index).Operator == BinaryOperator.Addition)
                        {
                            var boe = (BinaryOperatorExpression)index;

                            var a = boe.Arg1;
                            var b = boe.Arg2;

                            if (a is BinaryOperatorExpression && ((BinaryOperatorExpression)a).Operator == BinaryOperator.Multiplication)
                            {
                                var a_ = (BinaryOperatorExpression)a;
                                var c = a_.Arg2;

                                if (c is LiteralExpression && ((LiteralExpression)c).ReturnType == DataType.Int32
                                        && (int /* should be */)((LiteralExpression)c).Value == 32000)
                                    return new[] { a_.Arg1, b };
                            }
                        }
                        break;
                }

                return new[] { index };
            };

            for (int i = 0; i < instr.Length; i++)
            {
                var ins = instr[i];

                #region stuff
                var pst = (SingleTypeInstruction*)ins;
                var pdt = (DoubleTypeInstruction*)ins;
                var pcl = (CallInstruction      *)ins;
                var pps = (PushInstruction      *)ins;
                var pse = (SetInstruction       *)ins;
                var pbr = (GotoInstruction      *)ins;
                var pbk = (BreakInstruction     *)ins;

                var st = ins->SingleType;
                var dt = ins->DoubleType;
                var cl = ins->Call      ;
                var ps = ins->Push      ;
                var se = ins->Set       ;

                var t1 = ins->Kind() == InstructionKind.SingleType ? st.Type
                      : (ins->Kind() == InstructionKind.DoubleType ? dt.Types.Type1 : 0);
                var t2 = ins->Kind() == InstructionKind.DoubleType ? dt.Types.Type2
                      : (ins->Kind() == InstructionKind.SingleType ? st.Type        : 0);
                #endregion

                switch (ins->Code())
                {
                    #region dup, pop
                    case OpCode.Dup:
                        var normal = true;
                        if (i < instr.Length - 1 && instr[i + 1]->OpCode == OpCode.Push)
                        {
                            var n = &instr[i + 1]->Push;
                            var t = ((Reference*)&n->ValueRest)->Type;

                            if (t == VariableType.Array && stack.Count > 1)
                            {
                                normal = false;

                                stack.Push(stack.Skip(1).First()); // second item
                                stack.Push(stack.Skip(1).First()); // first  item (original stack top)
                            }
                        }

                        if (!normal)
                            break;

                        if (!dupTars.Contains(stack.Peek()))
                            dupTars.Add(stack.Peek());

                        if (stack.Peek().WalkExprTree(e => e is CallExpression).Any(_ => _))
                        {
                            stack.Push(new UnaryOperatorExpression
                            {
                                Input        = stack.Peek(),
                                Operator     = UnaryOperator.Duplicate,
                                OriginalType = stack.Peek().ReturnType,
                                ReturnType   = st.Type
                            });

                            //AddStmt(new DupStatement());
                        }
                        else
                            stack.Push(stack.Peek());
                        break;
                    case OpCode.Pop:
                        if (stack.Count > 0 && stack.Peek() is CallExpression)
                            AddStmt(new CallStatement
                            {
                                Call = stack.Pop() as CallExpression
                            });
                        else
                            AddStmt(new PopStatement());
                        break;
                    #endregion
                    #region env
                    //TODO: use actual '(with obj ...)' syntax
                    //! it might mess with the CFG structure
                    case OpCode.PushEnv:
                        AddStmt(new PushEnvStatement
                        {
                            Target       = (AnyInstruction*)((byte*)ins + pbr->Offset * 4L),
                            TargetOffset = (byte*)ins + pbr->Offset * 4L - (byte*)firstI,
                            Parent       = stack.Pop()
                        });
                        break;
                    case OpCode.PopEnv :
                        AddStmt(new PopEnvStatement
                        {
                            Target       = (AnyInstruction*)((byte*)ins + pbr->Offset * 4L),
                            TargetOffset = (byte*)ins + pbr->Offset * 4L - (byte*)firstI
                        });
                        break;
                    #endregion
                    #region branch
                    case OpCode.Brt:
                    case OpCode.Brf:
                    case OpCode.Br:
                        AddStmt(new BranchStatement
                        {
                            Type         = pbr->Type(),
                            Conditional  = pbr->Type() == BranchType.Unconditional ? null : Pop(),
                            Target       = (AnyInstruction*)((byte*)ins + pbr->Offset * 4L),
                            TargetOffset = (byte*)ins + pbr->Offset * 4L - (byte*)firstI
                        });
                        break;
                    #endregion
                    #region break, ret, exit
                    case OpCode.Break:
                        stack.Push(new AssertExpression
                        {
                            ControlValue = pbk->Signal,
                            ReturnType   = pbk->Type,
                            Expr         = Pop()
                        });
                        break;
                    case OpCode.Ret:
                        AddStmt(new ReturnStatement
                        {
                            ReturnType = pst->Type,
                            RetValue   = Pop()
                        });
                        break;
                    case OpCode.Exit:
                        AddStmt(new ExitStatement());
                        break;
                    #endregion
                    #region set
                    case OpCode.Set:
                        var ind = TryGetIndices(se.DestVar.Type); // call before Value's pop
                        AddStmt(new SetStatement
                        {
                            OriginalType = se.Types.Type1,
                            ReturnType   = se.Types.Type2,
                            Type         = se.DestVar.Type,
                            OwnerType    = se.Instance,
                            OwnerName    = se.Instance > InstanceType.StackTopOrGlobal ? SectionReader.GetObjectInfo(content, (uint)se.Instance).Name : null,
                            Target       = rdata.Variables[rdata.VarAccessors[(IntPtr)ins]],
                            Value        = Pop(),
                            ArrayIndices = ind ?? TryGetIndices(se.DestVar.Type)
                        });
                        break;
                    #endregion
                    default:
                        switch (ins->ExprType())
                        {
                            #region variable
                            case ExpressionType.Variable:
                                var vt = ((Reference*)&pps->ValueRest)->Type;

                                if (vt == VariableType.StackTop && (InstanceType)ps.Value == InstanceType.StackTopOrGlobal)
                                {
                                    stack.Push(new MemberExpression
                                    {
                                        Owner        = Pop(),
                                        ReturnType   = ps.Type,
                                        Type         = vt,
                                        OwnerType    = (InstanceType)ps.Value,
                                        OwnerName    = se.Instance > InstanceType.StackTopOrGlobal ? SectionReader.GetObjectInfo(content, (uint)se.Instance).Name : null,
                                        Variable     = rdata.Variables[rdata.VarAccessors[(IntPtr)ins]],
                                        ArrayIndices = TryGetIndices(vt)
                                    });
                                }
                                else
                                    stack.Push(new VariableExpression
                                    {
                                        ReturnType   = ps.Type,
                                        Type         = vt,
                                        OwnerType    = (InstanceType)ps.Value,
                                        Variable     = rdata.Variables[rdata.VarAccessors[(IntPtr)ins]],
                                        ArrayIndices = TryGetIndices(vt)
                                    });
                                break;
                            #endregion
                            #region literal
                            case ExpressionType.Literal:
                                object v         = null;
                                var rest         = &pps->ValueRest;

                                #region get value
                                switch (ps.Type)
                                {
                                    case DataType.Int16:
                                        v = ps.Value;
                                        break;
                                    case DataType.Boolean:
                                        v = ((DwordBool*)rest)->IsTrue();
                                        break;
                                    case DataType.Double:
                                        v = *(double*)rest;
                                        break;
                                    case DataType.Single:
                                        v = *(float*)rest;
                                        break;
                                    case DataType.Int32:
                                        v = *(int*)rest;
                                        break;
                                    case DataType.Int64:
                                        v = *(long*)rest;
                                        break;
                                    case DataType.String:
                                        v = SectionReader.GetStringInfo(content, ps.ValueRest);
                                        break;
                                }
                                #endregion

                                stack.Push(new LiteralExpression
                                {
                                    ReturnType = ps.Type,
                                    Value      = v
                                });
                                break;
                            #endregion
                            #region call
                            case ExpressionType.Call:
                                stack.Push(new CallExpression
                                {
                                    ReturnType = cl.ReturnType,
                                    Type       = cl.Function.Type,
                                    Function   = rdata.Functions[rdata.FuncAccessors[(IntPtr)ins]],
                                    Arguments  = PopMany(cl.Arguments).Reverse().ToArray()
                                });
                                break;
                            #endregion
                            #region binaryop
                            case ExpressionType.BinaryOp:
                                var a1 = Pop();
                                var a2 = Pop();

                                stack.Push(new BinaryOperatorExpression
                                {
                                    OriginalType = t1,
                                    ReturnType   = t2,
                                    Arg1         = a2,
                                    Arg2         = a1,
                                    Operator     = ins->BinaryOp()
                                });
                                break;
                            #endregion
                            #region unaryop
                            case ExpressionType.UnaryOp:
                                stack.Push(new UnaryOperatorExpression
                                {
                                    OriginalType = t1,
                                    ReturnType   = t2,
                                    Input        = Pop(),
                                    Operator     = ins->UnaryOp()
                                });
                                break;
                            #endregion
                        }
                        break;
                }
            }

            FlushStack();

            return stmts.ToArray();
        }
예제 #7
0
        public static GraphVertex[] BuildCFGraph(GMFileContent content, CodeInfo code)
        {
            if (code.Instructions.Length == 0)
                return EmptyGVArray;

            return CreateVertices(content, code);
        }
예제 #8
0
        static GraphVertex[] CreateVertices(GMFileContent content, CodeInfo code)
        {
            var blocks = SplitBlocks(code);
            var instr = code.Instructions;
            var firstI = (long)instr[0];

            // only one block -> just return it as a single vertex
            if (blocks.Length == 1)
                return new[]
                {
                    new GraphVertex
                    {
                        Branches     = EmptyGBArray,
                        Instructions = blocks[0].Instructions
                    }
                };

            var vertices = new GraphVertex[blocks.Length];

            // create list of vertices
            for (int i = 0; i < blocks.Length; i++)
            {
                var blk     = blocks[i];
                var hasNext = i < blocks.Length - 1 && blk.Type != BranchType.Unconditional /* no need to check if uncond */;

                vertices[i] = new GraphVertex
                {
                    Instructions = blk.Instructions,
                    Branches     = new GraphBranch[hasNext ? 2 : 1]
                };

                vertices[i].Branches[0] = new GraphBranch
                {
                    BranchTo = blk.BranchTo,
                    Type     = blk.Type
                };

                if (hasNext)
                    vertices[i].Branches[1] = new GraphBranch
                    {
                        BranchTo = blocks[i + 1].Instructions[0],
                        Type     = blk.Type.Invert()
                    };
            }

            // connect vertex branches to target vertices
            for (int i = 0; i < vertices.Length; i++)
            {
                var v = vertices[i];

                for (int j = 0; j < v.Branches.Length; j++)
                    v.Branches[j].ToVertex =
                        vertices.FirstOrDefault(ve => ve.Instructions[0] == v.Branches[j].BranchTo)
                            ?? (i == vertices.Length - 1 ? null : vertices[i + 1]);
            }

            return vertices;
        }
예제 #9
0
 public static void *PtrFromOffset(GMFileContent file, long offset) => file.RawData.BPtr + offset;
예제 #10
0
        internal GMFile(GMFileContent f)
        {
            Content = f;

            var orderList = new List <SectionHeaders>(f.HeaderOffsets.Length);

            foreach (long headerOffset in f.HeaderOffsets)
            {
                SectionHeaders tag = ((SectionHeader *)((byte *)f.Form + headerOffset))->Identity;
                if (tag != SectionHeaders.Form)
                {
                    orderList.Add(tag);
                }
            }
            ChunkOrder = orderList.ToArray();

            if (f.General != null)
            {
                General = SectionReader.GetGeneralInfo(f);
            }
            if (f.Options != null)
            {
                Options = SectionReader.GetOptionInfo(f);
            }
            if (f.Globals != null)
            {
                Globals = SectionReader.GetGlobalInfo(f);
            }

            Sound = MkLazyArr(f.Sounds, i => SectionReader.GetSoundInfo(f, i));

            if (f.TexturePages != null)
            {
                var toil = SectionReader.BuildTPAGOffsetIndexLUT(f);
                Sprites = MkLazyArr(f.Sprites, i => SectionReader.GetSpriteInfo(f, i, toil));
            }

            Backgrounds  = MkLazyArr(f.Backgrounds, i => SectionReader.GetBgInfo(f, i));
            Paths        = MkLazyArr(f.Paths, i => SectionReader.GetPathInfo(f, i));
            Scripts      = MkLazyArr(f.Scripts, i => SectionReader.GetScriptInfo(f, i));
            Fonts        = MkLazyArr(f.Fonts, i => SectionReader.GetFontInfo(f, i));
            Objects      = MkLazyArr(f.Objects, i => SectionReader.GetObjectInfo(f, i));
            Rooms        = MkLazyArr(f.Rooms, i => SectionReader.GetRoomInfo(f, i));
            TexturePages = MkLazyArr(f.TexturePages, i => SectionReader.GetTexPageInfo(f, i));
            Code         = MkLazyArr(f.Code, i => Disassembler.DisassembleCode(f, i));
            Strings      = MkLazyArr(f.Strings, i => SectionReader.GetStringInfo(f, i));
            Textures     = MkLazyArr(f.Textures, i => SectionReader.GetTextureInfo(f, i));
            Audio        = MkLazyArr(f.Audio, i => SectionReader.GetAudioInfo(f, i));
            AudioGroups  = MkLazyArr(f.AudioGroup, i => SectionReader.GetAudioGroupInfo(f, i));
            Extensions   = MkLazyArr(f.Extensions, i => SectionReader.GetExtensionInfo(f, i));
            Shaders      = MkLazyArr(f.Shaders, i => SectionReader.GetShaderInfo(f, i));
            Timelines    = MkLazyArr(f.Timelines, i => SectionReader.GetTimelineInfo(f, i));

            AudioSoundMap = new Dictionary <uint, uint>();
            if (f.Sounds != null)
            {
                for (uint i = 0; i < Sound.Length; i++)
                {
                    var s = Sound[i];

                    if ((s.IsEmbedded || s.IsCompressed) && s.AudioID != -1 && s.GroupID == 0)
                    {
                        AudioSoundMap[(uint)s.AudioID] = i;
                    }
                }
            }

            if (f.General == null)
            {
                return;
            }

            try
            {
                // TODO: do this in a better way
                var vars = General.IsOldBCVersion
                    ? SectionReader.GetRefDefs(f, f.Variables)
                    : SectionReader.GetRefDefsWithOthers(f, f.Variables);
                var fns = General.IsOldBCVersion
                    ? SectionReader.GetRefDefs(f, f.Functions)
                    : SectionReader.GetRefDefsWithLength(f, f.Functions);

                var varacc = Disassembler.GetReferenceTable(f, vars);
                var fnacc  = Disassembler.GetReferenceTable(f, fns);

                RefData = new RefData
                {
                    Variables     = vars,
                    Functions     = fns,
                    VarAccessors  = varacc,
                    FuncAccessors = fnacc
                };

                if (f.Functions->Entries.NameOffset * 12 < f.Functions->Header.Size)
                {
                    FunctionLocals = SectionReader.GetFunctionLocals(f, f.Functions);
                }
                if (f.Variables != null && !General.IsOldBCVersion)
                {
                    VariableExtra = new uint[]
                    {
                        ((uint *)&f.Variables->Entries)[0],
                        ((uint *)&f.Variables->Entries)[1],
                        ((uint *)&f.Variables->Entries)[2]
                    }
                }
                ;
            }
            catch (Exception e)
            {
                Console.Error.WriteLine("Warning: Can't figure out RefDef pairs. Exception:");
                Console.Error.WriteLine(e);
            }
        }
예제 #11
0
        public static unsafe SectionHeaders ChunkOf(GMFileContent file, long offset)
        {
            var sorted = file.HeaderOffsets.OrderBy(i => i).ToArray();

            if (sorted.Length == 1)
                return *(SectionHeaders*)PtrFromOffset(file, sorted[0]);

            for (int i = 0; i < sorted.Length - 1 && sorted[i + 1] != 0; i++)
                if (offset == sorted[i] || offset > sorted[i] && (offset < sorted[i + 1] || sorted[i + 1] == 0))
                    return *(SectionHeaders*)PtrFromOffset(file, sorted[i]);

            return SectionHeaders.Form;
        }
예제 #12
0
        public static GMFile GetFile(byte[] data)
        {
            var ret = new GMFileContent();

            var   hdr_bp = new UniquePtr(data);
            byte *hdr_b  = hdr_bp.BPtr;

            var basePtr = (SectionHeader *)hdr_b;

            ret.Form = basePtr;

            if (ret.Form->Identity != SectionHeaders.Form)
            {
                throw new InvalidDataException(ERR_NO_FORM);
            }

            SectionHeader *
                hdr    = basePtr + 1,
                hdrEnd = (SectionHeader *)((IntPtr)basePtr + (int)ret.Form->Size);

            int headersMet = 0;

            while (hdr < hdrEnd)
            {
                switch (hdr->Identity)
                {
                case SectionHeaders.General:
                    ret.General = (SectionGeneral *)hdr;
                    break;

                case SectionHeaders.Options:
                    ret.Options = (SectionOptions *)hdr;
                    break;

                case SectionHeaders.Extensions:
                    ret.Extensions = (SectionUnknown *)hdr;
                    break;

                case SectionHeaders.Sounds:
                    ret.Sounds = (SectionCountOffsets *)hdr;
                    break;

                case SectionHeaders.Sprites:
                    ret.Sprites = (SectionCountOffsets *)hdr;
                    break;

                case SectionHeaders.Backgrounds:
                    ret.Backgrounds = (SectionCountOffsets *)hdr;
                    break;

                case SectionHeaders.Paths:
                    ret.Paths = (SectionCountOffsets *)hdr;
                    break;

                case SectionHeaders.Scripts:
                    ret.Scripts = (SectionCountOffsets *)hdr;
                    break;

                case SectionHeaders.Shaders:
                    ret.Shaders = (SectionUnknown *)hdr;
                    break;

                case SectionHeaders.Fonts:
                    ret.Fonts = (SectionCountOffsets *)hdr;
                    break;

                case SectionHeaders.Timelines:
                    ret.Timelines = (SectionUnknown *)hdr;
                    break;

                case SectionHeaders.Objects:
                    ret.Objects = (SectionCountOffsets *)hdr;
                    break;

                case SectionHeaders.Rooms:
                    ret.Rooms = (SectionCountOffsets *)hdr;
                    break;

                case SectionHeaders.DataFiles:
                    ret.DataFiles = (SectionUnknown *)hdr;
                    break;

                case SectionHeaders.TexturePage:
                    ret.TexturePages = (SectionCountOffsets *)hdr;
                    break;

                case SectionHeaders.Code:
                    ret.Code = (SectionCountOffsets *)hdr;
                    break;

                case SectionHeaders.Variables:
                    ret.Variables = (SectionRefDefs *)hdr;
                    break;

                case SectionHeaders.Functions:
                    ret.Functions = (SectionRefDefs *)hdr;
                    break;

                case SectionHeaders.Strings:
                    ret.Strings = (SectionCountOffsets *)hdr;
                    break;

                case SectionHeaders.Textures:
                    ret.Textures = (SectionCountOffsets *)hdr;
                    break;

                case SectionHeaders.Audio:
                    ret.Audio = (SectionCountOffsets *)hdr;
                    break;

                case SectionHeaders.AudioGroup:
                    ret.AudioGroup = (SectionUnknown *)hdr;
                    break;
                }

                ret.HeaderOffsets[headersMet++] = (byte *)hdr - (byte *)basePtr;
                hdr = unchecked ((SectionHeader *)((IntPtr)hdr + (int)hdr->Size) + 1);
            }

            ret.RawData = hdr_bp;

            return(new GMFile(ret));
        }
예제 #13
0
        public static GMFile GetFile(byte[] data)
        {
            var ret = new GMFileContent();

            var   hdr_bp = new UniquePtr(data);
            byte *hdr_b  = hdr_bp.BPtr;

            var basePtr = (SectionHeader *)hdr_b;

            ret.Form = basePtr;

            if (ret.Form->Identity != SectionHeaders.Form)
            {
                throw new InvalidDataException(ERR_NO_FORM);
            }

            SectionHeader *
                hdr    = basePtr + 1,
                hdrEnd = (SectionHeader *)((IntPtr)basePtr + (int)ret.Form->Size);

            int headersMet = 0;

            while (hdr < hdrEnd)
            {
                switch (hdr->Identity)
                {
                case SectionHeaders.General:
                    ret.General = (SectionGeneral *)hdr;
                    break;

                case SectionHeaders.Options:
                    ret.Options = (SectionOptions *)hdr;
                    break;

                case SectionHeaders.Extensions:
                    ret.Extensions = (SectionUnknown *)hdr;

                    if (!ret.Extensions->IsEmpty())
                    {
                        Console.WriteLine("Warning: EXTN chunk is not empty, its content will not be exported!");
                    }
                    break;

                case SectionHeaders.Sounds:
                    ret.Sounds = (SectionCountOffsets *)hdr;
                    break;

                case SectionHeaders.Sprites:
                    ret.Sprites = (SectionCountOffsets *)hdr;
                    break;

                case SectionHeaders.Backgrounds:
                    ret.Backgrounds = (SectionCountOffsets *)hdr;
                    break;

                case SectionHeaders.Paths:
                    ret.Paths = (SectionCountOffsets *)hdr;
                    break;

                case SectionHeaders.Scripts:
                    ret.Scripts = (SectionCountOffsets *)hdr;
                    break;

                case SectionHeaders.Shaders:
                    ret.Shaders = (SectionUnknown *)hdr;

                    if (!ret.Shaders->IsEmpty())
                    {
                        Console.WriteLine("Warning: SHDR chunk is not empty, its content will not be exported!");
                    }
                    break;

                case SectionHeaders.Fonts:
                    ret.Fonts = (SectionCountOffsets *)hdr;
                    break;

                case SectionHeaders.Timelines:
                    ret.Timelines = (SectionUnknown *)hdr;

                    if (!ret.Timelines->IsEmpty())
                    {
                        Console.WriteLine("Warning: TMLN chunk is not empty, its content will not be exported!");
                    }
                    break;

                case SectionHeaders.Objects:
                    ret.Objects = (SectionCountOffsets *)hdr;
                    break;

                case SectionHeaders.Rooms:
                    ret.Rooms = (SectionCountOffsets *)hdr;
                    break;

                case SectionHeaders.DataFiles:
                    ret.DataFiles = (SectionUnknown *)hdr;

                    if (!ret.DataFiles->IsEmpty())
                    {
                        Console.WriteLine("Warning: DAFL chunk is not empty, its content will not be exported!");
                    }
                    break;

                case SectionHeaders.TexturePage:
                    ret.TexturePages = (SectionCountOffsets *)hdr;
                    break;

                case SectionHeaders.Code:
                    ret.Code = (SectionCountOffsets *)hdr;
                    break;

                case SectionHeaders.Variables:
                    ret.Variables = (SectionRefDefs *)hdr;
                    break;

                case SectionHeaders.Functions:
                    ret.Functions = (SectionRefDefs *)hdr;
                    break;

                case SectionHeaders.Strings:
                    ret.Strings = (SectionCountOffsets *)hdr;
                    break;

                case SectionHeaders.Textures:
                    ret.Textures = (SectionCountOffsets *)hdr;
                    break;

                case SectionHeaders.Audio:
                    ret.Audio = (SectionCountOffsets *)hdr;
                    break;

                case SectionHeaders.AudioGroup:
                    ret.AudioGroup = (SectionUnknown *)hdr;

                    if (!ret.AudioGroup->IsEmpty())
                    {
                        Console.WriteLine("Warning: AGRP chunk is not empty, its content will not be exported!");
                    }
                    break;

                case SectionHeaders.GNAL_Unk:
                    ret.GNAL_Unk = (SectionUnknown *)hdr;

                    if (!ret.GNAL_Unk->IsEmpty())
                    {
                        Console.WriteLine("Warning: GNAL chunk is not empty, its content will not be exported!");
                    }
                    break;

                default:
                    var unk = (SectionUnknown *)hdr;
                    if (!unk->IsEmpty())
                    {
                        Console.WriteLine($"Warning: unknown chunk {hdr->Identity.ToChunkName()}, chunk is not empty, its content will not be exported!");
                    }

                    ret.UnknownChunks.Add(hdr->Identity, (IntPtr)unk);
                    break;
                }

                for (int i = 0; i < ret.HeaderOffsets.Length; i++)
                {
                    if (((SectionHeader *)((byte *)basePtr + ret.HeaderOffsets[i]))->Identity == hdr->Identity)
                    {
                        Console.WriteLine($"WARNING: chunk {hdr->MagicString()} encountered (at least) twice! Only the last occurrence will be exported! (If you see this message, consider reversing manually.)");
                    }
                }

                if (ret.HeaderOffsets.Length >= headersMet)
                {
                    var ho = ret.HeaderOffsets;

                    Array.Resize(ref ho, (headersMet == ret.HeaderOffsets.Length) ? 1 : (headersMet + 2));

                    ret.HeaderOffsets = ho;
                }

                ret.HeaderOffsets[headersMet++] = (byte *)hdr - (byte *)basePtr;
                hdr = unchecked ((SectionHeader *)((IntPtr)hdr + (int)hdr->Size) + 1);
            }

            ret.RawData = hdr_bp;

            return(new GMFile(ret));
        }
예제 #14
0
        public unsafe static GMFileContent GetFile(byte[] data)
        {
            var ret = new GMFileContent();

            var hdr_bp = new UniquePtr(data);
            byte* hdr_b = hdr_bp.BPtr;

            var basePtr = (SectionHeader*)hdr_b;

            ret.Form = basePtr;

            if (ret.Form->Identity != SectionHeaders.Form)
                throw new InvalidDataException(ERR_NO_FORM);

            SectionHeader*
                hdr = basePtr + 1,
                hdrEnd = (SectionHeader*)((IntPtr)basePtr + (int)ret.Form->Size);

            int headersMet = 0;

            while (hdr < hdrEnd)
            {
                switch (hdr->Identity)
                {
                    case SectionHeaders.General:
                        ret.General = (SectionGeneral*)hdr;
                        break;
                    case SectionHeaders.Options:
                        ret.Options = (SectionOptions*)hdr;
                        break;
                    case SectionHeaders.Extensions:
                        ret.Extensions = (SectionUnknown*)hdr;
                        break;
                    case SectionHeaders.Sounds:
                        ret.Sounds = (SectionCountOffsets*)hdr;
                        break;
                    case SectionHeaders.Sprites:
                        ret.Sprites = (SectionCountOffsets*)hdr;
                        break;
                    case SectionHeaders.Backgrounds:
                        ret.Backgrounds = (SectionCountOffsets*)hdr;
                        break;
                    case SectionHeaders.Paths:
                        ret.Paths = (SectionCountOffsets*)hdr;
                        break;
                    case SectionHeaders.Scripts:
                        ret.Scripts = (SectionCountOffsets*)hdr;
                        break;
                    case SectionHeaders.Shaders:
                        ret.Shaders = (SectionUnknown*)hdr;
                        break;
                    case SectionHeaders.Fonts:
                        ret.Fonts = (SectionCountOffsets*)hdr;
                        break;
                    case SectionHeaders.Timelines:
                        ret.Timelines = (SectionUnknown*)hdr;
                        break;
                    case SectionHeaders.Objects:
                        ret.Objects = (SectionCountOffsets*)hdr;
                        break;
                    case SectionHeaders.Rooms:
                        ret.Rooms = (SectionCountOffsets*)hdr;
                        break;
                    case SectionHeaders.DataFiles:
                        ret.DataFiles = (SectionUnknown*)hdr;
                        break;
                    case SectionHeaders.TexturePage:
                        ret.TexturePages = (SectionCountOffsets*)hdr;
                        break;
                    case SectionHeaders.Code:
                        ret.Code = (SectionCountOffsets*)hdr;
                        break;
                    case SectionHeaders.Variables:
                        ret.Variables = (SectionRefDefs*)hdr;
                        break;
                    case SectionHeaders.Functions:
                        ret.Functions = (SectionRefDefs*)hdr;
                        break;
                    case SectionHeaders.Strings:
                        ret.Strings = (SectionCountOffsets*)hdr;
                        break;
                    case SectionHeaders.Textures:
                        ret.Textures = (SectionCountOffsets*)hdr;
                        break;
                    case SectionHeaders.Audio:
                        ret.Audio = (SectionCountOffsets*)hdr;
                        break;
                    case SectionHeaders.AudioGroup:
                        ret.AudioGroup = (SectionUnknown*)hdr;
                        break;
                }

                ret.HeaderOffsets[headersMet++] = (byte*)hdr - (byte*)basePtr;
                hdr = unchecked((SectionHeader*)((IntPtr)hdr + (int)hdr->Size) + 1);
            }

            ret.RawData = hdr_bp;

            return ret;
        }
예제 #15
0
        public static string DecompileCode(GMFileContent content, RefData rdata, CodeInfo code)
        {
            if (code.Instructions.Length == 0)
                return String.Empty;

            var sb = new StringBuilder();

            var stack = new Stack<Expression>();
            var dupts = new List <Expression>();

            var firstI = (long)code.Instructions[0];

            var graph = BuildCFGraph(content, code);

            //TODO: CFG kind recognition stuff (if, if/else, for, while, etc)
            var i = 0;
            foreach (var g in graph)
            {
                var stmts = ParseStatements(content, rdata, code, g.Instructions, stack);

                sb  .Append(SR.HEX_PRE)
                    .Append(((long)g.Instructions[0] - firstI).ToString(SR.HEX_FM6))
                    .AppendLine(SR.COLON);

                foreach (var s in stmts)
                    sb.Append(SR.INDENT4).AppendLine(s.ToString());

                i++;
            }

            sb.Append(SR.INDENT4).AppendLine(FinalRet.ToString());

            return sb.ToString();
        }
예제 #16
0
        public static string DisplayInstructions(GMFileContent content, RefData rdata, CodeInfo code, AnyInstruction*[] instructions = null)
        {
            var instrs = instructions ?? code.Instructions;

            if (instrs.Length == 0)
                return String.Empty;

            var sb = new StringBuilder();

            var firstI = code.Instructions[0];

            for (int i = 0; i < instrs.Length; i++)
            {
                var iptr = instrs[i];
                var relInstr = (long)iptr - (long)firstI;

                sb  .Append(HEX_PRE).Append(relInstr.ToString(HEX_FM6))
                    .Append(' ').Append(iptr->Code().ToPrettyString()).Append(' ');

                switch (iptr->Kind())
                {
                    case InstructionKind.SingleType:
                        var st = iptr->SingleType;

                        sb.Append(st.Type.ToPrettyString());
                        break;
                    case InstructionKind.DoubleType:
                        var dt = iptr->DoubleType;

                        sb.Append(dt.Types);
                        break;
                    case InstructionKind.Goto:
                        var g = iptr->Goto;

                        sb.Append(HEX_PRE).Append((relInstr + g.Offset * 4L).ToString(HEX_FM6));
                        break;

                    #region set
                    case InstructionKind.Set:
                        var s = iptr->Set;

                        sb.Append(s.Types).Append(' ');

                        if (s.Instance <= InstanceType.StackTopOrGlobal)
                            sb.Append(s.Instance.ToPrettyString());
                        else
                        {
                            var o = SectionReader.GetObjectInfo(content, (uint)s.Instance);

                            sb.Append('[').Append(o.Name).Append(']');
                        }

                        sb.Append(':');

                        sb.Append(rdata.Variables[rdata.VarAccessors[(IntPtr)iptr]].Name);
                        sb.Append(s.DestVar.Type.ToPrettyString());
                        break;
                    #endregion
                    #region push
                    case InstructionKind.Push:
                        var pp = (PushInstruction*)iptr;
                        var p = iptr->Push;

                        sb.Append(p.Type.ToPrettyString()).Append(' ');

                        var r = p.ValueRest;

                        switch (p.Type)
                        {
                            case DataType.Int16:
                                sb.Append(p.Value.ToString(CultureInfo.InvariantCulture));
                                break;
                            case DataType.Variable:
                                var rv = *(Reference*)&r;

                                var inst = (InstanceType)p.Value;

                                if (inst <= InstanceType.StackTopOrGlobal)
                                    sb.Append(inst.ToPrettyString());
                                else
                                {
                                    var o = SectionReader.GetObjectInfo(content, (uint)inst);

                                    sb.Append('[').Append(o.Name).Append(']');
                                }
                                sb.Append(':');

                                sb.Append(rdata.Variables[rdata.VarAccessors[(IntPtr)iptr]].Name);
                                sb.Append(rv.Type.ToPrettyString());
                                break;
                            case DataType.Boolean:
                                sb.Append(((DwordBool*)&r)->ToPrettyString());
                                break;
                            case DataType.Double:
                                sb.Append(((double*)&r)->ToString(CultureInfo.InvariantCulture));
                                break;
                            case DataType.Single:
                                sb.Append(((float*)&r)->ToString(CultureInfo.InvariantCulture));
                                break;
                            case DataType.Int32:
                                sb.Append(unchecked((int)r).ToString(CultureInfo.InvariantCulture));
                                break;
                            case DataType.Int64:
                                sb.Append(((long*)&pp->ValueRest)->ToString(CultureInfo.InvariantCulture));
                                break;
                            case DataType.String:
                                sb.Append(SectionReader.GetStringInfo(content, p.ValueRest).Escape());
                                break;
                        }
                        break;
                    #endregion
                    #region call
                    case InstructionKind.Call:
                        var c = iptr->Call;

                        sb.Append(c.ReturnType.ToPrettyString()).Append(':')
                            .Append(c.Arguments).Append(' ');

                        sb.Append(rdata.Functions[rdata.FuncAccessors[(IntPtr)iptr]].Name);
                        sb.Append(c.Function.Type.ToPrettyString());
                        break;
                    #endregion

                    case InstructionKind.Break:
                        var b = iptr->Break;

                        sb.Append(b.Type.ToPrettyString()).Append(' ').Append(b.Signal);
                        break;
                }

                sb.AppendLine();
            }

            return sb.ToString();
        }
예제 #17
0
 public static unsafe void* PtrFromOffset(GMFileContent file, long offset) => file.RawData.BPtr + offset;