Beispiel #1
0
        public static CodeInfo DeserializeCodeFromFile(string filename, uint bcv,
                                                       StringsListBuilder strings, IDictionary <string, uint> objectIndices)
        {
            IEnumerable <Instruction> instructions;

            if (filename.ToLowerInvariant().EndsWith(SR.EXT_GML_ASM))
            {
                instructions = Parser.Parse(Tokenizer.Tokenize(File.ReadAllText(filename)));
            }
            else if (filename.ToLowerInvariant().EndsWith(SR.EXT_GML_LSP))
            {
                // TODO
                throw new NotImplementedException();
            }
            else
            {
                throw new InvalidDataException("Unknown code format for '" + filename + "'");
            }
            return(DeserializeAssembly(Path.GetFileNameWithoutExtension(filename), instructions, bcv,
                                       strings, objectIndices));
        }
Beispiel #2
0
        public static CodeInfo DeserializeCodeFromFile(string filename, uint bcv,
                                                       StringsListBuilder strings, IDictionary <string, uint> objectIndices)
        {
            IEnumerable <Instruction> instructions;

            if (filename.EndsWith(SR.EXT_GML_ASM, StringComparison.InvariantCultureIgnoreCase))
            {
                instructions = Parser.Parse(Tokenizer.Tokenize(File.ReadAllText(filename)));
            }
            else if (filename.EndsWith(SR.EXT_GML_LSP, StringComparison.InvariantCultureIgnoreCase))
            {
                // TODO
                throw new NotImplementedException("Compiling LSP not supported; export ASM with --project or -d");
            }
            else
            {
                throw new InvalidDataException("Unknown code format for '" + filename + "'");
            }
            return(DeserializeAssembly(Path.GetFileNameWithoutExtension(filename), instructions, bcv,
                                       strings, objectIndices));
        }
