diff --git a/Aaru.Archives/Symbian/Conditions.cs b/Aaru.Archives/Symbian/Conditions.cs new file mode 100644 index 000000000..f867ed512 --- /dev/null +++ b/Aaru.Archives/Symbian/Conditions.cs @@ -0,0 +1,274 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Symbian.cs +// Author(s) : Natalia Portillo +// +// Component : Symbian plugin. +// +// --[ Description ] ---------------------------------------------------------- +// +// Identifies Symbian installer (.sis) packages and shows information. +// +// --[ License ] -------------------------------------------------------------- +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2023 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.IO; +using System.Text; + +namespace Aaru.Archives; + +public sealed partial class Symbian +{ + ConditionalExpression ParseConditionalExpression(BinaryReader br, uint maxOffset, StringBuilder sb, + ref Attribute? attribute) + { + if(br.BaseStream.Position >= maxOffset) + return null; + + var type = (ConditionalType)br.ReadUInt32(); + var operatorString = ""; + + SubConditionalExpression subExpression; + TwoSubsConditionalExpression twoSubsConditionalExpression; + switch(type) + { + case ConditionalType.Equals: + if(type == ConditionalType.Equals) + operatorString = " == "; + + twoSubsConditionalExpression = new TwoSubsConditionalExpression + { + type = type + }; + + sb.Append("("); + twoSubsConditionalExpression.leftOperand = ParseConditionalExpression(br, maxOffset, sb, ref attribute); + sb.Append(operatorString); + twoSubsConditionalExpression.rightOperand = + ParseConditionalExpression(br, maxOffset, sb, ref attribute); + sb.Append(")"); + + attribute = null; + + return twoSubsConditionalExpression; + case ConditionalType.Differs: + operatorString = " != "; + goto case ConditionalType.Equals; + case ConditionalType.GreaterThan: + operatorString = " > "; + goto case ConditionalType.Equals; + case ConditionalType.LessThan: + operatorString = " < "; + goto case ConditionalType.Equals; + case ConditionalType.GreaterOrEqualThan: + operatorString = " >= "; + goto case ConditionalType.Equals; + case ConditionalType.LessOrEqualThan: + operatorString = " <= "; + goto case ConditionalType.Equals; + case ConditionalType.And: + operatorString = " && "; + goto case ConditionalType.Equals; + case ConditionalType.Or: + operatorString = " || "; + goto case ConditionalType.Equals; + case ConditionalType.Exists: + sb.Append("exists("); + subExpression = new SubConditionalExpression + { + type = type, + subExpression = ParseConditionalExpression(br, maxOffset, sb, ref attribute) + }; + sb.Append(")"); + + attribute = null; + + return subExpression; + case ConditionalType.DeviceCapability: + sb.Append("devcap("); + subExpression = new SubConditionalExpression + { + type = type, + subExpression = ParseConditionalExpression(br, maxOffset, sb, ref attribute) + }; + sb.Append(')'); + + attribute = null; + + return subExpression; + case ConditionalType.ApplicationCapability: + twoSubsConditionalExpression = new TwoSubsConditionalExpression + { + type = type + }; + + sb.Append("appcap("); + twoSubsConditionalExpression.leftOperand = ParseConditionalExpression(br, maxOffset, sb, ref attribute); + sb.Append(", "); + twoSubsConditionalExpression.rightOperand = + ParseConditionalExpression(br, maxOffset, sb, ref attribute); + sb.Append(')'); + + attribute = null; + + return twoSubsConditionalExpression; + case ConditionalType.Not: + sb.Append('!'); + subExpression = new SubConditionalExpression + { + type = type, + subExpression = ParseConditionalExpression(br, maxOffset, sb, ref attribute) + }; + + attribute = null; + + return subExpression; + case ConditionalType.String: + var stringExpression = new StringConditionalExpression + { + type = type, + length = br.ReadUInt32(), + pointer = br.ReadUInt32() + }; + + long position = br.BaseStream.Position; + + br.BaseStream.Seek(stringExpression.pointer, SeekOrigin.Begin); + byte[] buffer = br.ReadBytes((int)stringExpression.length); + stringExpression.@string = _encoding.GetString(buffer); + + br.BaseStream.Seek(position, SeekOrigin.Begin); + + sb.Append($"\"{stringExpression.@string}\""); + + attribute = null; + + break; + case ConditionalType.Attribute: + var attributeExpression = new AttributeConditionalExpression + { + type = type, + attribute = (Attribute)br.ReadUInt32(), + unused = br.ReadUInt32() + }; + + sb.Append($"{attributeExpression.attribute}"); + + attribute = attributeExpression.attribute; + + return attributeExpression; + case ConditionalType.Number: + var numberExpression = new NumberConditionalExpression + { + type = type, + number = br.ReadUInt32(), + unused = br.ReadUInt32() + }; + + switch(attribute) + { + case Attribute.Manufacturer: + sb.Append($"{(ManufacturerCode)numberExpression.number}"); + break; + case Attribute.ManufacturerHardwareRev: + case Attribute.ManufacturerSoftwareRev: + case Attribute.DeviceFamilyRev: + sb.Append($"{numberExpression.number >> 8}.{numberExpression.number & 0xFF}"); + break; + case Attribute.MachineUid: + sb.Append($"{DecodeMachineUid(numberExpression.number)}"); + + break; + case Attribute.DeviceFamily: + sb.Append($"{(DeviceFamilyCode)numberExpression.number}"); + break; + case Attribute.CPU: + sb.Append($"{(CpuCode)numberExpression.number}"); + break; + case Attribute.CPUArch: + sb.Append($"{(CpuArchitecture)numberExpression.number}"); + break; + case Attribute.CPUABI: + sb.Append($"{(CpuAbiCode)numberExpression.number}"); + break; + case Attribute.CPUSpeed: + sb.Append($"{numberExpression.number / 1024}MHz"); + break; + case Attribute.SystemTickPeriod: + sb.Append($"{numberExpression.number}μs"); + + break; + case Attribute.MemoryRAM: + case Attribute.MemoryRAMFree: + case Attribute.MemoryROM: + case Attribute.MemoryPageSize: + case Attribute.Keyboard: + case Attribute.KeyboardDeviceKeys: + case Attribute.KeyboardAppKeys: + case Attribute.KeyboardClickVolumeMax: + case Attribute.DisplayXPixels: + case Attribute.DisplayYPixels: + case Attribute.DisplayXTwips: + case Attribute.DisplayYTwips: + case Attribute.DisplayColors: + case Attribute.DisplayContrastMax: + case Attribute.PenX: + case Attribute.PenY: + case Attribute.PenClickVolumeMax: + case Attribute.MouseX: + case Attribute.MouseY: + case Attribute.MouseButtons: + case Attribute.LEDs: + case Attribute.DisplayBrightnessMax: + case Attribute.KeyboardBacklightState: + case Attribute.AccessoryPower: + case Attribute.NumHalAttributes: + case Attribute.Language: + sb.Append($"{numberExpression.number}"); + break; + case Attribute.PowerBackup: + case Attribute.KeyboardClick: + case Attribute.Backlight: + case Attribute.Pen: + case Attribute.PenDisplayOn: + case Attribute.PenClick: + case Attribute.Mouse: + case Attribute.CaseSwitch: + case Attribute.IntegratedPhone: + case Attribute.RemoteInstall: + sb.Append(numberExpression.number == 0 ? "false" : "true"); + break; + default: + sb.Append($"0x{numberExpression.number:X8}"); + break; + } + + attribute = null; + + return numberExpression; + default: + throw new ArgumentOutOfRangeException(); + } + + return null; + } +} \ No newline at end of file diff --git a/Aaru.Archives/Symbian/Info.cs b/Aaru.Archives/Symbian/Info.cs index 96898351a..66fb62b39 100644 --- a/Aaru.Archives/Symbian/Info.cs +++ b/Aaru.Archives/Symbian/Info.cs @@ -295,20 +295,24 @@ public sealed partial class Symbian // description.AppendFormat("{0} = {1}", kvp.Key, kvp.Value).AppendLine(); // Set instance values - _files = new List(); + _files = new List(); + _conditions = new List(); uint currentFile = 0; offset = sh.files_ptr; + var conditionLevel = 0; do { - Parse(br, ref offset, ref currentFile, sh.files, languages); + Parse(br, ref offset, ref currentFile, sh.files, languages, ref conditionLevel); } while(currentFile < sh.files); description.AppendLine(); // Files appear on .sis in the reverse order they should be processed _files.Reverse(); + // Conditions do as well + _conditions.Reverse(); if(_files.Any(t => t.language is null)) { @@ -329,6 +333,13 @@ public sealed partial class Symbian description.AppendLine(); } + if(_conditions.Count > 0) + { + description.AppendLine("Conditions:"); + foreach(string condition in _conditions) + description.AppendLine(condition); + } + information = description.ToString(); } diff --git a/Aaru.Archives/Symbian/Open.cs b/Aaru.Archives/Symbian/Open.cs index 6b75038e7..0d6600dbb 100644 --- a/Aaru.Archives/Symbian/Open.cs +++ b/Aaru.Archives/Symbian/Open.cs @@ -128,12 +128,13 @@ public sealed partial class Symbian _files = new List(); - uint currentFile = 0; - uint offset = sh.files_ptr; + uint currentFile = 0; + uint offset = sh.files_ptr; + var conditionLevel = 0; do { - Parse(br, ref offset, ref currentFile, sh.files, languages); + Parse(br, ref offset, ref currentFile, sh.files, languages, ref conditionLevel); } while(currentFile < sh.files); // Files appear on .sis in the reverse order they should be processed diff --git a/Aaru.Archives/Symbian/Parser.cs b/Aaru.Archives/Symbian/Parser.cs index 6fd348b3b..997c3905f 100644 --- a/Aaru.Archives/Symbian/Parser.cs +++ b/Aaru.Archives/Symbian/Parser.cs @@ -32,22 +32,31 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Runtime.InteropServices; +using System.Text; using Aaru.Console; using Marshal = Aaru.Helpers.Marshal; namespace Aaru.Archives; +[SuppressMessage("ReSharper", "UnusedMember.Local")] public sealed partial class Symbian { - void Parse(BinaryReader br, ref uint offset, ref uint currentFile, uint maxFiles, List languages) + void Parse(BinaryReader br, ref uint offset, ref uint currentFile, uint maxFiles, List languages, + ref int conditionLevel) { currentFile++; if(currentFile > maxFiles) return; + var tabulationChars = new char[conditionLevel]; + for(var i = 0; i < conditionLevel; i++) + tabulationChars[i] = '\t'; + string tabulation = new(tabulationChars); + AaruConsole.DebugWriteLine(MODULE_NAME, "Seeking to {0} for parsing of file {1} of {2}", offset, currentFile, maxFiles); @@ -58,8 +67,11 @@ public sealed partial class Symbian br.BaseStream.Seek(-sizeof(FileRecordType), SeekOrigin.Current); - byte[] buffer; + byte[] buffer; + ConditionalRecord conditionalRecord; + StringBuilder conditionSb; + Attribute? nullAttribute; switch(recordType) { case FileRecordType.SimpleFile: @@ -109,6 +121,129 @@ public sealed partial class Symbian _files.Add(decodedFileRecord); + if(conditionLevel > 0) + { + bool wait, close; + switch(decodedFileRecord.type) + { + case FileType.FileText: + switch((FileDetails)((uint)decodedFileRecord.details & 0xFF)) + { + case FileDetails.TextContinue: + _conditions.Add(tabulation + + $"ShowText(\"{decodedFileRecord.sourceName}\", BUTTONS_CONTINUE, ACTION_CONTINUE)"); + break; + case FileDetails.TextSkip: + _conditions.Add(tabulation + + $"ShowText(\"{decodedFileRecord.sourceName}\", BUTTONS_YES_NO, ACTION_SKIP)"); + break; + case FileDetails.TextAbort: + _conditions.Add(tabulation + + $"ShowText(\"{decodedFileRecord.sourceName}\", BUTTONS_YES_NO, ACTION_ABORT)"); + break; + case FileDetails.TextExit: + _conditions.Add(tabulation + + $"ShowText(\"{decodedFileRecord.sourceName}\", BUTTONS_YES_NO, ACTION_EXIT)"); + break; + } + + break; + case FileType.FileRun: + // ReSharper disable BitwiseOperatorOnEnumWithoutFlags + wait = (decodedFileRecord.details & FileDetails.RunWait) != 0; + close = (decodedFileRecord.details & FileDetails.RunsEnd) != 0; + // ReSharper restore BitwiseOperatorOnEnumWithoutFlags + switch((FileDetails)((uint)decodedFileRecord.details & 0xFF)) + { + case FileDetails.RunInstall: + if(wait && close) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecord.sourceName}\", ON_INSTALL, WAIT | CLOSE)"); + } + else if(close) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecord.sourceName}\", ON_INSTALL, CLOSE)"); + } + else if(wait) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecord.sourceName}\", ON_INSTALL, WAIT)"); + } + else + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecord.sourceName}\", ON_INSTALL, 0)"); + } + + break; + case FileDetails.RunRemove: + if(wait && close) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecord.sourceName}\", ON_REMOVE, WAIT | CLOSE)"); + } + else if(close) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecord.sourceName}\", ON_REMOVE, CLOSE)"); + } + else if(wait) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecord.sourceName}\", ON_REMOVE, WAIT)"); + } + else + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecord.sourceName}\", ON_REMOVE, 0)"); + } + + break; + case FileDetails.RunBoth: + if(wait && close) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecord.sourceName}\", ON_INSTALL | ON_REMOVE, WAIT | CLOSE)"); + } + else if(close) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecord.sourceName}\", ON_INSTALL | ON_REMOVE, CLOSE)"); + } + else if(wait) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecord.sourceName}\", ON_INSTALL | ON_REMOVE, WAIT)"); + } + else + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecord.sourceName}\", ON_INSTALL | ON_REMOVE, 0)"); + } + + break; + } + + break; + case FileType.FileMime: + // ReSharper disable BitwiseOperatorOnEnumWithoutFlags + wait = (decodedFileRecord.details & FileDetails.RunWait) != 0; + close = (decodedFileRecord.details & FileDetails.RunsEnd) != 0; + // ReSharper restore BitwiseOperatorOnEnumWithoutFlags + if(wait && close) + _conditions.Add(tabulation + $"Open(\"{decodedFileRecord.sourceName}\", WAIT | CLOSE)"); + else if(close) + _conditions.Add(tabulation + $"Open(\"{decodedFileRecord.sourceName}\", CLOSE)"); + else if(wait) + _conditions.Add(tabulation + $"Open(\"{decodedFileRecord.sourceName}\", WAIT)"); + else + _conditions.Add(tabulation + $"Open(\"{decodedFileRecord.sourceName}\", 0)"); + break; + } + } + break; case FileRecordType.MultipleLanguageFiles: MultipleFileRecord multipleFileRecord = new(); @@ -148,7 +283,7 @@ public sealed partial class Symbian if(multipleFileRecord.record.destinationNameLen > 0) { br.BaseStream.Seek(multipleFileRecord.record.destinationNamePtr, SeekOrigin.Begin); - buffer = br.ReadBytes((int)multipleFileRecord.record.destinationNameLen); + buffer = br.ReadBytes((int)multipleFileRecord.record.destinationNameLen); destinationName = _encoding.GetString(buffer); } else @@ -180,17 +315,202 @@ public sealed partial class Symbian _files.AddRange(decodedFileRecords); + if(conditionLevel > 0) + { + bool wait, close; + switch(decodedFileRecords[0].type) + { + case FileType.FileText: + switch((FileDetails)((uint)decodedFileRecords[0].details & 0xFF)) + { + case FileDetails.TextContinue: + _conditions.Add(tabulation + + $"ShowText(\"{decodedFileRecords[0].sourceName}\", BUTTONS_CONTINUE, ACTION_CONTINUE)"); + break; + case FileDetails.TextSkip: + _conditions.Add(tabulation + + $"ShowText(\"{decodedFileRecords[0].sourceName}\", BUTTONS_YES_NO, ACTION_SKIP)"); + break; + case FileDetails.TextAbort: + _conditions.Add(tabulation + + $"ShowText(\"{decodedFileRecords[0].sourceName}\", BUTTONS_YES_NO, ACTION_ABORT)"); + break; + case FileDetails.TextExit: + _conditions.Add(tabulation + + $"ShowText(\"{decodedFileRecords[0].sourceName}\", BUTTONS_YES_NO, ACTION_EXIT)"); + break; + } + + break; + case FileType.FileRun: + // ReSharper disable BitwiseOperatorOnEnumWithoutFlags + wait = (decodedFileRecords[0].details & FileDetails.RunWait) != 0; + close = (decodedFileRecords[0].details & FileDetails.RunsEnd) != 0; + // ReSharper restore BitwiseOperatorOnEnumWithoutFlags + switch((FileDetails)((uint)decodedFileRecords[0].details & 0xFF)) + { + case FileDetails.RunInstall: + if(wait && close) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecords[0].sourceName}\", ON_INSTALL, WAIT | CLOSE)"); + } + else if(close) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecords[0].sourceName}\", ON_INSTALL, CLOSE)"); + } + else if(wait) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecords[0].sourceName}\", ON_INSTALL, WAIT)"); + } + else + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecords[0].sourceName}\", ON_INSTALL, 0)"); + } + + break; + case FileDetails.RunRemove: + if(wait && close) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecords[0].sourceName}\", ON_REMOVE, WAIT | CLOSE)"); + } + else if(close) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecords[0].sourceName}\", ON_REMOVE, CLOSE)"); + } + else if(wait) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecords[0].sourceName}\", ON_REMOVE, WAIT)"); + } + else + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecords[0].sourceName}\", ON_REMOVE, 0)"); + } + + break; + case FileDetails.RunBoth: + if(wait && close) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecords[0].sourceName}\", ON_INSTALL | ON_REMOVE, WAIT | CLOSE)"); + } + else if(close) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecords[0].sourceName}\", ON_INSTALL | ON_REMOVE, CLOSE)"); + } + else if(wait) + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecords[0].sourceName}\", ON_INSTALL | ON_REMOVE, WAIT)"); + } + else + { + _conditions.Add(tabulation + + $"Run(\"{decodedFileRecords[0].sourceName}\", ON_INSTALL | ON_REMOVE, 0)"); + } + + break; + } + + break; + case FileType.FileMime: + // ReSharper disable BitwiseOperatorOnEnumWithoutFlags + wait = (decodedFileRecords[0].details & FileDetails.RunWait) != 0; + close = (decodedFileRecords[0].details & FileDetails.RunsEnd) != 0; + // ReSharper restore BitwiseOperatorOnEnumWithoutFlags + if(wait && close) + { + _conditions.Add(tabulation + + $"Open(\"{decodedFileRecords[0].sourceName}\", WAIT | CLOSE)"); + } + else if(close) + _conditions.Add(tabulation + $"Open(\"{decodedFileRecords[0].sourceName}\", CLOSE)"); + else if(wait) + _conditions.Add(tabulation + $"Open(\"{decodedFileRecords[0].sourceName}\", WAIT)"); + else + _conditions.Add(tabulation + $"Open(\"{decodedFileRecords[0].sourceName}\", 0)"); + + break; + } + } + break; case FileRecordType.Options: throw new NotImplementedException(); case FileRecordType.If: - throw new NotImplementedException(); + conditionLevel--; + + tabulationChars = new char[conditionLevel]; + for(var i = 0; i < conditionLevel; i++) + tabulationChars[i] = '\t'; + tabulation = new string(tabulationChars); + + conditionalRecord = new ConditionalRecord + { + recordType = (FileRecordType)br.ReadUInt32(), + length = br.ReadUInt32() + }; + + offset = (uint)(br.BaseStream.Position + conditionalRecord.length); + conditionSb = new StringBuilder(); + nullAttribute = null; + + conditionSb.Append(tabulation + "if("); + ParseConditionalExpression(br, offset, conditionSb, ref nullAttribute); + conditionSb.Append(")"); + + _conditions.Add(conditionSb.ToString()); + + break; case FileRecordType.ElseIf: - throw new NotImplementedException(); + conditionLevel--; + + tabulationChars = new char[conditionLevel]; + for(var i = 0; i < conditionLevel; i++) + tabulationChars[i] = '\t'; + tabulation = new string(tabulationChars); + + conditionalRecord = new ConditionalRecord + { + recordType = (FileRecordType)br.ReadUInt32(), + length = br.ReadUInt32() + }; + + offset = (uint)(br.BaseStream.Position + conditionalRecord.length); + conditionSb = new StringBuilder(); + nullAttribute = null; + + conditionSb.Append(tabulation + "else if("); + ParseConditionalExpression(br, offset, conditionSb, ref nullAttribute); + conditionSb.Append(")"); + + _conditions.Add(conditionSb.ToString()); + + break; case FileRecordType.Else: - throw new NotImplementedException(); + tabulationChars = new char[conditionLevel - 1]; + for(var i = 0; i < conditionLevel - 1; i++) + tabulationChars[i] = '\t'; + tabulation = new string(tabulationChars); + + _conditions.Add(tabulation + "else"); + offset = (uint)(br.BaseStream.Position + Marshal.SizeOf()); + + break; case FileRecordType.EndIf: - throw new NotImplementedException(); + conditionLevel++; + _conditions.Add(tabulation + "endif()" + Environment.NewLine); + offset = (uint)(br.BaseStream.Position + Marshal.SizeOf()); + + break; default: throw new ArgumentOutOfRangeException(); } diff --git a/Aaru.Archives/Symbian/Structs.cs b/Aaru.Archives/Symbian/Structs.cs index 921e64217..0709706f9 100644 --- a/Aaru.Archives/Symbian/Structs.cs +++ b/Aaru.Archives/Symbian/Structs.cs @@ -44,6 +44,7 @@ namespace Aaru.Archives; [SuppressMessage("ReSharper", "InconsistentNaming")] [SuppressMessage("ReSharper", "InheritdocConsiderUsage")] [SuppressMessage("ReSharper", "NotAccessedField.Local")] +[SuppressMessage("ReSharper", "ClassCanBeSealed.Local")] public sealed partial class Symbian { #region Nested type: AttributeConditionalExpression @@ -420,8 +421,9 @@ public sealed partial class Symbian /// class StringConditionalExpression : ConditionalExpression { - public uint length; - public uint pointer; + public uint length; + public uint pointer; + public string @string; } #endregion diff --git a/Aaru.Archives/Symbian/Symbian.cs b/Aaru.Archives/Symbian/Symbian.cs index 38b885a8b..cc395691c 100644 --- a/Aaru.Archives/Symbian/Symbian.cs +++ b/Aaru.Archives/Symbian/Symbian.cs @@ -43,6 +43,7 @@ public sealed partial class Symbian : IArchive { const string MODULE_NAME = "Symbian Installation File Plugin"; bool _compressed; + List _conditions; Encoding _encoding; ArchiveSupportedFeature _features; List _files;