Ejemplo n.º 1
0
        /// <summary>
        /// Global factory helper
        /// </summary>
        /// <param name="frame">Frame to read from</param>
        /// <param name="getter">Func factory to create Global given data type char</param>
        /// <returns>Constructed Global from getter</returns>
        /// <exception cref="ArgumentException">If frame aligned to a malformed Global record</exception>
        public static T Create <T>(
            MutagenFrame frame,
            Func <MutagenFrame, char, T> getter)
            where T : IMajorRecordCommon, IGlobalCommon
        {
            var initialPos = frame.Position;
            var majorMeta  = frame.GetMajorRecordFrame();

            if (majorMeta.Header.RecordType != GLOB)
            {
                throw new ArgumentException();
            }

            T g = getter(frame, GetGlobalChar(majorMeta));

            frame.Reader.Position = initialPos + frame.MetaData.Constants.MajorConstants.TypeAndLengthLength;

            // Read data
            var fltvLoc = UtilityTranslation.FindFirstSubrecord(majorMeta.Content, frame.MetaData.Constants, FLTV, navigateToContent: true);

            if (fltvLoc == null)
            {
                throw new ArgumentException($"Could not find FLTV.");
            }
            g.RawFloat = majorMeta.Content.Slice(fltvLoc.Value).GetFloat();

            // Skip to end
            frame.Reader.Position = initialPos + majorMeta.Header.TotalLength;
            return(g);
        }
