[Symbian Installation File] Decode simple file records.

This commit is contained in:
2023-10-07 10:27:35 +01:00
parent a57ec70d43
commit fff5d129eb
7 changed files with 246 additions and 3 deletions

View File

@@ -131,6 +131,24 @@ namespace Aaru.Archives {
}
}
/// <summary>
/// Looks up a localized string similar to Files for `{0}` language:.
/// </summary>
internal static string Files_for_0_language {
get {
return ResourceManager.GetString("Files_for_0_language", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Files for all languages:.
/// </summary>
internal static string Files_for_all_languages {
get {
return ResourceManager.GetString("Files_for_all_languages", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to SIS contains an application.
/// </summary>

View File

@@ -63,4 +63,10 @@
<data name="Component_version_0_1" xml:space="preserve">
<value>Versión del componente: {0}.{1}</value>
</data>
<data name="Files_for_0_language" xml:space="preserve">
<value>Ficheros para el idioma `{0}`:</value>
</data>
<data name="Files_for_all_languages" xml:space="preserve">
<value>Ficheros para todos los idiomas:</value>
</data>
</root>

View File

@@ -71,4 +71,10 @@
<data name="Component_name_for_language_with_code_0_1" xml:space="preserve">
<value>Component name for language with code {0}: {1}</value>
</data>
<data name="Files_for_all_languages" xml:space="preserve">
<value>Files for all languages:</value>
</data>
<data name="Files_for_0_language" xml:space="preserve">
<value>Files for `{0}` language:</value>
</data>
</root>

View File

@@ -33,6 +33,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Aaru.CommonTypes.Interfaces;
@@ -134,11 +135,14 @@ public partial class Symbian
capabilities.Add(cap_Key, cap_Value);
}
_release6 = false;
if(sh.uid1 == SYMBIAN9_MAGIC)
{
description.AppendLine(Localization.Symbian_Installation_File);
description.AppendLine(Localization.Symbian_9_1_or_later);
description.AppendFormat(Localization.Application_ID_0, sh.uid3).AppendLine();
_release6 = true;
}
else if(sh.uid3 == SYMBIAN_MAGIC)
{
@@ -151,6 +155,7 @@ public partial class Symbian
break;
case EPOC6_MAGIC:
description.AppendLine(Localization.Symbian_6_or_later);
_release6 = true;
break;
default:
description.AppendFormat(Localization.Unknown_EPOC_magic_0, sh.uid2).AppendLine();
@@ -203,6 +208,39 @@ public partial class Symbian
// foreach(KeyValuePair<uint, uint> kvp in capabilities)
// description.AppendFormat("{0} = {1}", kvp.Key, kvp.Value).AppendLine();
// Set instance values
_encoding = encoding;
_files = new List<DecodedFileRecord>();
uint currentFile = 0;
uint offset = sh.files_ptr;
do
{
Parse(br, ref offset, ref currentFile, sh.files);
} while(currentFile < sh.files);
// Files appear on .sis in the reverse order they should be processed
_files.Reverse();
if(_files.Any(t => t.language is null))
{
description.AppendLine(Localization.Files_for_all_languages);
foreach(DecodedFileRecord file in _files.Where(t => t.language is null))
description.AppendLine($"{file.destinationName}");
description.AppendLine();
}
foreach(string lang in languages)
{
if(_files.All(t => t.language != lang))
continue;
description.AppendFormat(Localization.Files_for_0_language, lang).AppendLine();
foreach(DecodedFileRecord file in _files.Where(t => t.language == lang))
description.AppendLine($"{file.destinationName}");
}
information = description.ToString();
}

View File

@@ -0,0 +1,121 @@
// /***************************************************************************
// 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-2023 Natalia Portillo
// ****************************************************************************/
using System;
using System.IO;
using Aaru.Console;
using Aaru.Helpers;
namespace Aaru.Archives;
public partial class Symbian
{
void Parse(BinaryReader br, ref uint offset, ref uint currentFile, uint maxFiles)
{
currentFile++;
if(currentFile > maxFiles)
return;
AaruConsole.DebugWriteLine(MODULE_NAME, "Seeking to {0} for parsing of file {1} of {2}", offset, currentFile,
maxFiles);
br.BaseStream.Seek(offset, SeekOrigin.Begin);
var recordType = (FileRecordType)br.ReadUInt32();
AaruConsole.DebugWriteLine(MODULE_NAME, "Found record with type {0}", recordType);
br.BaseStream.Seek(-sizeof(FileRecordType), SeekOrigin.Current);
byte[] buffer;
switch(recordType)
{
case FileRecordType.SimpleFile:
buffer = br.ReadBytes(Marshal.SizeOf<SimpleFileRecord>());
SimpleFileRecord simpleFileRecord = Marshal.ByteArrayToStructureLittleEndian<SimpleFileRecord>(buffer);
offset = (uint)br.BaseStream.Position;
// Remove the 3 fields that exist only on >= ER6
if(!_release6)
offset -= sizeof(uint) * 3;
var decodedFileRecord = new DecodedFileRecord
{
type = simpleFileRecord.record.type,
details = simpleFileRecord.record.details,
length = simpleFileRecord.length,
pointer = simpleFileRecord.pointer
};
br.BaseStream.Seek(simpleFileRecord.record.sourceNamePtr, SeekOrigin.Begin);
buffer = br.ReadBytes((int)simpleFileRecord.record.sourceNameLen);
decodedFileRecord.sourceName = _encoding.GetString(buffer);
br.BaseStream.Seek(simpleFileRecord.record.destinationNamePtr, SeekOrigin.Begin);
buffer = br.ReadBytes((int)simpleFileRecord.record.destinationNameLen);
decodedFileRecord.destinationName = _encoding.GetString(buffer);
if(_release6)
{
decodedFileRecord.originalLength = simpleFileRecord.originalLength;
br.BaseStream.Seek(simpleFileRecord.mimePtr, SeekOrigin.Begin);
buffer = br.ReadBytes((int)simpleFileRecord.mimeLen);
decodedFileRecord.mime = _encoding.GetString(buffer);
}
AaruConsole.DebugWriteLine(MODULE_NAME, "Found file for \"{0}\" with length {1} at {2}",
decodedFileRecord.destinationName, decodedFileRecord.length,
decodedFileRecord.pointer);
_files.Add(decodedFileRecord);
break;
case FileRecordType.MultipleLanguageFiles:
throw new NotImplementedException();
case FileRecordType.Options:
throw new NotImplementedException();
case FileRecordType.If:
throw new NotImplementedException();
case FileRecordType.ElseIf:
throw new NotImplementedException();
case FileRecordType.Else:
throw new NotImplementedException();
case FileRecordType.EndIf:
throw new NotImplementedException();
default:
throw new ArgumentOutOfRangeException();
}
}
}

View File

@@ -207,6 +207,54 @@ public partial class Symbian
#endregion
#region Nested type: DecodedFileRecord
/// <summary>
/// On-memory structure
/// </summary>
struct DecodedFileRecord
{
/// <summary>
/// File type <see cref="FileType" />
/// </summary>
public FileType type;
/// <summary>
/// File details <see cref="FileDetails" />
/// </summary>
public FileDetails details;
/// <summary>
/// Source name (filename on the machine that built the SIS)
/// </summary>
public string sourceName;
/// <summary>
/// Destination name (filename+path it will be installed to. '!:' for drive means allow the user
/// to pick destination drive)
/// </summary>
public string destinationName;
/// <summary>
/// Length in bytes of the (compressed or uncompressed) file
/// </summary>
public uint length;
/// <summary>
/// Pointer to the (compressed or uncompressed) file data
/// </summary>
public uint pointer;
/// <summary>
/// EPOC Release >= 6, uncompressed file length
/// </summary>
public uint originalLength;
/// <summary>
/// EPOC Release >= 6, MIME type string
/// </summary>
public string mime;
/// <summary>
/// Language, or null for no language
/// </summary>
public string language;
}
#endregion
#region Nested type: MultipleFileRecord
/// <summary>
@@ -217,7 +265,7 @@ public partial class Symbian
/// <summary>
/// Common fields to simple file record and multiple file record
/// </summary>
BaseFileRecord record;
public BaseFileRecord record;
/// <summary>
/// Lengths in bytes of the (compressed or uncompressed) files, array sorted as language records
/// </summary>
@@ -339,7 +387,7 @@ public partial class Symbian
/// <summary>
/// Common fields to simple file record and multiple file record
/// </summary>
BaseFileRecord record;
public BaseFileRecord record;
/// <summary>
/// Length in bytes of the (compressed or uncompressed) file
/// </summary>

View File

@@ -31,6 +31,8 @@
// ****************************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using Aaru.CommonTypes.Interfaces;
namespace Aaru.Archives;
@@ -38,7 +40,11 @@ namespace Aaru.Archives;
// Information from https://thoukydides.github.io/riscos-psifs/sis.html
public partial class Symbian : IArchive
{
const string MODULE_NAME = "Symbian Installation File Plugin";
const string MODULE_NAME = "Symbian Installation File Plugin";
Encoding _encoding;
List<DecodedFileRecord> _files;
bool _release6;
#region IArchive Members