Exemple #1
0
        private void TestBBEmpty(float[] data, int period, float sigmaWidth)
        {
            BBData res = _testObj.Calculate(data, period, sigmaWidth);

            res.SMA.ShouldBeEmpty();
            res.BBL.ShouldBeEmpty();
            res.BBH.ShouldBeEmpty();
        }
Exemple #2
0
        private void TestBB(float[] data, BBData expected, int period, float sigmaWidth)
        {
            BBData res = _testObj.Calculate(data, period, sigmaWidth);

            res.SMA.ShouldBe(expected.SMA, 0.0001f);
            res.BBL.ShouldBe(expected.BBL, 0.0001f);
            res.BBH.ShouldBe(expected.BBH, 0.0001f);
        }
Exemple #3
0
        public override void Calculate(StockPricesData data)
        {
            BBData res = (new BB()).Calculate(data.C, _statParams.Get(StatBBParams.Period).As <int>(), _statParams.Get(StatBBParams.SigmaWidth).As <float>());

            _data[StatBBData.BBH] = res.BBH;
            _data[StatBBData.SMA] = res.SMA;
            _data[StatBBData.BBL] = res.BBL;
        }
Exemple #4
0
 private static void WriteCodeInfo(BBData data, CodeInfo ci, StringsChunkBuilder strings, uint bytecodeVersion)
 {
     data.Buffer.Write(strings.GetOffset(ci.Name)); // Name
     data.Buffer.Write(ci.Size);                    // Length
     if (bytecodeVersion > 0xE)
     {
         data.Buffer.Write(ci.ArgumentCount); // ArgumentCount
         data.Buffer.Write(0);                // BytecodeOffset
         data.Buffer.Write(0);                // pad
     }
     else
     {
         WriteCodeBlock(data, ci.InstructionsCopy, bytecodeVersion);
     }
 }
Exemple #5
0
 public static void WriteCodeBlock(BBData data, AnyInstruction[] instructions, uint bytecodeVersion)
 {
     foreach (var inst in instructions)
     {
         var ins_     = inst;
         var instdata = new BinBuffer();
         instdata.Write(inst);
         uint size;
         unsafe
         {
             size = DisasmExt.Size(&ins_, bytecodeVersion) * 4;
         }
         data.Buffer.Write(instdata, 0, (int)size, 0);
     }
 }
Exemple #6
0
        public static void ResolveReferenceOffsets(BBData data,
                                                   IList <Tuple <ReferenceSignature, uint> > references, StringsChunkBuilder strings, bool extended,
                                                   out IList <ReferenceDef> startOffsetsAndCounts)
        {
            startOffsetsAndCounts = new List <ReferenceDef>();
            int localCount    = 0;
            int nonLocalCount = 0;

            for (int i = 0; i < references.Count; i++)
            {
                Tuple <ReferenceSignature, uint> last = references[i];
                uint diff;
                uint existing;
                uint count     = 0;
                var  targetRef = references[i].Item1;
                var  start     = references[i].Item2;
                if (targetRef.InstanceType >= InstanceType.StackTopOrGlobal && extended && targetRef.VariableIndex != -1)
                {
                    for (InstanceType possibleInstanceType = InstanceType.Self; possibleInstanceType >= InstanceType.Local; possibleInstanceType--)
                    {
                        for (int j = i + 1; j < references.Count; j++)
                        {
                            if (references[j].Item1.Name == targetRef.Name &&
                                references[j].Item1.InstanceType == possibleInstanceType)
                            {
                                targetRef.InstanceType = references[j].Item1.InstanceType;
                                targetRef.Instance     = references[j].Item1.Instance;
                                break;
                            }
                        }
                        if (targetRef.InstanceType < InstanceType.StackTopOrGlobal)
                        {
                            break;
                        }
                    }
                    if (targetRef.InstanceType >= InstanceType.StackTopOrGlobal)
                    {
                        targetRef.InstanceType = InstanceType.Self; // ??
                    }
                }
                if (targetRef.InstanceType == InstanceType.Local && targetRef.Name == "arguments")
                {
                    //localCount = 0;
                }
                if (start != 0xFFFFFFFF)
                {
                    count = 1;
                    for (int j = i + 1; j < references.Count;)
                    {
                        if (references[j].Item1.Name == targetRef.Name &&
                            (!extended ||
                             (targetRef.VariableIndex != -1) ||
                             (references[j].Item1.InstanceType >= InstanceType.StackTopOrGlobal) ||
                             (references[j].Item1.InstanceType == targetRef.InstanceType &&
                              //references[j].Item1.VariableType == targetRef.VariableType &&
                              (references[j].Item1.InstanceType != InstanceType.Local ||
                               references[j].Item1.Instance == targetRef.Instance))) &&
                            ((targetRef.VariableIndex == -1) ||
                             (targetRef.VariableIndex == references[j].Item1.VariableIndex)))
                        {
                            diff = (references[j].Item2 - last.Item2) & 0xFFFFFF;
                            data.Buffer.Position = (int)last.Item2 + 4;
                            existing             = data.Buffer.ReadUInt32();
                            data.Buffer.Write(diff | existing);
                            last = references[j];
                            references.RemoveAt(j);
                            count++;
                        }
                        else
                        {
                            j++;
                        }
                    }
                    diff = strings.GetIndex(last.Item1.Name);
                    data.Buffer.Position = (int)last.Item2 + 4;
                    existing             = data.Buffer.ReadUInt32();
                    data.Buffer.Write(diff | existing);
                }
                var def = new ReferenceDef
                {
                    FirstOffset  = start,
                    HasExtra     = extended,
                    InstanceType = targetRef.InstanceType,
                    Name         = targetRef.Name,
                    Occurrences  = count,
                    unknown2     = targetRef.InstanceType == InstanceType.Local ?
                                   localCount : targetRef.VariableType == VariableType.StackTop ?
                                   nonLocalCount : -6,
                    VariableType = targetRef.VariableType
                };
                if (targetRef.VariableIndex == -1)
                {
                    startOffsetsAndCounts.Add(def);
                }
                else
                {
                    while (startOffsetsAndCounts.Count <= targetRef.VariableIndex)
                    {
                        startOffsetsAndCounts.Add(new ReferenceDef());
                    }
                    startOffsetsAndCounts[targetRef.VariableIndex] = def;
                }
                if (targetRef.InstanceType == InstanceType.Local)
                {
                    localCount++;
                }
                else if (targetRef.VariableType == VariableType.StackTop)
                {
                    nonLocalCount++;
                }
            }
        }