Beispiel #3
0
        public static GMFile /* errors: different return type? */ ReadFile(string baseDir, JsonData projFile)
        {
            var f = new GMFile();

            // OBJT: depends on SPRT, obj<->id map
            // ROOM: depends on OBJT, BGND
            // SCPT: depends on CODE

            if (projFile.Has("chunkorder") && projFile["chunkorder"].IsArray)
            {
                f.ChunkOrder = DeserializeArray(projFile["chunkorder"], jd => SectionHeadersExtensions.FromChunkName((string)jd));
            }
            else
            {
                Console.Error.WriteLine("Warning: Project file doesn't have a chunk order. You should export with a newer Altar.NET version.");
                f.ChunkOrder = new SectionHeaders[] {
                    SectionHeaders.General,
                    SectionHeaders.Options,
                    SectionHeaders.Language,
                    SectionHeaders.Extensions,
                    SectionHeaders.Sounds,
                    SectionHeaders.AudioGroup,
                    SectionHeaders.Sprites,
                    SectionHeaders.Backgrounds,
                    SectionHeaders.Paths,
                    SectionHeaders.Scripts,
                    SectionHeaders.Globals,
                    SectionHeaders.Shaders,
                    SectionHeaders.Fonts,
                    SectionHeaders.Timelines,
                    SectionHeaders.Objects,
                    SectionHeaders.Rooms,
                    SectionHeaders.DataFiles,
                    SectionHeaders.TexturePage,
                    SectionHeaders.Code,
                    SectionHeaders.Variables,
                    SectionHeaders.Functions,
                    SectionHeaders.Strings,
                    SectionHeaders.Textures,
                    SectionHeaders.Audio,
                    SectionHeaders.EmbedImage,
                };
            }

            if (projFile.Has("general"))
            {
                Console.WriteLine("Loading general...");
                try
                {
                    f.General = DeserializeGeneral(LoadJson(baseDir, (string)(projFile["general"])));
                    if (f.General.Version >= new Version(2, 0))
                    {
                        Console.Error.WriteLine("Warning: GM:S 2.0 support is incomplete!");
                    }
                }
                catch (Exception)
                {
                    Console.Error.WriteLine("Error loading general");
                    throw;
                }
            }
            if (projFile.Has("options"))
            {
                Console.WriteLine("Loading options...");
                try
                {
                    f.Options = DeserializeOptions(LoadJson(baseDir, (string)(projFile["options"])));
                }
                catch (Exception)
                {
                    Console.Error.WriteLine("Error loading options");
                    throw;
                }
            }
            if (projFile.Has("strings"))
            {
                Console.WriteLine("Loading strings...");
                try
                {
                    f.Strings = DeserializeArray(LoadJson(baseDir, (string)(projFile["strings"])), jd => (string)jd);
                }
                catch (Exception)
                {
                    Console.Error.WriteLine("Error loading strings");
                    throw;
                }
            }

            var variables = new ReferenceDef[0];
            var functions = new ReferenceDef[0];

            if (projFile.Has("variables"))
            {
                Console.WriteLine("Loading variables...");
                try
                {
                    var vardata = LoadJson(baseDir, (string)(projFile["variables"]));
                    variables = DeserializeArray(vardata.IsArray ? vardata : vardata["variables"], DeserializeReferenceDef);
                    if (vardata.Has("extra"))
                    {
                        f.VariableExtra = DeserializeArray(vardata["extra"], jd => (uint)jd);
                    }
                }
                catch (Exception)
                {
                    Console.Error.WriteLine("Error loading variables");
                    throw;
                }
            }
            if (projFile.Has("functions"))
            {
                Console.WriteLine("Loading functions...");
                try
                {
                    var funcdata = LoadJson(baseDir, (string)(projFile["functions"]));
                    functions = DeserializeArray(funcdata.IsArray ? funcdata : funcdata["functions"], DeserializeReferenceDef);
                    if (funcdata.Has("locals"))
                    {
                        f.FunctionLocals = DeserializeArray(funcdata["locals"], DeserializeFuncLocals);
                    }
                }
                catch (Exception)
                {
                    Console.Error.WriteLine("Error loading functions");
                    throw;
                }
            }
            f.RefData = new RefData {
                Variables = variables, Functions = functions
            };

            if (projFile.Has("textures"))
            {
                Console.WriteLine("Loading textures...");
                var textures = projFile["textures"].ToArray();
                var ts       = new TextureInfo[textures.Length];
                for (int i = 0; i < textures.Length; i++)
                {
                    try
                    {
                        var texinfo = new TextureInfo
                        {
                            PngData = File.ReadAllBytes(Path.Combine(baseDir, (string)(textures[i])))
                        };

                        var bp = new UniquePtr(texinfo.PngData);

                        unsafe
                        {
                            var png = (PngHeader *)bp.BPtr;

                            texinfo.Width  = Utils.SwapEnd32(png->IHDR.Width);
                            texinfo.Height = Utils.SwapEnd32(png->IHDR.Height);
                        }

                        ts[i] = texinfo;
                    }
                    catch (Exception)
                    {
                        Console.Error.WriteLine($"Error loading {textures[i]}");
                        throw;
                    }
                }
                f.Textures = ts;
            }
            if (projFile.Has("tpags"))
            {
                Console.Write("Loading texture pages... ");
                var cl = Console.CursorLeft;
                var ct = Console.CursorTop;

                var tpags = projFile["tpags"].ToArray();
                var tps   = new TexturePageInfo[tpags.Length];
                for (int i = 0; i < tpags.Length; i++)
                {
                    Console.SetCursorPosition(cl, ct);
                    Console.WriteLine(O_PAREN + (i + 1) + SLASH + tpags.Length + C_PAREN);
                    try
                    {
                        tps[i] = DeserializeTPag(LoadJson(baseDir, (string)(tpags[i])));
                    }
                    catch (Exception)
                    {
                        Console.Error.WriteLine($"Error loading {tpags[i]}");
                        throw;
                    }
                }
                f.TexturePages = tps;
            }
            if (projFile.Has("audio"))
            {
                Console.WriteLine("Loading audio...");
                var audio = projFile["audio"].ToArray();
                var ais   = new AudioInfo[audio.Length];
                for (int i = 0; i < audio.Length; i++)
                {
                    try
                    {
                        var audioinfo = new AudioInfo
                        {
                            Wave = File.ReadAllBytes(Path.Combine(baseDir, (string)(audio[i])))
                        };
                        ais[i] = audioinfo;
                    }
                    catch (Exception)
                    {
                        Console.Error.WriteLine($"Error loading {audio[i]}");
                        throw;
                    }
                }
                f.Audio = ais;
            }
            if (projFile.Has("sprites"))
            {
                Console.Write("Loading sprites... ");
                var cl = Console.CursorLeft;
                var ct = Console.CursorTop;

                var sprites = projFile["sprites"].ToArray();
                var ss      = new SpriteInfo[sprites.Length];
                for (int i = 0; i < sprites.Length; i++)
                {
                    Console.SetCursorPosition(cl, ct);
                    Console.WriteLine(O_PAREN + (i + 1) + SLASH + sprites.Length + C_PAREN);
                    try
                    {
                        ss[i]      = DeserializeSprite(LoadJson(baseDir, (string)(sprites[i])));
                        ss[i].Name = Path.GetFileNameWithoutExtension((string)(sprites[i]));
                    }
                    catch (Exception)
                    {
                        Console.Error.WriteLine($"Error loading {sprites[i]}");
                        throw;
                    }
                }
                f.Sprites = ss;
            }
            if (projFile.Has("objs"))
            {
                Console.Write("Loading objects... ");
                var cl = Console.CursorLeft;
                var ct = Console.CursorTop;

                var objs     = projFile["objs"].ToArray();
                var objNames = objs.Select(o => Path.GetFileNameWithoutExtension((string)o)).ToArray();
                var os       = new ObjectInfo[objs.Length];
                for (int i = 0; i < objs.Length; i++)
                {
                    Console.SetCursorPosition(cl, ct);
                    Console.WriteLine(O_PAREN + (i + 1) + SLASH + objs.Length + C_PAREN);
                    try
                    {
                        os[i] = DeserializeObj(
                            LoadJson(baseDir, (string)(objs[i])),
                            f.Sprites,
                            s => (uint)Array.IndexOf(objNames, s));
                        os[i].Name = objNames[i];
                    }
                    catch (Exception)
                    {
                        Console.Error.WriteLine($"Error loading {objs[i]}");
                        throw;
                    }
                }
                f.Objects = os;
            }
            if (projFile.Has("code"))
            {
                Console.WriteLine("Loading code...");
                var code = projFile["code"].ToArray();
                var cs   = new CodeInfo[code.Length];

                var strings = new StringsListBuilder();
                strings.AddStrings(f.Strings);
                IDictionary <string, uint> objectIndices = new Dictionary <string, uint>(f.Objects.Length);
                for (uint i = 0; i < f.Objects.Length; i++)
                {
                    objectIndices[f.Objects[i].Name] = i;
                }

                for (int i = 0; i < code.Length; i++)
                {
                    Console.WriteLine((string)(code[i]));
                    try
                    {
                        cs[i] = Assembler.DeserializeCodeFromFile(Path.Combine(baseDir, (string)(code[i])), f.General.BytecodeVersion,
                                                                  strings, objectIndices);
                        cs[i].Name          = Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension((string)(code[i])));
                        cs[i].ArgumentCount = 1;
                        if (f.FunctionLocals != null)
                        {
                            for (int j = 0; j < f.FunctionLocals.Length; j++)
                            {
                                int fastIndex = (j + i) % f.FunctionLocals.Length;
                                if (f.FunctionLocals[fastIndex].FunctionName == cs[i].Name)
                                {
                                    cs[i].ArgumentCount = f.FunctionLocals[fastIndex].LocalNames.Length;
                                    break;
                                }
                            }
                        }
                    }
                    catch (Exception)
                    {
                        Console.Error.WriteLine($"Error loading {code[i]}");
                        throw;
                    }
                }
                f.Code = cs;

                f.Strings = strings.GetStrings();
            }
            if (projFile.Has("sounds"))
            {
                Console.WriteLine("Loading sounds...");
                var sounds = projFile["sounds"].ToArray();
                var ss     = new SoundInfo[sounds.Length];
                for (int i = 0; i < sounds.Length; i++)
                {
                    try
                    {
                        ss[i]      = DeserializeSound(LoadJson(baseDir, (string)(sounds[i])));
                        ss[i].Name = Path.GetFileNameWithoutExtension((string)(sounds[i]));
                    }
                    catch (Exception)
                    {
                        Console.Error.WriteLine($"Error loading {sounds[i]}");
                        throw;
                    }
                }
                f.Sound = ss;
            }
            if (projFile.Has("bg"))
            {
                Console.WriteLine("Loading backgrounds...");
                var bg = projFile["bg"].ToArray();
                var bs = new BackgroundInfo[bg.Length];
                for (int i = 0; i < bg.Length; i++)
                {
                    try
                    {
                        bs[i]      = DeserializeBg(LoadJson(baseDir, (string)(bg[i])));
                        bs[i].Name = Path.GetFileNameWithoutExtension((string)(bg[i]));
                    }
                    catch (Exception)
                    {
                        Console.Error.WriteLine($"Error loading {bg[i]}");
                        throw;
                    }
                }
                f.Backgrounds = bs;
            }
            if (projFile.Has("paths"))
            {
                Console.WriteLine("Loading paths...");
                var paths = projFile["paths"].ToArray();
                var ps    = new PathInfo[paths.Length];
                for (int i = 0; i < paths.Length; i++)
                {
                    try
                    {
                        ps[i]      = DeserializePath(LoadJson(baseDir, (string)(paths[i])));
                        ps[i].Name = Path.GetFileNameWithoutExtension((string)(paths[i]));
                    }
                    catch (Exception)
                    {
                        Console.Error.WriteLine($"Error loading {paths[i]}");
                        throw;
                    }
                }
                f.Paths = ps;
            }
            if (projFile.Has("scripts"))
            {
                Console.WriteLine("Loading scripts...");
                var scripts = projFile["scripts"].ToArray();
                var ss      = new ScriptInfo[scripts.Length];
                for (int i = 0; i < scripts.Length; i++)
                {
                    try
                    {
                        ss[i]      = DeserializeScript(LoadJson(baseDir, (string)(scripts[i])), f.Code);
                        ss[i].Name = Path.GetFileNameWithoutExtension((string)(scripts[i]));
                    }
                    catch (Exception)
                    {
                        Console.Error.WriteLine($"Error loading {scripts[i]}");
                        throw;
                    }
                }
                f.Scripts = ss;
            }
            if (projFile.Has("fonts"))
            {
                Console.WriteLine("Loading fonts...");
                var fonts = projFile["fonts"].ToArray();
                var fs    = new FontInfo[fonts.Length];
                for (int i = 0; i < fonts.Length; i++)
                {
                    try
                    {
                        fs[i]          = DeserializeFont(LoadJson(baseDir, (string)(fonts[i])));
                        fs[i].CodeName = Path.GetFileNameWithoutExtension((string)(fonts[i]));
                    }
                    catch (Exception)
                    {
                        Console.Error.WriteLine($"Error loading {fonts[i]}");
                        throw;
                    }
                }
                f.Fonts = fs;
            }
            if (projFile.Has("rooms"))
            {
                Console.Write("Loading rooms... ");
                var cl = Console.CursorLeft;
                var ct = Console.CursorTop;

                var rooms = projFile["rooms"].ToArray();
                var rs    = new RoomInfo[rooms.Length];
                for (int i = 0; i < rooms.Length; i++)
                {
                    Console.SetCursorPosition(cl, ct);
                    Console.WriteLine(O_PAREN + (i + 1) + SLASH + rooms.Length + C_PAREN);
                    try
                    {
                        rs[i]      = DeserializeRoom(LoadJson(baseDir, (string)(rooms[i])), f.Backgrounds, f.Objects);
                        rs[i].Name = Path.GetFileNameWithoutExtension((string)(rooms[i]));
                    }
                    catch (Exception)
                    {
                        Console.Error.WriteLine($"Error loading {rooms[i]}");
                        throw;
                    }
                }
                f.Rooms = rs;
            }
            if (projFile.Has("audiogroups"))
            {
                Console.WriteLine("Loading audio groups...");
                try
                {
                    f.AudioGroups = DeserializeArray(LoadJson(baseDir, (string)(projFile["audiogroups"])), jd => (string)jd);
                }
                catch (Exception)
                {
                    Console.Error.WriteLine("Error loading audio groups");
                    throw;
                }
            }
            if (projFile.Has("shaders"))
            {
                Console.WriteLine("Loading shaders...");
                var shaders = projFile["shaders"].ToArray();
                var ss      = new ShaderInfo[shaders.Length];
                for (int i = 0; i < shaders.Length; i++)
                {
                    try
                    {
                        ss[i]      = DeserializeShader(LoadJson(baseDir, (string)(shaders[i])));
                        ss[i].Name = Path.GetFileNameWithoutExtension((string)(shaders[i]));
                    }
                    catch (Exception)
                    {
                        Console.Error.WriteLine($"Error loading {shaders[i]}");
                        throw;
                    }
                }
                f.Shaders = ss;
            }
            return(f);
        }