Ejemplo n.º 2
0
        public void FixVMADFormIDs(
            MajorRecordFrame frame,
            long fileOffset,
            out int?vmadPos,
            out ushort objectFormat,
            out int processed)
        {
            vmadPos = UtilityTranslation.FindFirstSubrecord(frame.Content, Meta, RecordTypes.VMAD);
            if (vmadPos == null)
            {
                processed    = 0;
                objectFormat = 0;
                return;
            }
            var stream = new MutagenMemoryReadStream(frame.HeaderAndContentData, Bundle)
            {
                Position = vmadPos.Value + frame.HeaderLength
            };

            stream.Position += Meta.SubConstants.HeaderLength;
            // Skip version
            stream.Position += 2;
            objectFormat     = stream.ReadUInt16();
            var scriptCt = stream.ReadUInt16();

            for (int i = 0; i < scriptCt; i++)
            {
                FixVMADScriptIDs(stream, fileOffset, objectFormat);
            }
            processed = (int)(stream.Position - vmadPos.Value - frame.HeaderLength);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Iterates a MajorRecordFrame's subrecords and locates the first occurance of the desired type
        /// </summary>
        /// <param name="majorFrame">Frame to read from</param>
        /// <param name="type">Type to search for</param>
        /// <param name="offset">Offset within the Major Record's contents to start searching</param>
        /// <param name="pin">SubrecordPinFrame if found</param>
        /// <returns>True if matching subrecord is found</returns>
        public static bool TryLocateSubrecordPinFrame(this MajorRecordFrame majorFrame, RecordType type, int offset, out SubrecordPinFrame pin)
        {
            var find = UtilityTranslation.FindFirstSubrecord(majorFrame.Content.Slice(offset - majorFrame.HeaderLength), majorFrame.Meta, type, navigateToContent: false);

            if (find == null)
            {
                pin = default;
                return(false);
            }
            pin = new SubrecordPinFrame(majorFrame.Meta, majorFrame.Content.Slice(find.Value + offset - majorFrame.HeaderLength), find.Value + offset);
            return(true);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Iterates a MajorRecordFrame's subrecords and locates the first occurance of the desired type
        /// </summary>
        /// <param name="majorFrame">Frame to read from</param>
        /// <param name="type">Type to search for</param>
        /// <param name="frame">SubrecordFrame if found</param>
        /// <returns>True if matching subrecord is found</returns>
        public static bool TryLocateSubrecordFrame(this MajorRecordFrame majorFrame, RecordType type, out SubrecordFrame frame)
        {
            var find = UtilityTranslation.FindFirstSubrecord(majorFrame.Content, majorFrame.Meta, type, navigateToContent: false);

            if (find == null)
            {
                frame = default;
                return(false);
            }
            frame = new SubrecordFrame(majorFrame.Meta, majorFrame.Content.Slice(find.Value));
            return(true);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Iterates a MajorRecordFrame's subrecords and locates the first occurance of the desired type
        /// </summary>
        /// <param name="majorFrame">Frame to read from</param>
        /// <param name="type">Type to search for</param>
        /// <param name="header">SubrecordHeader if found</param>
        /// <param name="loc">Location of the subrecord, relative to the parent record's RecordType data</param>
        /// <returns>True if matching subrecord is found</returns>
        public static bool TryLocateSubrecord(this MajorRecordFrame majorFrame, RecordType type, int offset, out SubrecordHeader header, out int loc)
        {
            var find = UtilityTranslation.FindFirstSubrecord(majorFrame.Content.Slice(offset - majorFrame.HeaderLength), majorFrame.Meta, type, navigateToContent: false);

            if (find == null)
            {
                header = default;
                loc    = default;
                return(false);
            }
            header = new SubrecordHeader(majorFrame.Meta, majorFrame.Content.Slice(find.Value + offset - majorFrame.HeaderLength));
            loc    = find.Value + offset;
            return(true);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Retrieves the character representing a Global's data type from a MajorRecordFrame
        /// </summary>
        /// <param name="frame">Frame to retrieve from</param>
        /// <returns>Character representing data type</returns>
        /// <exception cref="ArgumentException">If FNAM not present or malformed</exception>
        public static char GetGlobalChar(MajorRecordFrame frame)
        {
            var subrecordSpan = frame.Content;
            var fnamLocation  = UtilityTranslation.FindFirstSubrecord(subrecordSpan, frame.Header.Meta, FNAM);

            if (fnamLocation == null)
            {
                throw new ArgumentException($"Could not find FNAM.");
            }
            var fnamMeta = frame.Header.Meta.SubrecordFrame(subrecordSpan.Slice(fnamLocation.Value));

            if (fnamMeta.Content.Length != 1)
            {
                throw new ArgumentException($"FNAM had non 1 length: {fnamMeta.Content.Length}");
            }
            return((char)fnamMeta.Content[0]);
        }
Ejemplo n.º 7
0
        private void ProcessRegions(
            MajorRecordFrame majorFrame,
            long fileOffset)
        {
            var rdat = UtilityTranslation.FindFirstSubrecord(majorFrame.Content, majorFrame.Meta, RecordTypes.RDAT, navigateToContent: false);

            if (rdat == null)
            {
                return;
            }

            // Order RDATs by index
            SortedList <uint, RangeInt64> rdats = new SortedList <uint, RangeInt64>();
            List <uint> raw = new List <uint>();

            while (rdat != null)
            {
                var rdatHeader = majorFrame.Meta.SubrecordFrame(majorFrame.Content.Slice(rdat.Value));
                var index      = BinaryPrimitives.ReadUInt32LittleEndian(rdatHeader.Content);
                var nextRdat   = UtilityTranslation.FindFirstSubrecord(
                    majorFrame.Content,
                    majorFrame.Meta,
                    RecordTypes.RDAT,
                    navigateToContent: false,
                    offset: rdat.Value + rdatHeader.TotalLength);
                rdats[index] =
                    new RangeInt64(
                        fileOffset + majorFrame.HeaderLength + rdat.Value,
                        nextRdat == null ? fileOffset + majorFrame.TotalLength - 1 : nextRdat.Value - 1 + fileOffset + majorFrame.HeaderLength);
                raw.Add(index);
                rdat = nextRdat;
            }
            if (raw.SequenceEqual(rdats.Keys))
            {
                return;
            }
            foreach (var item in rdats.Reverse())
            {
                this._Instructions.SetMove(
                    loc: fileOffset + majorFrame.TotalLength,
                    section: item.Value);
            }
        }
Ejemplo n.º 8
0
 public void FindFirstSubrecord_Duplicate()
 {
     Assert.Equal(FirstTypicalLocation, UtilityTranslation.FindFirstSubrecord(GetTypical(), GameConstants.Oblivion, FirstTypicalType));
 }
Ejemplo n.º 9
0
        public void FindFirstSubrecord_Empty()
        {
            var b = new byte[0];

            Assert.Null(UtilityTranslation.FindFirstSubrecord(b, GameConstants.Oblivion, SecondTypicalType));
        }
Ejemplo n.º 10
0
        private void ProcessPackages(
            MajorRecordFrame majorFrame,
            long fileOffset)
        {
            // Reorder Idle subrecords

            // Reorder data values
            var xnamPos = UtilityTranslation.FindFirstSubrecord(majorFrame.Content, majorFrame.Meta, RecordTypes.XNAM);

            if (xnamPos == null)
            {
                throw new ArgumentException();
            }

            if (!majorFrame.TryLocateSubrecordFrame(RecordTypes.PKCU, out var pkcuRec))
            {
                throw new ArgumentException();
            }
            var count = pkcuRec.Content.Int32();

            if (count == 0)
            {
                return;
            }

            var        anamPos = UtilityTranslation.FindFirstSubrecord(majorFrame.Content, majorFrame.Meta, RecordTypes.ANAM);
            RecordType pldt    = new RecordType("PLDT");
            RecordType ptda    = new RecordType("PTDA");
            RecordType pdto    = new RecordType("PDTO");
            RecordType tpic    = new RecordType("TPIC");
            RecordType unam    = new RecordType("UNAM");
            RecordType bnam    = new RecordType("BNAM");
            RecordType pnam    = new RecordType("PNAM");

            // Reorder data values to be in index ordering
            if (anamPos.HasValue && anamPos.Value < xnamPos.Value)
            {
                var startLoc   = anamPos.Value;
                var dataValues = new List <(sbyte Index, ReadOnlyMemorySlice <byte> Data)>();
                var curLoc     = startLoc;
                while (anamPos.HasValue && anamPos.Value < xnamPos.Value)
                {
                    var anamRecord = majorFrame.Meta.SubrecordFrame(majorFrame.Content.Slice(anamPos.Value));
                    var recs       = UtilityTranslation.FindNextSubrecords(
                        majorFrame.Content.Slice(anamPos.Value + anamRecord.TotalLength),
                        majorFrame.Meta,
                        out var _,
                        RecordTypes.ANAM,
                        RecordTypes.CNAM,
                        pldt,
                        ptda,
                        pdto,
                        tpic);
                    int finalLoc;
                    if (recs[0] == null)
                    {
                        finalLoc = recs.NotNull().Max();
                    }
                    else if (recs[0] == 0)
                    {
                        dataValues.Add(
                            (-1, majorFrame.Content.Slice(anamPos.Value, anamRecord.TotalLength)));
                        curLoc  = anamPos.Value + anamRecord.TotalLength;
                        anamPos = anamPos.Value + anamRecord.TotalLength;
                        continue;
                    }
                    else
                    {
                        finalLoc = recs
                                   .NotNull()
                                   .Where(i => i < recs[0] !.Value)
                                   .Max();
                    }
                    var finalRec  = majorFrame.Meta.Subrecord(majorFrame.Content.Slice(anamPos.Value + anamRecord.TotalLength + finalLoc));
                    var dataSlice = majorFrame.Content.Slice(anamPos.Value, anamRecord.TotalLength + finalLoc + finalRec.TotalLength);
                    if (BinaryStringUtility.ProcessWholeToZString(anamRecord.Content) == "Bool" &&
                        recs[1] != null)
                    {
                        // Ensure bool value is 1 or 0
                        var cnam = majorFrame.Meta.SubrecordFrame(majorFrame.Content.Slice(anamPos.Value + anamRecord.TotalLength + recs[1].Value));
                        if (cnam.Content.Length != 1)
                        {
                            throw new ArgumentException();
                        }
                        if (cnam.Content[0] > 1)
                        {
                            var bytes     = dataSlice.ToArray();
                            int boolIndex = anamRecord.TotalLength + recs[1].Value + cnam.HeaderLength;
                            bytes[boolIndex] = (byte)(bytes[boolIndex] > 0 ? 1 : 0);
                            dataSlice        = bytes;
                        }
                    }
                    dataValues.Add((-1, dataSlice));

                    curLoc  = anamPos.Value + anamRecord.TotalLength + finalLoc + finalRec.TotalLength;
                    anamPos = anamPos.Value + anamRecord.TotalLength + recs[0];
                }

                var unamLocs = UtilityTranslation.ParseRepeatingSubrecord(
                    majorFrame.Content.Slice(curLoc),
                    majorFrame.Meta,
                    unam,
                    out var _);
                if (unamLocs == null ||
                    unamLocs.Length != dataValues.Count ||
                    unamLocs.Length != count)
                {
                    throw new ArgumentException();
                }

                for (sbyte i = 0; i < unamLocs.Length; i++)
                {
                    var unamRec = majorFrame.Meta.SubrecordFrame(majorFrame.Content.Slice(curLoc + unamLocs[i]));
                    dataValues[i] = (
                        (sbyte)unamRec.Content[0],
                        dataValues[i].Data);
                }

                var subLoc = startLoc;
                foreach (var item in dataValues.OrderBy(i => i.Index))
                {
                    _Instructions.SetSubstitution(
                        fileOffset + majorFrame.HeaderLength + subLoc,
                        item.Data.ToArray());
                    subLoc += item.Data.Length;
                }
                foreach (var item in dataValues.OrderBy(i => i.Index))
                {
                    byte[] bytes = new byte[] { 0x55, 0x4E, 0x41, 0x4D, 0x01, 0x00, 0x00 };
                    bytes[6] = (byte)item.Index;
                    _Instructions.SetSubstitution(
                        fileOffset + majorFrame.HeaderLength + subLoc,
                        bytes.ToArray());
                    subLoc += bytes.Length;
                }
            }

            // Reorder inputs
            var unamPos = UtilityTranslation.FindFirstSubrecord(majorFrame.Content.Slice(xnamPos.Value), majorFrame.Meta, unam);

            if (!unamPos.HasValue)
            {
                return;
            }
            unamPos += xnamPos.Value;
            var writeLoc    = fileOffset + majorFrame.HeaderLength + unamPos.Value;
            var inputValues = new List <(sbyte Index, ReadOnlyMemorySlice <byte> Data)>();

            while (unamPos.HasValue)
            {
                var unamRecord = majorFrame.Meta.SubrecordFrame(majorFrame.Content.Slice(unamPos.Value));
                var recs       = UtilityTranslation.FindNextSubrecords(
                    majorFrame.Content.Slice(unamPos.Value + unamRecord.TotalLength),
                    majorFrame.Meta,
                    out var _,
                    unam,
                    bnam,
                    pnam);
                int finalLoc;
                if (recs[0] == null)
                {
                    finalLoc = recs.NotNull().Max();
                }
                else if (recs[0] == 0)
                {
                    inputValues.Add(
                        ((sbyte)unamRecord.Content[0], majorFrame.Content.Slice(unamPos.Value, unamRecord.TotalLength)));
                    unamPos = unamPos.Value + unamRecord.TotalLength;
                    continue;
                }
                else
                {
                    finalLoc = recs
                               .NotNull()
                               .Where(i => i < recs[0] !.Value)
                               .Max();
                }
                var finalRec = majorFrame.Meta.Subrecord(majorFrame.Content.Slice(unamPos.Value + unamRecord.TotalLength + finalLoc));
                inputValues.Add(
                    ((sbyte)unamRecord.Content[0], majorFrame.Content.Slice(unamPos.Value, unamRecord.TotalLength + finalLoc + finalRec.TotalLength)));

                unamPos = unamPos.Value + unamRecord.TotalLength + recs[0];
            }
            foreach (var item in inputValues.OrderBy(i => i.Index))
            {
                _Instructions.SetSubstitution(
                    writeLoc,
                    item.Data.ToArray());
                writeLoc += item.Data.Length;
            }
        }