Exemple #1
0
 public unsafe string UnsafeAlloc()
 {
     var span = data.AsSpan();
     Span<char> chars = stackalloc char[span.Length];
     BinaryStringUtility.ToZStringBuffer(span, chars);
     return chars.ToString();
 }
Exemple #2
0
            public static void CustomStringImports(MutagenFrame frame, IConditionData item)
            {
                if (!frame.Reader.TryGetSubrecordFrame(out var subMeta))
                {
                    return;
                }
                if (!(item is IFunctionConditionData funcData))
                {
                    return;
                }
                switch (subMeta.RecordType.TypeInt)
                {
                case 0x31534943:     // CIS1
                    funcData.ParameterOneString = BinaryStringUtility.ProcessWholeToZString(subMeta.Content);
                    break;

                case 0x32534943:     // CIS2
                    funcData.ParameterTwoString = BinaryStringUtility.ProcessWholeToZString(subMeta.Content);
                    break;

                default:
                    return;
                }
                frame.Position += subMeta.TotalLength;
            }
Exemple #3
0
            public static partial void FillBinaryEffectInitialCustom(MutagenFrame frame, IEffect item)
            {
                var subMeta = frame.ReadSubrecord();

                if (subMeta.ContentLength != Plugins.Internals.Constants.HeaderLength)
                {
                    throw new ArgumentException($"Magic effect name must be length 4.  Was: {subMeta.ContentLength}");
                }
                var magicEffName = frame.ReadMemory(4);

                if (!frame.Reader.TryGetSubrecord(RecordTypes.EFIT, out var efitMeta))
                {
                    throw new ArgumentException("Expected EFIT header.");
                }
                if (efitMeta.ContentLength < Plugins.Internals.Constants.HeaderLength)
                {
                    throw new ArgumentException($"Magic effect ref length was less than 4.  Was: {efitMeta.ContentLength}");
                }
                var magicEffName2 = frame.GetMemory(amount: Plugins.Internals.Constants.HeaderLength, offset: efitMeta.HeaderLength);

                if (!magicEffName.Span.SequenceEqual(magicEffName2.Span))
                {
                    throw new ArgumentException($"Magic effect names did not match. {BinaryStringUtility.ToZString(magicEffName)} != {BinaryStringUtility.ToZString(magicEffName2)}");
                }
            }
        /// <inheritdoc />
        public bool TryLookup(uint key, [MaybeNullWhen(false)] out string str)
        {
            if (!_locations.TryGetValue(key, out var loc))
            {
                str = default;
                return(false);
            }

            switch (_type)
            {
            case StringsFileFormat.Normal:
                str = BinaryStringUtility.ParseUnknownLengthString(this._stringData.Slice(loc));
                break;

            case StringsFileFormat.LengthPrepended:
                try
                {
                    str = BinaryStringUtility.ParsePrependedString(this._stringData.Slice(loc), 4);
                }
                catch (ArgumentOutOfRangeException)
                {
                    throw new ArgumentOutOfRangeException("Strings file malformed.");
                }
                break;

            default:
                throw new NotImplementedException();
            }
            return(true);
        }
Exemple #5
0
            public static partial ParseResult FillBinaryEffectInitialCustom(MutagenFrame frame, IEffect item, PreviousParse lastParsed)
            {
                var subMeta = frame.ReadSubrecord();

                if (subMeta.ContentLength != Mutagen.Bethesda.Plugins.Internals.Constants.HeaderLength)
                {
                    throw new ArgumentException($"Magic effect name must be length 4.  Was: {subMeta.ContentLength}");
                }
                var magicEffName = frame.ReadMemory(4);

                if (!frame.Reader.TryGetSubrecord(RecordTypes.EFIT, out var efitMeta))
                {
                    throw new ArgumentException("Expected EFIT header.");
                }
                if (efitMeta.ContentLength < Mutagen.Bethesda.Plugins.Internals.Constants.HeaderLength)
                {
                    throw new ArgumentException($"Magic effect ref length was less than 4.  Was: {efitMeta.ContentLength}");
                }
                var magicEffName2 = frame.GetMemory(amount: Mutagen.Bethesda.Plugins.Internals.Constants.HeaderLength, offset: efitMeta.HeaderLength);

                if (!magicEffName.Span.SequenceEqual(magicEffName2.Span))
                {
                    throw new ArgumentException($"Magic effect names did not match. {BinaryStringUtility.ToZString(magicEffName, frame.MetaData.Encodings.NonTranslated)} != {BinaryStringUtility.ToZString(magicEffName2, frame.MetaData.Encodings.NonTranslated)}");
                }

                return(lastParsed.ParsedIndex);
            }
