Beispiel #1
0
        internal override void InternalWrite(BinaryWriter writer)
        {
            int posFileStart = (int)writer.BaseStream.Position;

            // seek past the header, type table and code labels
            writer.BaseStream.Seek(DATA_START + (_procedures.Length * BFCodeLabel.SIZE) + (_jumpLabels.Length * BFCodeLabel.SIZE), SeekOrigin.Current);

            // create code label type table entries
            int procsLength = _procedures.Length * BFCodeLabel.SIZE;
            int jumpsLength = _jumpLabels.Length * BFCodeLabel.SIZE;

            int opCodeDataStart = (int)(writer.BaseStream.Position - posFileStart);
            int numProcsSet = 0;
            int numJumpsSet = 0;
            for (int i = 0; i < _opcodes.Count; i++)
            {
                int procIdx = -1;

                // try to find a procedure with this index
                if (numProcsSet != _procedures.Length)
                {
                    procIdx = Array.FindIndex(_procedures, p => p.OpcodeIndex == i);
                    if (procIdx != -1)
                    {
                        _procedures[procIdx].Offset = (uint)(((writer.BaseStream.Position - posFileStart) - opCodeDataStart) / 4);
                        numProcsSet++;
                    }
                }

                // if we haven't found a procedure, try to find a jump label with this index
                if (procIdx == -1 && numJumpsSet != _jumpLabels.Length)
                {
                    int jumpIdx = Array.FindIndex(_jumpLabels, j => j.OpcodeIndex == i);
                    if (jumpIdx != -1)
                    {
                        _jumpLabels[jumpIdx].Offset = (uint)(((writer.BaseStream.Position - posFileStart) - opCodeDataStart) / 4);
                        numJumpsSet++;
                    }
                }
                
                // write the opcode data
                writer.Write((ushort)_opcodes[i].Instruction);

                if (_opcodes[i].Operand != null)
                {
                    switch (_opcodes[i].Operand.Type)
                    {
                        case BFOperandType.Immediate:
                            if (_opcodes[i].Instruction == BFInstruction.PushUInt32)
                            {
                                writer.Write((ushort)0);
                                writer.Write((uint)_opcodes[i].Operand.ImmediateValue);
                            }
                            else
                            {
                                writer.Write((ushort)_opcodes[i].Operand.ImmediateValue);
                            }
                            break;
                        case BFOperandType.FloatingPoint:
                            writer.Write((ushort)0);
                            writer.Write((float)_opcodes[i].Operand.FloatValue);
                            break;
                    }
                }
                else
                {
                    writer.Write((ushort)0);
                }
            }

            int opCodeDataEnd = (int)(writer.BaseStream.Position - posFileStart);

            // set type table entries
            TypeTableEntry[] typeTableEntries = new TypeTableEntry[TYPE_TABLE_COUNT];
            typeTableEntries[(int)TypeTableType.Procedures] = CreateTypeTableEntry(TypeTableType.Procedures, procsLength, DATA_START);
            typeTableEntries[(int)TypeTableType.JumpLabels] = CreateTypeTableEntry(TypeTableType.JumpLabels, jumpsLength, DATA_START + procsLength);
            typeTableEntries[(int)TypeTableType.Opcodes]    = CreateTypeTableEntry(TypeTableType.Opcodes, opCodeDataEnd - opCodeDataStart, opCodeDataStart);
            typeTableEntries[(int)TypeTableType.Messages]   = CreateTypeTableEntry(TypeTableType.Messages, 0, opCodeDataEnd);
            typeTableEntries[(int)TypeTableType.Strings]    = CreateTypeTableEntry(TypeTableType.Strings, 0xF0, opCodeDataEnd);

            if (_messageFile != null)
            {
                _messageFile.InternalWrite(writer);
                int messageDataEnd = (int)writer.BaseStream.Position - posFileStart;
                int messageDataSize = messageDataEnd - opCodeDataEnd;

                typeTableEntries[(int)TypeTableType.Strings].dataOffset += messageDataSize;
                typeTableEntries[(int)TypeTableType.Messages] = CreateTypeTableEntry(TypeTableType.Messages, messageDataSize, opCodeDataEnd);
            }

            // TODO: add code for the 'string' table here? haven't really seen it being used though.
            // fixed size zero bytes for the strings table when unused
            writer.Write(0, 0xF0);

            long posFileEnd = writer.BaseStream.Position;
            int length = (int)posFileEnd - posFileStart;

            writer.BaseStream.Seek(posFileStart, SeekOrigin.Begin);

            // write standard header
            writer.Write(TYPE);
            writer.Write((short)0); // userID
            writer.Write(length);
            writer.WriteCString(TAG, 4);
            writer.Write(0); // unused

            // write bf header
            writer.Write(typeTableEntries.Length);
            writer.Write(0); // some unknown value here, not sure what its for
            writer.AlignPosition(16);

            // write type table entries
            foreach (TypeTableEntry entry in typeTableEntries)
            {
                entry.InternalWrite(writer);
            }

            // lastly, write the code labels
            foreach (BFCodeLabel label in _procedures)
            {
                label.InternalWrite(writer);
            }

            foreach (BFCodeLabel label in _jumpLabels)
            {
                label.InternalWrite(writer);
            }
        }
