mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 11:14:25 +00:00
201 lines
7.5 KiB
C#
201 lines
7.5 KiB
C#
// /***************************************************************************
|
|
// Aaru Data Preservation Suite
|
|
// ----------------------------------------------------------------------------
|
|
//
|
|
// Filename : Symbian.cs
|
|
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
|
//
|
|
// 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 <http://www.gnu.org/licenses/>.
|
|
//
|
|
// ----------------------------------------------------------------------------
|
|
// Copyright © 2011-2025 Natalia Portillo
|
|
// ****************************************************************************/
|
|
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using Aaru.CommonTypes.Enums;
|
|
using Aaru.CommonTypes.Interfaces;
|
|
using Aaru.Helpers;
|
|
using Aaru.Logging;
|
|
|
|
namespace Aaru.Archives;
|
|
|
|
public sealed partial class Symbian
|
|
{
|
|
#region IArchive Members
|
|
|
|
/// <inheritdoc />
|
|
public ErrorNumber Open(IFilter filter, Encoding encoding)
|
|
{
|
|
// Already opened!
|
|
if(Opened) return ErrorNumber.InvalidArgument;
|
|
|
|
var languages = new List<string>();
|
|
_stream = filter.GetDataForkStream();
|
|
|
|
if(_stream.Length < Marshal.SizeOf<SymbianHeader>()) return ErrorNumber.InvalidArgument;
|
|
|
|
var buffer = new byte[Marshal.SizeOf<SymbianHeader>()];
|
|
|
|
_stream.Seek(0, SeekOrigin.Begin);
|
|
_stream.EnsureRead(buffer, 0, buffer.Length);
|
|
SymbianHeader sh = Marshal.ByteArrayToStructureLittleEndian<SymbianHeader>(buffer);
|
|
|
|
AaruLogging.Debug(MODULE_NAME, "sh.uid1 = {0}", sh.uid1);
|
|
AaruLogging.Debug(MODULE_NAME, "sh.uid2 = {0}", sh.uid2);
|
|
AaruLogging.Debug(MODULE_NAME, "sh.uid3 = {0}", sh.uid3);
|
|
AaruLogging.Debug(MODULE_NAME, "sh.uid4 = {0}", sh.uid4);
|
|
AaruLogging.Debug(MODULE_NAME, "sh.crc16 = {0}", sh.crc16);
|
|
AaruLogging.Debug(MODULE_NAME, "sh.languages = {0}", sh.languages);
|
|
AaruLogging.Debug(MODULE_NAME, "sh.files = {0}", sh.files);
|
|
AaruLogging.Debug(MODULE_NAME, "sh.requisites = {0}", sh.requisites);
|
|
AaruLogging.Debug(MODULE_NAME, "sh.inst_lang = {0}", sh.inst_lang);
|
|
AaruLogging.Debug(MODULE_NAME, "sh.inst_files = {0}", sh.inst_files);
|
|
AaruLogging.Debug(MODULE_NAME, "sh.inst_drive = {0}", sh.inst_drive);
|
|
AaruLogging.Debug(MODULE_NAME, "sh.capabilities = {0}", sh.capabilities);
|
|
AaruLogging.Debug(MODULE_NAME, "sh.inst_version = {0}", sh.inst_version);
|
|
AaruLogging.Debug(MODULE_NAME, "sh.options = {0}", sh.options);
|
|
AaruLogging.Debug(MODULE_NAME, "sh.type = {0}", sh.type);
|
|
AaruLogging.Debug(MODULE_NAME, "sh.major = {0}", sh.major);
|
|
AaruLogging.Debug(MODULE_NAME, "sh.minor = {0}", sh.minor);
|
|
AaruLogging.Debug(MODULE_NAME, "sh.variant = {0}", sh.variant);
|
|
AaruLogging.Debug(MODULE_NAME, "sh.lang_ptr = {0}", sh.lang_ptr);
|
|
AaruLogging.Debug(MODULE_NAME, "sh.files_ptr = {0}", sh.files_ptr);
|
|
AaruLogging.Debug(MODULE_NAME, "sh.reqs_ptr = {0}", sh.reqs_ptr);
|
|
AaruLogging.Debug(MODULE_NAME, "sh.certs_ptr = {0}", sh.certs_ptr);
|
|
AaruLogging.Debug(MODULE_NAME, "sh.comp_ptr = {0}", sh.comp_ptr);
|
|
AaruLogging.Debug(MODULE_NAME, "sh.sig_ptr = {0}", sh.sig_ptr);
|
|
AaruLogging.Debug(MODULE_NAME, "sh.caps_ptr = {0}", sh.caps_ptr);
|
|
AaruLogging.Debug(MODULE_NAME, "sh.instspace = {0}", sh.instspace);
|
|
AaruLogging.Debug(MODULE_NAME, "sh.maxinsspc = {0}", sh.maxinsspc);
|
|
AaruLogging.Debug(MODULE_NAME, "sh.reserved1 = {0}", sh.reserved1);
|
|
AaruLogging.Debug(MODULE_NAME, "sh.reserved2 = {0}", sh.reserved2);
|
|
|
|
_release6 = false;
|
|
|
|
if(sh.uid1 == SYMBIAN9_MAGIC)
|
|
{
|
|
AaruLogging.Error("Symbian Installation Files from Symbian OS 9 or later are not yet supported.");
|
|
|
|
return ErrorNumber.NotSupported;
|
|
}
|
|
|
|
if(sh.uid3 == SYMBIAN_MAGIC)
|
|
{
|
|
switch(sh.uid2)
|
|
{
|
|
case EPOC_MAGIC:
|
|
break;
|
|
case EPOC6_MAGIC:
|
|
_release6 = true;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(sh.options.HasFlag(SymbianOptions.IsUnicode))
|
|
_encoding = Encoding.Unicode;
|
|
else
|
|
_encoding = encoding ?? Encoding.GetEncoding("windows-1252");
|
|
|
|
var br = new BinaryReader(_stream);
|
|
|
|
// Go to enumerate languages
|
|
br.BaseStream.Seek(sh.lang_ptr, SeekOrigin.Begin);
|
|
for(var i = 0; i < sh.languages; i++) languages.Add(((LanguageCodes)br.ReadUInt16()).ToString("G"));
|
|
|
|
_files = [];
|
|
_conditions = [];
|
|
_options = [];
|
|
|
|
uint currentFile = 0;
|
|
uint offset = sh.files_ptr;
|
|
var conditionLevel = 0;
|
|
|
|
// Get only the options records
|
|
do
|
|
{
|
|
Parse(br, ref offset, ref currentFile, sh.files, languages, ref conditionLevel, true);
|
|
} while(currentFile < sh.files);
|
|
|
|
// Get all other records
|
|
offset = sh.files_ptr;
|
|
currentFile = 0;
|
|
conditionLevel = 0;
|
|
|
|
do
|
|
{
|
|
Parse(br, ref offset, ref currentFile, sh.files, languages, ref conditionLevel, false);
|
|
} while(currentFile < sh.files);
|
|
|
|
// Files appear on .sis in the reverse order they should be processed
|
|
_files.Reverse();
|
|
|
|
List<DecodedFileRecord> filesWithFixedFilenames = [];
|
|
|
|
foreach(DecodedFileRecord f in _files)
|
|
{
|
|
DecodedFileRecord file = f;
|
|
|
|
if(file.destinationName.Length > 3 && file.destinationName[1] == ':' && file.destinationName[2] == '\\')
|
|
file.destinationName = file.destinationName[3..];
|
|
|
|
file.destinationName = file.destinationName.Replace('\\', '/');
|
|
|
|
if(file.language != null) file.destinationName = $"{file.language}/{file.destinationName}";
|
|
|
|
filesWithFixedFilenames.Add(file);
|
|
}
|
|
|
|
_files = filesWithFixedFilenames;
|
|
|
|
_features = ArchiveSupportedFeature.SupportsFilenames | ArchiveSupportedFeature.SupportsSubdirectories;
|
|
|
|
if(_release6 && !sh.options.HasFlag(SymbianOptions.NoCompress))
|
|
{
|
|
_features |= ArchiveSupportedFeature.SupportsCompression;
|
|
_compressed = true;
|
|
}
|
|
|
|
if(_files.Any(static t => t.mime is not null)) _features |= ArchiveSupportedFeature.SupportsXAttrs;
|
|
|
|
Opened = true;
|
|
|
|
return ErrorNumber.NoError;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public void Close()
|
|
{
|
|
// Already closed
|
|
if(!Opened) return;
|
|
|
|
_stream?.Close();
|
|
|
|
_stream = null;
|
|
Opened = false;
|
|
}
|
|
|
|
#endregion
|
|
} |