Exemple #6
0
 public string ArrayAllocation()
 {
     var span = data.AsSpan();
     char[] chars = new char[span.Length];
     BinaryStringUtility.ToZStringBuffer(span, chars);
     var charSpan = chars.AsSpan();
     return charSpan.ToString();
 }
Exemple #7
0
 public string ArrayRenting()
 {
     var span = data.AsSpan();
     var chars = ArrayPool<char>.Shared.Rent(span.Length);
     BinaryStringUtility.ToZStringBuffer(span, chars);
     var ret = new string(chars, 0, span.Length);
     ArrayPool<char>.Shared.Return(chars);
     return ret;
 }
Exemple #8
0
 string?GetIconCustom()
 {
     if (_IconLocation.HasValue)
     {
         return(BinaryStringUtility.ProcessWholeToZString(HeaderTranslation.ExtractSubrecordMemory(_data, _IconLocation.Value, _package.MetaData.Constants)));
     }
     if (_SecondaryIconLocation.HasValue)
     {
         return(BinaryStringUtility.ProcessWholeToZString(HeaderTranslation.ExtractSubrecordMemory(_data, _SecondaryIconLocation.Value, _package.MetaData.Constants)));
     }
     return(default);
Exemple #9
0
            public static void FillCloudTexture(IMutagenReadStream stream, RecordType nextRecordType, string?[] textures)
            {
                int layer = nextRecordType.TypeInt - TextureIntBase;

                if (layer > 29 || layer < 0)
                {
                    throw new ArgumentException();
                }
                var subRec = stream.ReadSubrecordFrame();

                textures[layer] = BinaryStringUtility.ProcessWholeToZString(subRec.Content, stream.MetaData.Encodings.NonTranslated);
            }
Exemple #10
0
        public void GetMemorySlice()
        {
            var archive = Archive.CreateReader(GameRelease.SkyrimSE, TestBsa);

            archive.TryGetFolder("derp\\some_FoldeR", out var folder)
            .Should().BeTrue();
            if (folder == null)
            {
                throw new NullReferenceException();
            }
            var file = folder.Files.First();

            BinaryStringUtility.ProcessWholeToZString(file.GetMemorySlice())
            .Should().Be("Found me");
        }
Exemple #11
0
 public static partial void FillBinaryBipedObjectNamesCustom(MutagenFrame frame, IRaceInternal item)
 {
     for (int i = 0; i < NumBipedObjectNames; i++)
     {
         if (!frame.Reader.TryReadSubrecordFrame(RecordTypes.NAME, out var subHeader))
         {
             break;
         }
         BipedObject type = (BipedObject)i;
         var         val  = BinaryStringUtility.ProcessWholeToZString(subHeader.Content, frame.MetaData.Encodings.NonTranslated);
         if (!string.IsNullOrEmpty(val))
         {
             item.BipedObjectNames[type] = val;
         }
     }
 }
Exemple #12
0
        public void AsStream()
        {
            var archive = Archive.CreateReader(GameRelease.SkyrimSE, TestBsa);

            archive.TryGetFolder("derp\\some_FoldeR", out var folder)
            .Should().BeTrue();
            if (folder == null)
            {
                throw new NullReferenceException();
            }
            var file   = folder.Files.First();
            var stream = file.AsStream();

            byte[] b = new byte[stream.Length];
            stream.Remaining().Should().Be(8);
            stream.Read(b);
            stream.Remaining().Should().Be(0);
            BinaryStringUtility.ProcessWholeToZString(b)
            .Should().Be("Found me");
        }
Exemple #13
0
        private string Get(int loc)
        {
            switch (_type)
            {
            case StringsFileFormat.Normal:
                return(BinaryStringUtility.ParseUnknownLengthString(this._stringData.Slice(loc)));

            case StringsFileFormat.LengthPrepended:
                try
                {
                    return(BinaryStringUtility.ParsePrependedString(this._stringData.Slice(loc), 4));
                }
                catch (ArgumentOutOfRangeException)
                {
                    throw new ArgumentOutOfRangeException("Strings file malformed.");
                }

            default:
                throw new NotImplementedException();
            }
        }
        /// <summary>
        /// Takes a span aligned to a major record, and attempts to locate the game setting type.
        /// Will throw if the span is misaligned or doesn't start at a valid major record header.
        /// </summary>
        /// <param name="span">Data beginning at the start of a major record</param>
        /// <param name="meta">Game meta information to use in parsing</param>
        /// <returns>A response of the GameSettingType if found, or a reason if not.</returns>
        public static GetResponse <GameSettingType> GetGameSettingType(ReadOnlyMemorySlice <byte> span, GameConstants meta)
        {
            var majorMeta = meta.MajorRecordFrame(span);
            var edidLoc   = UtilityTranslation.FindFirstSubrecord(majorMeta.Content, meta, Constants.EditorID);

            if (edidLoc == null)
            {
                return(GetResponse <GameSettingType> .Fail($"EDID was not located"));
            }
            var edidMeta = meta.SubrecordFrame(majorMeta.Content.Slice(edidLoc.Value));
            var edid     = BinaryStringUtility.ProcessWholeToZString(edidMeta.Content);

            if (edid.Length == 0)
            {
                return(GetResponse <GameSettingType> .Fail("No EDID parsed."));
            }
            if (!TryGetGameSettingType(edid[0], out var settingType))
            {
                return(GetResponse <GameSettingType> .Fail($"Unknown game setting type: {edid[0]}"));
            }
            return(GetResponse <GameSettingType> .Succeed(settingType));
        }
 public string ReadMemory()
 {
     return(BinaryStringUtility.ToZString(stream.GetMemory(data.Length)));
 }
 public string ReadSpan()
 {
     return(BinaryStringUtility.ToZString(stream.GetSpan(data.Length)));
 }
Exemple #17
0
 /// <summary>
 /// Interprets a subrecord's content as a string.
 /// </summary>
 /// <param name="frame">Frame to read from</param>
 /// <returns>Subrecord's content as a string, null trimmed if applicable</returns>
 public static string AsString(this SubrecordFrame frame)
 {
     return(BinaryStringUtility.ProcessWholeToZString(frame.Content));
 }
Exemple #18
0
    private void ProcessRegions(
        IMutagenReadStream stream,
        MajorRecordFrame majorFrame,
        long fileOffset)
    {
        if (!majorFrame.TryLocateSubrecordFrame(RecordTypes.RDAT, out var rdatFrame, out var rdatIndex))
        {
            return;
        }
        int amount = 0;
        SortedList <uint, RangeInt64> rdats = new SortedList <uint, RangeInt64>();
        bool foundNext = true;

        while (foundNext)
        {
            foundNext = majorFrame.TryLocateSubrecordFrame(RecordTypes.RDAT, offset: rdatIndex + rdatFrame.TotalLength, out var nextRdatFrame, out var nextRdatIndex);
            var index = rdatFrame.Content.UInt32();
            rdats[index] =
                new RangeInt64(
                    rdatIndex + fileOffset,
                    foundNext ? nextRdatIndex - 1 + fileOffset : fileOffset + majorFrame.TotalLength - 1);
            rdatFrame = nextRdatFrame;
            rdatIndex = nextRdatIndex;
        }

        foreach (var item in rdats.Reverse())
        {
            if (item.Key == (int)RegionData.RegionDataType.Icon)
            {
                continue;
            }
            this._instructions.SetMove(
                loc: fileOffset + majorFrame.TotalLength,
                section: item.Value);
        }

        if (rdats.ContainsKey((int)RegionData.RegionDataType.Icon))
        { // Need to create icon record
            if (!majorFrame.TryLocateSubrecordFrame("EDID", out var edidFrame, out var edidLoc))
            {
                throw new ArgumentException();
            }
            var locToPlace = fileOffset + edidLoc + edidFrame.TotalLength;

            // Get icon string
            var iconLoc = rdats[(int)RegionData.RegionDataType.Icon];
            stream.Position = iconLoc.Min + 20;
            var iconStr = BinaryStringUtility.ToZString(stream.ReadMemory((int)(iconLoc.Max - stream.Position)), MutagenEncodingProvider._1252);

            // Get icon bytes
            MemoryStream memStream = new MemoryStream();
            using (var writer = new MutagenWriter(memStream, this.GameRelease))
            {
                using (HeaderExport.Header(
                           writer,
                           new RecordType("ICON"),
                           ObjectType.Subrecord))
                {
                    StringBinaryTranslation.Instance.Write(writer, iconStr, StringBinaryType.NullTerminate);
                }
            }

            var arr = memStream.ToArray();
            this._instructions.SetAddition(
                loc: locToPlace,
                addition: arr);
            this._instructions.SetRemove(
                section: iconLoc);
            amount += arr.Length;
            amount -= (int)iconLoc.Width;
        }

        ProcessLengths(
            majorFrame,
            amount,
            fileOffset);
    }
Exemple #19
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;
            }
        }