Beispiel #2
0
        private void InternalRead(BinaryReader reader)
        {
            long posFileStart = reader.GetPosition();
            short flag = reader.ReadInt16();
            short userID = reader.ReadInt16();
            int length = reader.ReadInt32();
            string tag = reader.ReadCString(4);
            int unused = reader.ReadInt32();

            if (tag != TAG)
            {
                throw new InvalidDataException("Identifier mismatch.");
            }

            int numTypeTableEntries = reader.ReadInt32();
            int numUnknown = reader.ReadInt32();

            reader.AlignPosition(16);

            TypeTableEntry[] typeTable = new TypeTableEntry[numTypeTableEntries];
            for (int i = 0; i < numTypeTableEntries; i++)
            {
                typeTable[i] = new TypeTableEntry(reader);
            }

            System.Diagnostics.Debug.Assert(typeTable[(int)TypeTableType.Strings].elementCount == 0xF0);

            for (int i = 0; i < numTypeTableEntries; i++)
            {
                reader.Seek(posFileStart + typeTable[i].dataOffset, SeekOrigin.Begin);

                switch ((TypeTableType)typeTable[i].type)
                {
                    case TypeTableType.Procedures:
                        ReadCodeLabels(reader, ref _procedures, typeTable[i].elementCount, out _requireSortProcedures);
                        break;
                    case TypeTableType.JumpLabels:
                        ReadCodeLabels(reader, ref _jumpLabels, typeTable[i].elementCount, out _requireSortJumps);
                        break;
                    case TypeTableType.Opcodes:
                        {
                            bool hasExtendedOpcodes;
                            _opcodes = BFDisassembler.ParseCodeblock(reader.ReadUInt32Array(typeTable[i].elementCount), out hasExtendedOpcodes);

                            if (hasExtendedOpcodes) // only fix up the opcode indices if they have to be
                                FixupOpcodeIndices(); // this function is kinda 2*O(n^2)
                        }
                        break;
                    case TypeTableType.Messages:
                        if (typeTable[i].elementCount > 0)
                            _messageFile = new BMDFile(StreamHelper.ReadStream(reader, typeTable[i].elementCount), false);
                        break;
                    case TypeTableType.Strings:
                        // TODO: Implement this
                        break;
                }
            }
        }
Beispiel #3
0
        private static TypeTableEntry CreateTypeTableEntry(TypeTableType entryType, int entriesTotalSize, int dataOffset = 0)
        {
            int elementLength = 0;
            switch (entryType)
            {
                case TypeTableType.Procedures:
                case TypeTableType.JumpLabels:
                    elementLength = 32;
                    break;
                case TypeTableType.Opcodes:
                    elementLength = 4;
                    break;
                case TypeTableType.Messages:
                case TypeTableType.Strings:
                    elementLength = 1;
                    break;
            }

            TypeTableEntry entry = new TypeTableEntry()
            {
                type = (int)entryType,
                dataOffset = dataOffset,
                elementCount = entriesTotalSize / elementLength,
                elementLength = elementLength,
            };

            return entry;
        }