private IField ToField(ModuleSchema schema, ModuleJson module, string name, int offset, string description, FieldCondition?condition) { // TODO: Validate that we don't have "extra" parameters? return(Type switch { "boolean" => (IField) new BooleanField(BuildCommon(1)), "boolean32" => new BooleanField(BuildCommon(4)), "range8" => BuildNumericField(1), "range16" => BuildNumericField(2), "range32" => BuildNumericField(4), "enum" => BuildEnumField(1), "enum16" => BuildEnumField(2), "enum32" => BuildEnumField(4), "dynamicOverlay" => BuildDynamicOverlay(), "instrument" => new InstrumentField(BuildCommon(4), ValidateNotNull(BankOffset, nameof(BankOffset)).Value, ValidateNotNull(VeditOffset, nameof(VeditOffset)).Value), "musicalNote" => new EnumField(BuildCommon(4), MusicalNoteValues, 0, 0), "volume32" => new NumericField(BuildCommon(4), -601, 60, 0, 10, null, 0, "dB", (-601, "-INF")), "string" => BuildStringField(1), "string16" => BuildStringField(2), "midi32" => new MidiNoteField(BuildCommon(4)), string text when text.StartsWith(ContainerPrefix) => BuildContainer(), _ => throw new InvalidOperationException($"Unknown field type: {Type}") });
private VisualTreeConversionContext( ModuleJson moduleJson, FixedContainer containerContext, IReadOnlyDictionary <string, string> lookupsByPath, List <KeyValuePair <string, string> > indexes) { this.moduleJson = moduleJson; this.ContainerContext = containerContext; this.lookupsByPath = lookupsByPath; this.indexes = indexes; }
internal Container ToContainer(ModuleSchema schema, ModuleJson module, string name, int offset, string description, FieldCondition?condition) { // TODO: This works and is pleasantly efficient, but it's pretty ugly. if (cachedFields == null) { // TODO: Check that all fields are either primitive or container, check the size etc. cachedFields = Fields .SelectMany(fieldJson => fieldJson.ToFields(schema, module)) .ToList() .AsReadOnly(); } var lastField = Fields.LastOrDefault(); int size = Size?.Value ?? lastField?.Offset?.Value ?? 0; var common = new FieldBase.Parameters(schema, name, offset, size, description, condition); return(new Container(common, cachedFields)); }
internal IEnumerable <IField> ToFields(ModuleSchema schema, ModuleJson module) { string description = ValidateNotNull(Description, nameof(Description)); string name = Name ?? description; int? repeat = module.GetCount(Repeat); var offset = ValidateNotNull(Offset, nameof(Offset)).Value; FieldCondition?condition = GetCondition(); if (repeat == null) { yield return(ToField(schema, module, name, offset, description, condition)); } else { var gap = ValidateNotNull(Gap, nameof(Gap)).Value; List <string>?lookup = null; if (DescriptionLookup != null) { ValidateNotNull(module.Lookups, nameof(module.Lookups)); lookup = module.Lookups.FirstOrDefault(candidate => candidate.Name == DescriptionLookup)?.Values; Validate(lookup != null, "Lookup ${DescriptionLookup} not found for descriptions."); Validate(lookup !.Count == repeat, $"Lookup ${DescriptionLookup} has {lookup.Count} elements; field has repeats {repeat} times."); } for (int i = 1; i <= repeat; i++) { string indexedName = Invariant($"{name}[{i}]"); string indexValue = i.ToString(CultureInfo.InvariantCulture); string?lookupValue = lookup?[i - 1]; string fullDescription = string.Format(Description, indexValue, lookupValue); yield return(ToField(schema, module, indexedName, offset, fullDescription, condition)); offset += gap; // TODO: This is ugly. We need it because otherwise in SetList we end up with offsets of // 0x03_00_00_00 // 0x03_00_10_00 // 0x03_00_20_00 // .... // 0x03_00_70_00 // 0x03_00_80_00 => This will be promoted to an *address* of 0x03_01_00_00 automatically... // ... // 0x03_00_f0_00 // 0x03_01_00_00 => We now get 0x03_01_00_00 again :( // 0x03_01_10_00 // But it's annoying to have this *here*... if ((offset & 0x80) != 0) { offset += 0x80; } if ((offset & 0x80_00) != 0) { offset += 0x80_00; } if ((offset & 0x80_00_00) != 0) { offset += 0x80_00_00; } } } FieldCondition?GetCondition() { if (Condition is null) { return(null); } int conditionOffset = ValidateNotNull(Condition.Offset, nameof(Condition.Offset)).Value; int requiredValue = ValidateNotNull(Condition.RequiredValue, nameof(Condition.RequiredValue)); return(new FieldCondition(conditionOffset, requiredValue)); } }
internal static VisualTreeConversionContext Create( ModuleJson moduleJson, FixedContainer containerContext, IReadOnlyDictionary <string, string> lookupsByPath) => new VisualTreeConversionContext(moduleJson, containerContext, lookupsByPath, new List <KeyValuePair <string, string> >());