// Generated from executable documentation examples. Edit the source region, then regenerate. using System; using System.IO; using System.IO.Pipelines; using System.Linq; using System.Buffers; using System.Collections.Generic; using System.Dynamic; using System.Globalization; using System.Numerics; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using CStructSharp; using CStructSharp.Codecs; using CStructSharp.Diagnostics; using CStructSharp.Introspection; using CStructSharp.Values; internal static partial class Program { public static void Main() { FlagsAndDataSizedArrays(); Console.WriteLine("PASS flags-and-data-sized-arrays"); } private static void FlagsAndDataSizedArrays() { // A flag reads as a decomposed name list; `[]` on a struct is an array terminated by an all-zero // element (the exFAT/APFS habit) and `[EOF]` takes every whole element that remains. const string definition = """ flag access : uint16 { READ, WRITE, EXEC, HIDDEN = 0x100 }; struct entry { uint8 kind; uint8 size; }; struct root { access mode; entry entries[]; uint16 trailer[EOF]; }; """; var layout = new CStruct(definition); byte[] bytes = [0x05, 0x01, 1, 10, 2, 20, 0, 0, 0x34, 0x12, 0x78, 0x56]; StructValue root = layout.Parse(bytes, "root"); FlagValueResult mode = root.Get("mode"); Equal("READ|EXEC|HIDDEN", string.Join("|", mode.Names)); True(mode.Has("EXEC") && !mode.Has("WRITE"), "EXEC is set and WRITE is not"); Equal(2, root.Get>("entries").Count); Equal((ushort)0x5678, root.Get("trailer[1]")); // Writing appends the terminator element and nothing after the read-to-end array; a flag accepts names. byte[] written = layout.Serialize( "root", new Dictionary { ["mode"] = "READ|HIDDEN", ["entries"] = new object[] { new Dictionary { ["kind"] = (byte)3, ["size"] = (byte)30 } }, ["trailer"] = new ushort[] { 1 }, }); SequenceEqual([0x01, 0x01, 3, 30, 0, 0, 0x01, 0x00], written); } private static void Equal(T expected, T actual) { if (!EqualityComparer.Default.Equals(expected, actual)) { throw new InvalidOperationException($"Expected '{expected}', received '{actual}'."); } } private static void True(bool condition, string message) { if (!condition) { throw new InvalidOperationException(message); } } private static void SequenceEqual(byte[] expected, byte[] actual) { if (!expected.AsSpan().SequenceEqual(actual)) { throw new InvalidOperationException( $"Expected {Convert.ToHexString(expected)}, received {Convert.ToHexString(actual)}."); } } }