Beispiel #4
0
        private static CodeInfo DeserializeAssembly(string name, IEnumerable <Instruction> instructions, uint bcv,
                                                    StringsListBuilder strings, IDictionary <string, uint> objectIndices)
        {
            uint size   = 0;
            var  labels = new Dictionary <string, uint>();

            foreach (var inst in instructions)
            {
                if (inst is Label labelInst)
                {
                    if (labelInst.LabelValue is string label)
                    {
                        labels[label] = size * sizeof(int);
                    }
                }
                else
                {
                    size += InstSize(inst, bcv);
                }
            }

            IList <Tuple <ReferenceSignature, uint> > functionReferences = new List <Tuple <ReferenceSignature, uint> >();
            IList <Tuple <ReferenceSignature, uint> > variableReferences = new List <Tuple <ReferenceSignature, uint> >();

            var binaryInstructions = new List <AnyInstruction>();

            size = 0;
            foreach (var inst in instructions)
            {
                if (inst is Label)
                {
                    continue;
                }
                var op = new OpCodes {
                    VersionE = inst.OpCode.VersionE, VersionF = inst.OpCode.VersionF
                };
                var            type    = DisasmExt.Kind(op, bcv);
                AnyInstruction bininst = new AnyInstruction();
                switch (type)
                {
                case InstructionKind.Set:
                    var setinst = (Set)inst;
                    bininst.Set = new SetInstruction
                    {
                        DestVar  = new Reference(setinst.VariableType, 0),
                        Instance = GetInstanceType(setinst.InstanceType, setinst.InstanceName, objectIndices),
                        OpCode   = op,
                        Types    = new TypePair(setinst.Type1, setinst.Type2)
                    };
                    variableReferences.Add(new Tuple <ReferenceSignature, uint>(new ReferenceSignature
                    {
                        Name          = setinst.TargetVariable,
                        InstanceType  = setinst.InstanceType,
                        Instance      = setinst.InstanceType == InstanceType.Local ? name : null,
                        VariableType  = setinst.VariableType,
                        VariableIndex = setinst.VariableIndex
                    }, size));
                    break;

                case InstructionKind.Push:
                    var bp = new PushInstruction
                    {
                        OpCode = op,
                        Type   = ((Push)inst).Type
                    };
                    if (bp.Type == DataType.Variable)
                    {
                        var p = (PushVariable)inst;
                        bp.Value     = (short)GetInstanceType(p.InstanceType, p.InstanceName, objectIndices);
                        bp.ValueRest = new Reference(p.VariableType, 0).val;
                        variableReferences.Add(new Tuple <ReferenceSignature, uint>(new ReferenceSignature
                        {
                            Name          = p.VariableName,
                            InstanceType  = p.InstanceType,
                            Instance      = p.InstanceType == InstanceType.Local ? name : null,
                            VariableType  = p.VariableType,
                            VariableIndex = p.VariableIndex
                        }, size));
                    }
                    else
                    {
                        var p = (PushConst)inst;
                        switch (p.Type)
                        {
                        case DataType.Int16:
                            bp.Value = (short)(long)p.Value;
                            break;

                        case DataType.Boolean:
                            bp.ValueRest = (uint)(long)p.Value;
                            break;

                        case DataType.Double:
                        case DataType.Single:
                            bp.ValueRest = BitConverter.ToUInt64(BitConverter.GetBytes(Convert.ToDouble(p.Value)), 0);
                            break;

                        case DataType.Int32:
                        case DataType.Int64:
                            bp.ValueRest = BitConverter.ToUInt64(BitConverter.GetBytes(unchecked ((long)(p.Value))), 0);
                            break;

                        case DataType.String:
                            bp.ValueRest = strings.GetIndex((string)p.Value);
                            break;
                        }
                    }
                    bininst.Push = bp;
                    break;

                case InstructionKind.Call:
                    var callinst = (Call)inst;
                    bininst.Call = new CallInstruction
                    {
                        Arguments  = (ushort)callinst.Arguments,
                        Function   = new Reference(callinst.FunctionType, 0),
                        OpCode     = op,
                        ReturnType = callinst.ReturnType
                    };
                    functionReferences.Add(new Tuple <ReferenceSignature, uint>(new ReferenceSignature
                    {
                        Name          = callinst.FunctionName,
                        InstanceType  = InstanceType.StackTopOrGlobal,
                        VariableType  = callinst.FunctionType,
                        VariableIndex = -1
                    }, size));
                    break;

                case InstructionKind.Break:
                    var breakinst = (Break)inst;
                    bininst.Break = new BreakInstruction
                    {
                        OpCode = op,
                        Signal = (short)breakinst.Signal,
                        Type   = breakinst.Type
                    };
                    break;

                case InstructionKind.DoubleType:
                    var doubleinst = (DoubleType)inst;
                    bininst.DoubleType = new DoubleTypeInstruction
                    {
                        OpCode = op,
                        Types  = new TypePair(doubleinst.Type1, doubleinst.Type2)
                    };
                    if (inst is Compare cmpinst)
                    {
                        bininst.DoubleType.ComparisonType = cmpinst.ComparisonType;
                    }
                    break;

                case InstructionKind.SingleType:
                    var singleinst = (SingleType)inst;
                    bininst.SingleType = new SingleTypeInstruction
                    {
                        OpCode = op,
                        Type   = singleinst.Type
                    };
                    if (inst is Dup dupinst)
                    {
                        bininst.SingleType.DupExtra = dupinst.Extra;
                    }
                    break;

                case InstructionKind.Goto:
                    var  gotoinst  = (Branch)inst;
                    uint absTarget = 0;
                    if (gotoinst.Label is long)
                    {
                        absTarget = (uint)(long)(gotoinst.Label);
                    }
                    else if (gotoinst.Label is string)
                    {
                        absTarget = labels[(string)gotoinst.Label];
                    }
                    else if (gotoinst.Label == null)
                    {
                        bininst.Goto = new BranchInstruction
                        {
                            Offset = new Int24(0xF00000),
                            OpCode = op
                        };
                        break;
                    }
                    else
                    {
                        Console.Error.WriteLine($"Error in {name}: Can't use label {gotoinst.Label}");
                        break;
                    }
                    var  relTarget = (int)absTarget - (int)size;
                    uint offset    = unchecked ((uint)relTarget);
                    if (relTarget < 0)
                    {
                        offset &= 0xFFFFFF;
                        offset += 0x1000000;
                    }
                    offset      /= 4;
                    bininst.Goto = new BranchInstruction
                    {
                        Offset = new Int24(offset),
                        OpCode = op
                    };
                    break;

                default:
                    Console.Error.WriteLine($"Error in {name}: Unknown instruction type {type}!");
                    continue;
                }
                binaryInstructions.Add(bininst);
                unsafe
                {
                    size += DisasmExt.Size(&bininst, bcv) * 4;
                }
            }

            return(new CodeInfo
            {
                Size = (int)size,
                InstructionsCopy = binaryInstructions.ToArray(),
                functionReferences = functionReferences,
                variableReferences = variableReferences
            });
        }