Exemple #20
0
            public static IEnumerable <APerkEffect> ParseEffects(IMutagenReadStream stream)
            {
                while (stream.TryReadSubrecordFrame(RecordTypes.PRKE, out var prkeFrame))
                {
                    var         type     = (Perk.EffectType)prkeFrame.Content[0];
                    var         rank     = prkeFrame.Content[1];
                    var         priority = prkeFrame.Content[2];
                    APerkEffect effect;
                    if (stream.TryReadSubrecordFrame(RecordTypes.DATA, out var dataFrame))
                    {
                        switch (type)
                        {
                        case Perk.EffectType.Quest:
                            effect = new PerkQuestEffect()
                            {
                                Quest   = new FormLink <IQuestGetter>(FormKeyBinaryTranslation.Instance.Parse(dataFrame.Content, stream.MetaData.MasterReferences !)),
                                Stage   = dataFrame.Content[4],
                                Unknown = dataFrame.Content.Slice(5, 3).ToArray(),
                            };
                            effect.Conditions.SetTo(
                                ListBinaryTranslation <PerkCondition> .Instance.Parse(
                                    reader: new MutagenFrame(stream),
                                    transl: (MutagenFrame r, out PerkCondition listSubItem) =>
                            {
                                return(LoquiBinaryTranslation <PerkCondition> .Instance.Parse(
                                           frame: r,
                                           item: out listSubItem !));
                            }));
                            break;

                        case Perk.EffectType.Ability:
                            effect = new PerkAbilityEffect()
                            {
                                Ability = new FormLink <ISpellGetter>(FormKeyBinaryTranslation.Instance.Parse(dataFrame.Content, stream.MetaData.MasterReferences !)),
                            };
                            effect.Conditions.SetTo(
                                ListBinaryTranslation <PerkCondition> .Instance.Parse(
                                    reader: new MutagenFrame(stream),
                                    transl: (MutagenFrame r, out PerkCondition listSubItem) =>
                            {
                                return(LoquiBinaryTranslation <PerkCondition> .Instance.Parse(
                                           frame: r,
                                           item: out listSubItem !));
                            }));
                            break;

                        case Perk.EffectType.EntryPoint:
                            var entryPt    = (APerkEntryPointEffect.EntryType)dataFrame.Content[0];
                            var func       = (APerkEntryPointEffect.FunctionType)dataFrame.Content[1];
                            var tabCount   = dataFrame.Content[2];
                            var conditions = ListBinaryTranslation <PerkCondition> .Instance.Parse(
                                reader : new MutagenFrame(stream),
                                transl : (MutagenFrame r, out PerkCondition listSubItem) =>
                            {
                                return(LoquiBinaryTranslation <PerkCondition> .Instance.Parse(
                                           frame: r,
                                           item: out listSubItem !));
                            })
                                             .ToList();

                            ReadOnlyMemorySlice <byte>?epf2 = null;
                            ReadOnlyMemorySlice <byte>?epf3 = null;
                            ReadOnlyMemorySlice <byte>?epfd = null;
                            ReadOnlyMemorySlice <byte>?epft = null;
                            while (stream.TryReadSubrecordFrame(out var subFrame))
                            {
                                switch (subFrame.RecordTypeInt)
                                {
                                case RecordTypeInts.EPF2:
                                    epf2 = subFrame.Content;
                                    break;

                                case RecordTypeInts.EPF3:
                                    epf3 = subFrame.Content;
                                    break;

                                case RecordTypeInts.EPFD:
                                    epfd = subFrame.Content;
                                    break;

                                case RecordTypeInts.EPFT:
                                    epft = subFrame.Content;
                                    break;

                                default:
                                    stream.Position -= subFrame.Content.Length;
                                    goto searchDone;
                                }
                            }
searchDone:
                            APerkEntryPointEffect entryPointEffect;
                            switch (func)
                            {
                            case APerkEntryPointEffect.FunctionType.SetValue:
                            case APerkEntryPointEffect.FunctionType.AddValue:
                            case APerkEntryPointEffect.FunctionType.MultiplyValue:
                                if (epf2.HasValue)
                                {
                                    stream.MetaData.ReportIssue(RecordTypes.EPF2, $"{nameof(PerkEntryPointModifyValue)} had EPF2 unexpectedly");
                                }
                                if (epf3.HasValue)
                                {
                                    stream.MetaData.ReportIssue(RecordTypes.EPF3, $"{nameof(PerkEntryPointModifyValue)} had EPF3 unexpectedly");
                                }
                                float?f;
                                if (epft == null && epfd == null)
                                {
                                    f = null;
                                }
                                else
                                {
                                    if (!epft.HasValue)
                                    {
                                        throw new ArgumentException($"{nameof(PerkEntryPointModifyValue)} did not have expected EPFT record");
                                    }
                                    if (!epfd.HasValue)
                                    {
                                        throw new ArgumentException($"{nameof(PerkEntryPointModifyValue)} did not have expected EPFD record");
                                    }
                                    if (epft.Value[0] != (byte)APerkEntryPointEffect.ParameterType.Float)
                                    {
                                        throw new ArgumentException($"{nameof(PerkEntryPointModifyValue)} did not have expected parameter type flag: {epft.Value[0]}");
                                    }

                                    f = epfd.Value.Float();
                                }
                                entryPointEffect = new PerkEntryPointModifyValue()
                                {
                                    Value        = f,
                                    Modification = func switch
                                    {
                                        APerkEntryPointEffect.FunctionType.SetValue => PerkEntryPointModifyValue.ModificationType.Set,
                                        APerkEntryPointEffect.FunctionType.MultiplyValue => PerkEntryPointModifyValue.ModificationType.Multiply,
                                        APerkEntryPointEffect.FunctionType.AddValue => PerkEntryPointModifyValue.ModificationType.Add,
                                        _ => throw new ArgumentException(),
                                    }
                                };
                                break;

                            case APerkEntryPointEffect.FunctionType.AddRangeToValue:
                                if (epf2.HasValue)
                                {
                                    stream.MetaData.ReportIssue(RecordTypes.EPF2, $"{nameof(PerkEntryPointModifyValue)} had EPF2 unexpectedly");
                                }
                                if (epf3.HasValue)
                                {
                                    stream.MetaData.ReportIssue(RecordTypes.EPF3, $"{nameof(PerkEntryPointModifyValue)} had EPF3 unexpectedly");
                                }
                                if (!epft.HasValue)
                                {
                                    throw new ArgumentException($"{nameof(PerkEntryPointAddRangeToValue)} did not have expected EPFT record");
                                }
                                if (!epfd.HasValue)
                                {
                                    throw new ArgumentException($"{nameof(PerkEntryPointAddRangeToValue)} did not have expected EPFD record");
                                }
                                if (epft.Value[0] != (byte)APerkEntryPointEffect.ParameterType.FloatFloat)
                                {
                                    throw new ArgumentException($"{nameof(PerkEntryPointAddRangeToValue)} did not have expected parameter type flag: {epft.Value[0]}");
                                }
                                entryPointEffect = new PerkEntryPointAddRangeToValue()
                                {
                                    From = epfd.Value.Float(),
                                    To   = epfd.Value.Slice(4).Float(),
                                };
                                break;

                            case APerkEntryPointEffect.FunctionType.SetToActorValueMult:
                            case APerkEntryPointEffect.FunctionType.MultiplyActorValueMult:
                            case APerkEntryPointEffect.FunctionType.MultiplyOnePlusActorValueMult:
                            case APerkEntryPointEffect.FunctionType.AddActorValueMult:
                                if (epf2.HasValue)
                                {
                                    stream.MetaData.ReportIssue(RecordTypes.EPF2, $"{nameof(PerkEntryPointModifyValue)} had EPF2 unexpectedly");
                                }
                                if (epf3.HasValue)
                                {
                                    stream.MetaData.ReportIssue(RecordTypes.EPF3, $"{nameof(PerkEntryPointModifyValue)} had EPF3 unexpectedly");
                                }
                                if (!epft.HasValue)
                                {
                                    throw new ArgumentException($"{nameof(PerkEntryPointModifyActorValue)} did not have expected EPFT record");
                                }
                                if (!epfd.HasValue)
                                {
                                    throw new ArgumentException($"{nameof(PerkEntryPointModifyActorValue)} did not have expected EPFD record");
                                }
                                if (epft.Value[0] != (byte)APerkEntryPointEffect.ParameterType.FloatFloat)
                                {
                                    throw new ArgumentException($"{nameof(PerkEntryPointModifyActorValue)} did not have expected parameter type flag: {epft.Value[0]}");
                                }
                                entryPointEffect = new PerkEntryPointModifyActorValue()
                                {
                                    ActorValue   = (ActorValue)BinaryPrimitives.ReadInt32LittleEndian(epfd.Value),
                                    Value        = epfd.Value.Slice(4).Float(),
                                    Modification = func switch
                                    {
                                        APerkEntryPointEffect.FunctionType.SetToActorValueMult => PerkEntryPointModifyActorValue.ModificationType.SetToAVMult,
                                        APerkEntryPointEffect.FunctionType.AddActorValueMult => PerkEntryPointModifyActorValue.ModificationType.AddAVMult,
                                        APerkEntryPointEffect.FunctionType.MultiplyActorValueMult => PerkEntryPointModifyActorValue.ModificationType.MultiplyAVMult,
                                        APerkEntryPointEffect.FunctionType.MultiplyOnePlusActorValueMult => PerkEntryPointModifyActorValue.ModificationType.MultiplyOnePlusAVMult,
                                        _ => throw new ArgumentException(),
                                    }
                                };
                                break;

                            case APerkEntryPointEffect.FunctionType.AbsoluteValue:
                            case APerkEntryPointEffect.FunctionType.NegativeAbsoluteValue:
                                if (epf2.HasValue)
                                {
                                    stream.MetaData.ReportIssue(RecordTypes.EPF2, $"{nameof(PerkEntryPointModifyValue)} had EPF2 unexpectedly");
                                }
                                if (epf3.HasValue)
                                {
                                    stream.MetaData.ReportIssue(RecordTypes.EPF3, $"{nameof(PerkEntryPointModifyValue)} had EPF3 unexpectedly");
                                }
                                if (epft.HasValue && epft.Value[0] != (byte)APerkEntryPointEffect.ParameterType.None)
                                {
                                    throw new ArgumentException($"{nameof(PerkEntryPointAbsoluteValue)} did not have expected parameter type flag: {epft.Value[0]}");
                                }
                                entryPointEffect = new PerkEntryPointAbsoluteValue()
                                {
                                    Negative = func == APerkEntryPointEffect.FunctionType.NegativeAbsoluteValue
                                };
                                break;

                            case APerkEntryPointEffect.FunctionType.AddLeveledList:
                                if (epf2.HasValue)
                                {
                                    stream.MetaData.ReportIssue(RecordTypes.EPF2, $"{nameof(PerkEntryPointModifyValue)} had EPF2 unexpectedly");
                                }
                                if (epf3.HasValue)
                                {
                                    stream.MetaData.ReportIssue(RecordTypes.EPF3, $"{nameof(PerkEntryPointModifyValue)} had EPF3 unexpectedly");
                                }
                                if (!epft.HasValue)
                                {
                                    throw new ArgumentException($"{nameof(PerkEntryPointAddLeveledItem)} did not have expected EPFT record");
                                }
                                if (epft.Value[0] != (byte)APerkEntryPointEffect.ParameterType.LeveledItem)
                                {
                                    throw new ArgumentException($"{nameof(PerkEntryPointAddLeveledItem)} did not have expected parameter type flag: {epft.Value[0]}");
                                }
                                entryPointEffect = new PerkEntryPointAddLeveledItem()
                                {
                                    Item = new FormLink <ILeveledItemGetter>(epfd.HasValue ? FormKeyBinaryTranslation.Instance.Parse(epfd.Value, stream.MetaData.MasterReferences !) : FormKey.Null)
                                };
                                break;

                            case APerkEntryPointEffect.FunctionType.AddActivateChoice:
                                if (!epft.HasValue)
                                {
                                    throw new ArgumentException($"{nameof(PerkEntryPointAddActivateChoice)} did not have expected EPFT record");
                                }
                                if (!epf3.HasValue)
                                {
                                    throw new ArgumentException($"{nameof(PerkEntryPointAddActivateChoice)} did not have expected EPF3 record");
                                }
                                if (epft.Value[0] != (byte)APerkEntryPointEffect.ParameterType.SpellWithStrings)
                                {
                                    throw new ArgumentException($"{nameof(PerkEntryPointAddActivateChoice)} did not have expected parameter type flag: {epft.Value[0]}");
                                }
                                entryPointEffect = new PerkEntryPointAddActivateChoice()
                                {
                                    Spell       = new FormLinkNullable <ISpellGetter>(epfd.HasValue ? FormKeyBinaryTranslation.Instance.Parse(epfd.Value, stream.MetaData.MasterReferences !) : default(FormKey?)),
                                    ButtonLabel = epf2.HasValue ? StringBinaryTranslation.Instance.Parse(epf2.Value, StringsSource.Normal, stream.MetaData) : null,
                                    Flags       = new PerkScriptFlag()
                                    {
                                        Flags         = (PerkScriptFlag.Flag)BinaryPrimitives.ReadInt16LittleEndian(epf3.Value),
                                        FragmentIndex = BinaryPrimitives.ReadUInt16LittleEndian(epf3.Value.Slice(2))
                                    },
                                };
                                break;

                            case APerkEntryPointEffect.FunctionType.SelectSpell:
                                if (epf2.HasValue)
                                {
                                    stream.MetaData.ReportIssue(RecordTypes.EPF2, $"{nameof(PerkEntryPointModifyValue)} had EPF2 unexpectedly");
                                }
                                if (epf3.HasValue)
                                {
                                    stream.MetaData.ReportIssue(RecordTypes.EPF3, $"{nameof(PerkEntryPointModifyValue)} had EPF3 unexpectedly");
                                }
                                if (!epft.HasValue)
                                {
                                    throw new ArgumentException($"{nameof(PerkEntryPointSelectSpell)} did not have expected EPFT record");
                                }
                                if (epft.Value[0] != (byte)APerkEntryPointEffect.ParameterType.Spell)
                                {
                                    throw new ArgumentException($"{nameof(PerkEntryPointSelectSpell)} did not have expected parameter type flag: {epft.Value[0]}");
                                }
                                entryPointEffect = new PerkEntryPointSelectSpell()
                                {
                                    Spell = new FormLink <ISpellGetter>(epfd.HasValue ? FormKeyBinaryTranslation.Instance.Parse(epfd.Value, stream.MetaData.MasterReferences !) : FormKey.Null),
                                };
                                break;

                            case APerkEntryPointEffect.FunctionType.SelectText:
                                if (epf2.HasValue)
                                {
                                    stream.MetaData.ReportIssue(RecordTypes.EPF2, $"{nameof(PerkEntryPointModifyValue)} had EPF2 unexpectedly");
                                }
                                if (epf3.HasValue)
                                {
                                    stream.MetaData.ReportIssue(RecordTypes.EPF3, $"{nameof(PerkEntryPointModifyValue)} had EPF3 unexpectedly");
                                }
                                if (!epft.HasValue)
                                {
                                    throw new ArgumentException($"{nameof(PerkEntryPointSelectText)} did not have expected EPFT record");
                                }
                                if (epft.Value[0] != (byte)APerkEntryPointEffect.ParameterType.String)
                                {
                                    throw new ArgumentException($"{nameof(PerkEntryPointSelectText)} did not have expected parameter type flag: {epft.Value[0]}");
                                }
                                entryPointEffect = new PerkEntryPointSelectText()
                                {
                                    Text = epfd.HasValue ? BinaryStringUtility.ProcessWholeToZString(epfd.Value, stream.MetaData.Encodings.NonTranslated) : string.Empty
                                };
                                break;

                            case APerkEntryPointEffect.FunctionType.SetText:
                                if (epf2.HasValue)
                                {
                                    stream.MetaData.ReportIssue(RecordTypes.EPF2, $"{nameof(PerkEntryPointModifyValue)} had EPF2 unexpectedly");
                                }
                                if (epf3.HasValue)
                                {
                                    stream.MetaData.ReportIssue(RecordTypes.EPF3, $"{nameof(PerkEntryPointModifyValue)} had EPF3 unexpectedly");
                                }
                                if (!epft.HasValue)
                                {
                                    throw new ArgumentException($"{nameof(PerkEntryPointSetText)} did not have expected EPFT record");
                                }
                                if (epft.Value[0] != (byte)APerkEntryPointEffect.ParameterType.LString)
                                {
                                    throw new ArgumentException($"{nameof(PerkEntryPointSetText)} did not have expected parameter type flag: {epft.Value[0]}");
                                }
                                entryPointEffect = new PerkEntryPointSetText()
                                {
                                    Text = epfd.HasValue ? StringBinaryTranslation.Instance.Parse(epfd.Value, StringsSource.Normal, stream.MetaData) : (TranslatedString)string.Empty,
                                };
                                break;

                            default:
                                throw new NotImplementedException();
                            }
                            entryPointEffect.EntryPoint            = entryPt;
                            entryPointEffect.PerkConditionTabCount = tabCount;
                            entryPointEffect.Conditions.SetTo(conditions);
                            effect = entryPointEffect;
                            break;

                        default:
                            throw new NotImplementedException();
                        }
                    }
                    else
                    {
                        effect = type switch
                        {
                            Perk.EffectType.Quest => new PerkQuestEffect(),
                            Perk.EffectType.Ability => new PerkAbilityEffect(),
                            _ => throw new ArgumentException($"Expected DATA subrecord that did not exist."),
                        };
                    }
                    effect.Rank     = rank;
                    effect.Priority = priority;
                    if (stream.TryReadSubrecordFrame(RecordTypes.EPFT, out var epftFrame) &&
                        epftFrame.ContentLength != 1 &&
                        epftFrame.Content[0] != (byte)APerkEntryPointEffect.ParameterType.None)
                    {
                        throw new ArgumentException($"Encountered an unexpected epft frame.");
                    }
                    stream.TryReadSubrecordFrame(RecordTypes.PRKF, out var _);
                    yield return(effect);
                }
            }