Exemple #7
0
        public static int[] WriteCodes(BBData data, GMFile f, StringsChunkBuilder strings)
        {
            int bytecodeSize = 0;

            foreach (var ci in f.Code)
            {
                bytecodeSize += ci.Size;
            }

            Console.WriteLine($"Assembling...");

            BBData[] datas = new BBData[f.Code.Length];
            for (int i = 0; i < f.Code.Length; i++)
            {
                BBData codedata = new BBData(new BinBuffer(), new int[0]);
                WriteCodeInfo(codedata, f.Code[i], strings, f.General.BytecodeVersion);
                datas[i] = codedata;
            }

            data.Buffer.Write(datas.Length);

            var allOffs = data.OffsetOffsets.ToList();

            var offAcc = data.Buffer.Position + datas.Length * sizeof(int); // after all offsets

            if (f.General.BytecodeVersion > 0xE)
            {
                offAcc += bytecodeSize;
            }
            int[] offsets             = new int[datas.Length];
            var   stringOffsetOffsets = new int[f.Code.Length];

            for (int i = 0; i < datas.Length; i++)
            {
                allOffs.Add(data.Buffer.Position);
                data.Buffer.Write(offAcc);
                offsets[i] = offAcc;

                stringOffsetOffsets[i] = offAcc + 8;

                offAcc += datas[i].Buffer.Size;
            }

            Console.WriteLine($"Linking...");

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

            variableReferences.Add(new Tuple <ReferenceSignature, uint>(new ReferenceSignature
            {
                Name          = "prototype",
                InstanceType  = InstanceType.Self,
                VariableType  = VariableType.Normal,
                VariableIndex = 0
            }, 0xFFFFFFFF));
            variableReferences.Add(new Tuple <ReferenceSignature, uint>(new ReferenceSignature
            {
                Name          = "@@array@@",
                InstanceType  = InstanceType.Self,
                VariableType  = VariableType.Normal,
                VariableIndex = 1
            }, 0xFFFFFFFF));

            int[] bytecodeOffsets = null;
            if (f.General.BytecodeVersion > 0xE)
            {
                // In >=F bytecodes, the code comes before the info data, which
                // is why this method can't just be a call to WriteList.
                bytecodeOffsets = new int[f.Code.Length];
                for (int i = 0; i < f.Code.Length; i++)
                {
                    bytecodeOffsets[i] = data.Buffer.Position - 12;
                    AddReferencesOffset(functionReferences, f.Code[i].functionReferences, data.Buffer.Position);
                    if (f.Code[i].variableReferences.Count == 0 || f.Code[i].variableReferences[0].Item1.Name != "arguments")
                    {
                        variableReferences.Add(new Tuple <ReferenceSignature, uint>(new ReferenceSignature
                        {
                            Name          = "arguments",
                            InstanceType  = InstanceType.Local,
                            Instance      = f.Code[i].Name,
                            VariableType  = VariableType.Normal,
                            VariableIndex = -1
                        }, 0xFFFFFFFF));
                    }
                    AddReferencesOffset(variableReferences, f.Code[i].variableReferences, data.Buffer.Position);
                    WriteCodeBlock(data, f.Code[i].InstructionsCopy, f.General.BytecodeVersion);
                }
            }

            for (int i = 0; i < datas.Length; i++)
            {
                if (f.General.BytecodeVersion > 0xE)
                {
                    datas[i].Buffer.Position = (int)Marshal.OffsetOf(typeof(CodeEntryF), "BytecodeOffset");
                    datas[i].Buffer.Write(bytecodeOffsets[i] - data.Buffer.Position);
                }
                else
                {
                    AddReferencesOffset(functionReferences, f.Code[i].functionReferences, data.Buffer.Position);
                    if (f.Code[i].variableReferences.Count == 0 || f.Code[i].variableReferences[0].Item1.Name != "arguments")
                    {
                        variableReferences.Add(new Tuple <ReferenceSignature, uint>(new ReferenceSignature
                        {
                            Name          = "arguments",
                            InstanceType  = InstanceType.Local,
                            Instance      = f.Code[i].Name,
                            VariableType  = VariableType.Normal,
                            VariableIndex = -1
                        }, 0xFFFFFFFF));
                    }
                    AddReferencesOffset(variableReferences, f.Code[i].variableReferences, data.Buffer.Position);
                }
                SectionWriter.Write(data.Buffer, datas[i]);
                allOffs.AddRange(datas[i].OffsetOffsets); // updated by Write
            }

            IList <ReferenceDef> functionStartOffsetsAndCounts;

            ResolveReferenceOffsets(data, functionReferences, strings, false, out functionStartOffsetsAndCounts);

            IList <ReferenceDef> variableStartOffsetsAndCounts;

            ResolveReferenceOffsets(data, variableReferences, strings, true, out variableStartOffsetsAndCounts);

            if (f.RefData.Variables == null || f.RefData.Variables.Length == 0)
            {
                Console.Error.WriteLine("Warning: Variable definitions not pre-loaded. Linking may be inaccurate or lose information.");
            }
            else
            {
                // I tried my best at guessing what these should be, but it wasn't enough.
                // I suspect it may have to do with variable type, since getting
                // one wrong resulted in "tried to index something that isn't an
                // array" (or something to that effect).
                for (int i = 0; i < variableStartOffsetsAndCounts.Count; i++)
                {
                    var v = variableStartOffsetsAndCounts[i];
                    if (i < f.RefData.Variables.Length &&
                        v.Name == f.RefData.Variables[i].Name) // &&
                                                               //(v.InstanceType == f.RefData.Variables[i].InstanceType || v.InstanceType >= InstanceType.StackTopOrGlobal))
                    {
                        v.unknown2     = f.RefData.Variables[i].unknown2;
                        v.InstanceType = f.RefData.Variables[i].InstanceType;
                        variableStartOffsetsAndCounts[i] = v;
                    }
                }
            }

            f.RefData = new RefData
            {
                Functions = functionStartOffsetsAndCounts.ToArray(),
                Variables = variableStartOffsetsAndCounts.ToArray()
            };

            data.OffsetOffsets = allOffs.ToArray();

            return(stringOffsetOffsets);
        }