Exemple #21
0
            public static void FillPackageData(IMutagenReadStream stream, int expectedCount, IDictionary <sbyte, APackageData> data)
            {
                // Retrieve the expected types, then skip rest of data
                var valuesPosition = stream.Position;
                var types          = new List <string>(expectedCount);

                while (stream.TryReadSubrecordFrame(out var subRecord))
                {
                    switch (subRecord.RecordTypeInt)
                    {
                    case 0x4D414E41:     // ANAM
                        types.Add(BinaryStringUtility.ProcessWholeToZString(subRecord.Content));
                        break;

                    case 0x4D414E43:     // CNAM
                    case 0x4D414E42:     // BNAM
                    case 0x43495054:     // TPIC
                    case 0x41445450:     // PTDA
                    case 0x4F544450:     // PDTO
                    case 0x54444C50:     // PLDT
                        // Skip
                        break;

                    default:
                        stream.Position -= subRecord.TotalLength;
                        goto done_types;
                    }
                }
done_types:

                // Parse package data
                APackageData? lastPackage = null;
                int itemIndex = 0;
                var packages  = new List <APackageData>(expectedCount);

                while (stream.TryGetSubrecordFrame(out var subRecord))
                {
                    switch (subRecord.RecordTypeInt)
                    {
                    case 0x4D414E55:     // UNAM
                        var index = (sbyte)subRecord.Content[0];
                        lastPackage = data.GetOrAdd <sbyte, APackageData>(
                            index,
                            () =>
                        {
                            return((types[itemIndex++]) switch
                            {
                                IntKey => new PackageDataInt(),
                                FloatKey => new PackageDataFloat(),
                                BoolKey => new PackageDataBool(),
                                LocationKey => new PackageDataLocation(),
                                SingleRefKey => new
                                PackageDataTarget()
                                {
                                    Type = PackageDataTarget.Types.SingleRef
                                },
                                TargetSelectorKey => new PackageDataTarget()
                                {
                                    Type = PackageDataTarget.Types.Target
                                },
                                TopicKey => new PackageDataTopic(),
                                ObjectListKey => new PackageDataObjectList(),
                                _ => throw new NotImplementedException(),
                            });
                        });
 public void ParsePrependedStringTypical()
 {
     BinaryStringUtility.ParsePrependedString(File.ReadAllBytes(TestDataPathing.PrependedString), 2, MutagenEncodingProvider._1252)
     .Should().Be("HelloWorld");
 }
 public void ParsePrependedStringZeroLength()
 {
     BinaryStringUtility.ParsePrependedString(File.ReadAllBytes(TestDataPathing.ZeroContentPrependedString), 2, MutagenEncodingProvider._1252)
     .Should().Be("");
 }
        public void ProcessNullTerminationOnEmpty()
        {
            var span = BinaryStringUtility.ProcessNullTermination(Array.Empty <byte>().AsSpan());

            span.Length.Should().Be(0);
        }
Exemple #25
0
 /// <summary>
 /// Interprets a subrecord's content as a string.
 /// </summary>
 /// <param name="frame">Frame to read from</param>
 /// <param name="encoding">Encoding to use</param>
 /// <returns>Subrecord's content as a string, null trimmed if applicable</returns>
 public static string AsString(this SubrecordFrame frame, IMutagenEncoding encoding)
 {
     return(BinaryStringUtility.ProcessWholeToZString(frame.Content, encoding));
 }