Exemple #8
0
        public static byte[] WriteFile(string baseDir, JsonData projFile, GMFile f)
        {
            Console.WriteLine($"Preparing strings...");
            var stringsChunkBuilder = new StringsChunkBuilder();

            stringsChunkBuilder.AddStrings(f.Strings);

            var texpChunk = new BBData(new BinBuffer(), new int[0]);

            Console.WriteLine($"Preparing textures...");
            int[] texPagOffsets = SectionWriter.WriteTexturePages(texpChunk, f.TexturePages);

            var codeChunk = new BBData(new BinBuffer(), new int[0]);

            Console.WriteLine($"Preparing code...");
            var codeChunkStringOffsetOffsets = Assembler.WriteCodes(codeChunk, f, stringsChunkBuilder);

            var    offsets = new int[0];
            BBData writer  = new BBData(new BinBuffer(), offsets);

            writer.Buffer.Write(SectionHeaders.Form);
            writer.Buffer.Write(0);

            var stringOffsetOffsets = new List <int>();
            int stringsDataPosition = 0;
            var texpOffsetOffsets   = new List <int>();
            int texpChunkPosition   = 0;
            var codeOffsetOffsets   = new List <int>();
            int codeChunkPosition   = 0;

            foreach (SectionHeaders chunkId in f.ChunkOrder)
            {
                Console.WriteLine($"Writing {chunkId}...");
                BBData chunk = new BBData(new BinBuffer(), new int[0]);
                int[]  chunkStringOffsetOffsets = null;
                int[]  chunkTexpOffsetOffsets   = null;
                int[]  chunkCodeOffsetOffsets   = null;
                switch (chunkId)
                {
                case SectionHeaders.General:
                    chunkStringOffsetOffsets = SectionWriter.WriteGeneral(chunk, f.General, f.Rooms, stringsChunkBuilder);
                    break;

                case SectionHeaders.Options:
                    chunkStringOffsetOffsets = SectionWriter.WriteOptions(chunk, f.Options, stringsChunkBuilder);
                    break;

                case SectionHeaders.Sounds:
                    chunkStringOffsetOffsets = SectionWriter.WriteSounds(chunk, f.Sound, stringsChunkBuilder, f.AudioGroups);
                    break;

                case SectionHeaders.AudioGroup:
                    chunkStringOffsetOffsets = SectionWriter.WriteAudioGroups(chunk, f.AudioGroups, stringsChunkBuilder);
                    break;

                case SectionHeaders.Sprites:
                    SectionWriter.WriteSprites(chunk, f.Sprites, stringsChunkBuilder, texPagOffsets,
                                               out chunkStringOffsetOffsets, out chunkTexpOffsetOffsets);
                    break;

                case SectionHeaders.Backgrounds:
                    SectionWriter.WriteBackgrounds(chunk, f.Backgrounds, stringsChunkBuilder, texPagOffsets,
                                                   out chunkStringOffsetOffsets, out chunkTexpOffsetOffsets);
                    break;

                case SectionHeaders.Paths:
                    chunkStringOffsetOffsets = SectionWriter.WritePaths(chunk, f.Paths, stringsChunkBuilder);
                    break;

                case SectionHeaders.Scripts:
                    chunkStringOffsetOffsets = SectionWriter.WriteScripts(chunk, f.Scripts, stringsChunkBuilder);
                    break;

                case SectionHeaders.Fonts:
                    SectionWriter.WriteFonts(chunk, f.Fonts, stringsChunkBuilder, texPagOffsets,
                                             out chunkStringOffsetOffsets, out chunkTexpOffsetOffsets);
                    break;

                case SectionHeaders.Objects:
                    chunkStringOffsetOffsets = SectionWriter.WriteObjects(chunk, f.Objects, stringsChunkBuilder);
                    break;

                case SectionHeaders.Rooms:
                    chunkStringOffsetOffsets = SectionWriter.WriteRooms(chunk, f.Rooms, stringsChunkBuilder);
                    break;

                case SectionHeaders.TexturePage:
                    chunk             = texpChunk;
                    texpChunkPosition = writer.Buffer.Position + 8;
                    break;

                case SectionHeaders.Code:
                    chunk = codeChunk;
                    chunkStringOffsetOffsets = codeChunkStringOffsetOffsets;
                    codeChunkPosition        = writer.Buffer.Position + 8;
                    break;

                case SectionHeaders.Variables:
                    if (f.VariableExtra != null)
                    {
                        foreach (var e in f.VariableExtra)
                        {
                            chunk.Buffer.Write(e);
                        }
                    }
                    SectionWriter.WriteRefDefs(chunk, f.RefData.Variables, stringsChunkBuilder, f.General.IsOldBCVersion, false,
                                               out chunkStringOffsetOffsets, out chunkCodeOffsetOffsets);
                    break;

                case SectionHeaders.Functions:
                    SectionWriter.WriteRefDefs(chunk, f.RefData.Functions, stringsChunkBuilder, f.General.IsOldBCVersion, true,
                                               out chunkStringOffsetOffsets, out chunkCodeOffsetOffsets);
                    chunkStringOffsetOffsets = chunkStringOffsetOffsets.Concat(SectionWriter.WriteFunctionLocals(chunk, f.FunctionLocals, stringsChunkBuilder)).ToArray();
                    break;

                case SectionHeaders.Strings:
                    var stringOffsets = stringsChunkBuilder.WriteStringsChunk(chunk);
                    stringsDataPosition = writer.Buffer.Position + stringOffsets[0] + 12;
                    // for Textures chunk up next
                    SectionWriter.Pad(chunk, 0x80, writer.Buffer.Position + 8);
                    break;

                case SectionHeaders.Textures:
                    SectionWriter.WriteTextures(chunk, f.Textures);
                    break;

                case SectionHeaders.Audio:
                    SectionWriter.WriteAudio(chunk, f.Audio, writer.Buffer.Position);
                    break;

                case SectionHeaders.Shaders:
                    chunkStringOffsetOffsets = SectionWriter.WriteShaders(chunk, f.Shaders, stringsChunkBuilder);
                    break;

                default:
                    var chunkName = chunkId.ToChunkName();
                    Console.Error.WriteLine($"Note: Don't know how to handle {chunkName}");
                    string chunkFile = null;
                    if (projFile.Has("chunks") && projFile["chunks"].IsArray)
                    {
                        foreach (JsonData jd in projFile["chunks"])
                        {
                            if (jd.IsString)
                            {
                                if (Path.GetFileNameWithoutExtension((string)jd) == chunkName)
                                {
                                    chunkFile = (string)jd;
                                    break;
                                }
                            }
                        }
                    }
                    BinBuffer chunkData;
                    if (chunkFile == null)
                    {
                        Console.Error.WriteLine($"Note: Chunk {chunkName} was not dumped, assuming it's empty");
                        chunkData = new BinBuffer();
                    }
                    else
                    {
                        Console.Error.WriteLine($"Note: Loading {chunkName} from dump");
                        try
                        {
                            chunkData = new BinBuffer(File.ReadAllBytes(Path.Combine(baseDir, chunkFile)));
                        }
                        catch (Exception e)
                        {
                            Console.Error.WriteLine($"Error loading {chunkName}, using empty");
                            Console.Error.WriteLine(e);
                            chunkData = new BinBuffer();
                        }
                    }
                    chunk = new BBData(chunkData, new int[0]);
                    break;
                }
                if (chunkStringOffsetOffsets != null)
                {
                    foreach (var offset in chunkStringOffsetOffsets)
                    {
                        stringOffsetOffsets.Add(offset + writer.Buffer.Position);
                    }
                }
                chunkStringOffsetOffsets = null;
                if (chunkTexpOffsetOffsets != null)
                {
                    foreach (var offset in chunkTexpOffsetOffsets)
                    {
                        texpOffsetOffsets.Add(offset + writer.Buffer.Position);
                    }
                }
                chunkTexpOffsetOffsets = null;
                if (chunkCodeOffsetOffsets != null)
                {
                    foreach (var offset in chunkCodeOffsetOffsets)
                    {
                        codeOffsetOffsets.Add(offset + writer.Buffer.Position);
                    }
                }
                chunkCodeOffsetOffsets = null;
                SectionWriter.WriteChunk(writer, chunkId, chunk);
            }

            writer.Buffer.Position = 4;
            writer.Buffer.Write(writer.Buffer.Size - 8);
            writer.Buffer.Position = writer.Buffer.Size;

            foreach (var stringOffset in stringOffsetOffsets)
            {
                writer.Buffer.Position = stringOffset;
                var o = writer.Buffer.ReadInt32();
                //bb.Position -= sizeof(int);
                writer.Buffer.Write(o + stringsDataPosition);
            }

            foreach (var texpOffset in texpOffsetOffsets)
            {
                writer.Buffer.Position = texpOffset;
                var o = writer.Buffer.ReadInt32();
                //bb.Position -= sizeof(int);
                writer.Buffer.Write(o + texpChunkPosition);
            }

            foreach (var codeOffset in codeOffsetOffsets)
            {
                writer.Buffer.Position = codeOffset;
                var o = writer.Buffer.ReadInt32();
                //bb.Position -= sizeof(int);
                writer.Buffer.Write(o + codeChunkPosition);
            }

            writer.Buffer.Position = 0;
            return(writer.Buffer.ReadBytes(writer.Buffer.Size));
        }