General refactor and restyling.

This commit is contained in:
2021-11-09 19:44:38 +00:00
parent f351cbcf14
commit 38ba41368d
11 changed files with 371 additions and 495 deletions

View File

@@ -29,7 +29,7 @@
<ExternalConsole>true</ExternalConsole> <ExternalConsole>true</ExternalConsole>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Program.cs" /> <Compile Include="Program.cs"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Claunia.RsrcFork\Claunia.RsrcFork.csproj"> <ProjectReference Include="..\Claunia.RsrcFork\Claunia.RsrcFork.csproj">

View File

@@ -31,7 +31,7 @@ using System.Text;
namespace Claunia.RsrcFork.CLI; namespace Claunia.RsrcFork.CLI;
class MainClass internal class MainClass
{ {
public static void Main(string[] args) public static void Main(string[] args)
{ {
@@ -39,103 +39,101 @@ class MainClass
Console.WriteLine("© 2016 Natalia Portillo"); Console.WriteLine("© 2016 Natalia Portillo");
Console.WriteLine(); Console.WriteLine();
if(args.Length != 2 && args.Length != 4) if(args.Length != 2 &&
args.Length != 4)
{ {
Usage(); Usage();
return;
}
if(args.Length == 2)
{
if(args[0] != "-l")
{
Usage();
return;
}
if(!File.Exists(args[1]))
{
Console.WriteLine("Specified file does not exist.");
return;
}
FileStream rsrcStream = new FileStream(args[1], FileMode.Open, FileAccess.Read);
ResourceFork rsrc = new ResourceFork(rsrcStream);
foreach(uint type in rsrc.GetTypes())
{
byte[] typeBytes = BitConverter.GetBytes(type);
typeBytes = typeBytes.Reverse().ToArray();
string typeName = Types.GetName(type);
if(typeName != null)
Console.WriteLine("\"{0}\" (0x{1:X8}) - {2}", Encoding.ASCII.GetString(typeBytes), type,
typeName);
else Console.WriteLine("\"{0}\" (0x{1:X8})", Encoding.ASCII.GetString(typeBytes), type);
Resource rez = rsrc.GetResource(type);
Console.WriteLine("{0,6}{1,8}\t{2}", "ID", "Length", "Name");
Console.WriteLine("{0,6}{1,8}--{2}", "------", "--------", "----------------");
foreach(short id in rez.GetIds())
if(rez.GetName(id) != null)
Console.WriteLine("{0,6}{1,8}\t\"{2}\"", id, rez.GetLength(id), rez.GetName(id));
else Console.WriteLine("{0,6}{1,8}", id, rez.GetLength(id));
Console.WriteLine();
}
return; return;
} }
if(args.Length == 4) switch(args.Length)
{ {
if(args[0] != "-x") case 2 when args[0] != "-l":
{
Usage(); Usage();
return;
}
if(args[1] != "-o")
{
Usage();
return; return;
} case 2 when !File.Exists(args[1]):
if(Directory.Exists(args[2]))
{
Console.WriteLine("Output directory exists, not proceeding");
return;
}
if(!File.Exists(args[3]))
{
Console.WriteLine("Specified file does not exist."); Console.WriteLine("Specified file does not exist.");
return; return;
} case 2:
FileStream rsrcStream = new FileStream(args[3], FileMode.Open, FileAccess.Read);
FileStream outStream;
ResourceFork rsrc = new ResourceFork(rsrcStream);
foreach(uint type in rsrc.GetTypes())
{ {
byte[] typeBytes = BitConverter.GetBytes(type); var rsrcStream = new FileStream(args[1], FileMode.Open, FileAccess.Read);
typeBytes = typeBytes.Reverse().ToArray();
Directory.CreateDirectory(Path.Combine(args[2], Encoding.ASCII.GetString(typeBytes))); var rsrc = new ResourceFork(rsrcStream);
Resource rez = rsrc.GetResource(type); foreach(uint type in rsrc.GetTypes())
foreach(short id in rez.GetIds())
{ {
outStream = byte[] typeBytes = BitConverter.GetBytes(type);
new typeBytes = typeBytes.Reverse().ToArray();
FileStream(Path.Combine(args[2], Encoding.ASCII.GetString(typeBytes), string.Format("{0}", id)), string typeName = Types.GetName(type);
FileMode.Create, FileAccess.ReadWrite);
byte[] rez_b = rez.GetResource(id); if(typeName != null)
outStream.Write(rez_b, 0, rez_b.Length); Console.WriteLine("\"{0}\" (0x{1:X8}) - {2}", Encoding.ASCII.GetString(typeBytes), type,
outStream.Close(); typeName);
else
Console.WriteLine("\"{0}\" (0x{1:X8})", Encoding.ASCII.GetString(typeBytes), type);
Resource rez = rsrc.GetResource(type);
Console.WriteLine("{0,6}{1,8}\t{2}", "ID", "Length", "Name");
Console.WriteLine("{0,6}{1,8}--{2}", "------", "--------", "----------------");
foreach(short id in rez.GetIds())
if(rez.GetName(id) != null)
Console.WriteLine("{0,6}{1,8}\t\"{2}\"", id, rez.GetLength(id), rez.GetName(id));
else
Console.WriteLine("{0,6}{1,8}", id, rez.GetLength(id));
Console.WriteLine();
} }
return;
}
case 4 when args[0] != "-x":
Usage();
return;
case 4 when args[1] != "-o":
Usage();
return;
case 4 when Directory.Exists(args[2]):
Console.WriteLine("Output directory exists, not proceeding");
return;
case 4 when !File.Exists(args[3]):
Console.WriteLine("Specified file does not exist.");
return;
case 4:
{
var rsrcStream = new FileStream(args[3], FileMode.Open, FileAccess.Read);
FileStream outStream;
var rsrc = new ResourceFork(rsrcStream);
foreach(uint type in rsrc.GetTypes())
{
byte[] typeBytes = BitConverter.GetBytes(type);
typeBytes = typeBytes.Reverse().ToArray();
Directory.CreateDirectory(Path.Combine(args[2], Encoding.ASCII.GetString(typeBytes)));
Resource rez = rsrc.GetResource(type);
foreach(short id in rez.GetIds())
{
outStream = new FileStream(Path.Combine(args[2], Encoding.ASCII.GetString(typeBytes), $"{id}"),
FileMode.Create, FileAccess.ReadWrite);
byte[] rez_b = rez.GetResource(id);
outStream.Write(rez_b, 0, rez_b.Length);
outStream.Close();
}
}
break;
} }
} }
} }

View File

@@ -29,7 +29,7 @@
<ConsolePause>false</ConsolePause> <ConsolePause>false</ConsolePause>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Test.cs" /> <Compile Include="Test.cs"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="Samples\SelfMountingImage.rsrc"> <None Include="Samples\SelfMountingImage.rsrc">
@@ -46,7 +46,7 @@
</None> </None>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Samples\" /> <Folder Include="Samples\"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Claunia.RsrcFork\Claunia.RsrcFork.csproj"> <ProjectReference Include="..\Claunia.RsrcFork\Claunia.RsrcFork.csproj">
@@ -60,15 +60,15 @@
</EmbeddedResource> </EmbeddedResource>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0"/>
<PackageReference Include="NUnit" Version="3.13.2" /> <PackageReference Include="NUnit" Version="3.13.2"/>
</ItemGroup> </ItemGroup>
<ProjectExtensions> <ProjectExtensions>
<MonoDevelop> <MonoDevelop>
<Properties> <Properties>
<Policies> <Policies>
<TextStylePolicy FileWidth="120" inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/x-csharp" /> <TextStylePolicy FileWidth="120" inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/x-csharp"/>
<CSharpFormattingPolicy SpacingAfterMethodDeclarationName="False" SpaceAfterMethodCallName="False" SpaceAfterControlFlowStatementKeyword="False" SpaceBeforeOpenSquareBracket="False" inheritsSet="Mono" inheritsScope="text/x-csharp" scope="text/x-csharp" /> <CSharpFormattingPolicy SpacingAfterMethodDeclarationName="False" SpaceAfterMethodCallName="False" SpaceAfterControlFlowStatementKeyword="False" SpaceBeforeOpenSquareBracket="False" inheritsSet="Mono" inheritsScope="text/x-csharp" scope="text/x-csharp"/>
</Policies> </Policies>
</Properties> </Properties>
</MonoDevelop> </MonoDevelop>

View File

@@ -35,17 +35,20 @@ public class Test
{ {
readonly byte[] DC42_Vers = readonly byte[] DC42_Vers =
{ {
0x06, 0x40, 0x80, 0x00, 0x00, 0x00, 0x09, 0x44, 0x69, 0x73, 0x6B, 0x20, 0x43, 0x6F, 0x70, 0x79, 0x1C, 0x06, 0x40, 0x80, 0x00, 0x00, 0x00, 0x09, 0x44, 0x69, 0x73, 0x6B, 0x20, 0x43, 0x6F, 0x70, 0x79, 0x1C, 0x34,
0x34, 0x2E, 0x32, 0x2C, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x63, 0x68, 0x65, 0x63, 0x6B, 0x73, 0x75, 0x2E, 0x32, 0x2C, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x63, 0x68, 0x65, 0x63, 0x6B, 0x73, 0x75, 0x6D, 0x3D,
0x6D, 0x3D, 0x24, 0x41, 0x35, 0x31, 0x34, 0x37, 0x46, 0x37, 0x45 0x24, 0x41, 0x35, 0x31, 0x34, 0x37, 0x46, 0x37, 0x45
};
readonly byte[] DC42_Str =
{
0x09, 0x44, 0x69, 0x73, 0x6B, 0x20, 0x43, 0x6F, 0x70, 0x79
}; };
readonly byte[] DC42_Str = {0x09, 0x44, 0x69, 0x73, 0x6B, 0x20, 0x43, 0x6F, 0x70, 0x79};
[Test] [Test]
public void TestDC42() public void TestDC42()
{ {
FileStream dc42Stream = new FileStream("Samples/DiskCopy42.rsrc", FileMode.Open, FileAccess.Read); var dc42Stream = new FileStream("Samples/DiskCopy42.rsrc", FileMode.Open, FileAccess.Read);
ResourceFork rsrc = new ResourceFork(dc42Stream); var rsrc = new ResourceFork(dc42Stream);
uint[] types = rsrc.GetTypes(); uint[] types = rsrc.GetTypes();
Assert.AreEqual(0x53545220, types[0]); Assert.AreEqual(0x53545220, types[0]);
@@ -56,7 +59,7 @@ public class Test
short[] str_Ids = str_.GetIds(); short[] str_Ids = str_.GetIds();
Assert.AreEqual(-16396, str_Ids[0]); Assert.AreEqual(-16396, str_Ids[0]);
Assert.AreEqual(10, str_.GetLength(-16396)); Assert.AreEqual(10, str_.GetLength(-16396));
byte[] str1 = str_.GetResource(-16396); byte[] str1 = str_.GetResource(-16396);
Assert.AreEqual(DC42_Str, str1); Assert.AreEqual(DC42_Str, str1);
@@ -67,7 +70,7 @@ public class Test
Resource vers = rsrc.GetResource(0x76657273); Resource vers = rsrc.GetResource(0x76657273);
Assert.IsNotNull(vers); Assert.IsNotNull(vers);
short[] versIds = vers.GetIds(); short[] versIds = vers.GetIds();
Assert.AreEqual(1, versIds[0]); Assert.AreEqual(1, versIds[0]);
Assert.AreEqual(45, vers.GetLength(1)); Assert.AreEqual(45, vers.GetLength(1));
byte[] vers1 = vers.GetResource(1); byte[] vers1 = vers.GetResource(1);
@@ -76,21 +79,21 @@ public class Test
string versStr = vers.GetName(1); string versStr = vers.GetName(1);
Assert.IsNull(versStr); Assert.IsNull(versStr);
Version versDec = new Version(vers1); var versDec = new Version(vers1);
Assert.AreEqual(6, versDec.MajorVersion); Assert.AreEqual(6, versDec.MajorVersion);
Assert.AreEqual(40, versDec.MinorVersion); Assert.AreEqual(40, versDec.MinorVersion);
Assert.AreEqual(Version.DevelopmentStage.Final, versDec.DevStage); Assert.AreEqual(Version.DevelopmentStage.Final, versDec.DevStage);
Assert.AreEqual(0, versDec.PreReleaseVersion); Assert.AreEqual(0, versDec.PreReleaseVersion);
Assert.AreEqual(0, versDec.RegionCode); Assert.AreEqual(0, versDec.RegionCode);
Assert.AreEqual("Disk Copy", versDec.VersionString); Assert.AreEqual("Disk Copy", versDec.VersionString);
Assert.AreEqual("4.2, data checksum=$A5147F7E", versDec.VersionMessage); Assert.AreEqual("4.2, data checksum=$A5147F7E", versDec.VersionMessage);
} }
[Test] [Test]
public void TestDC6() public void TestDC6()
{ {
FileStream dc6Stream = new FileStream("Samples/DiskCopy6.rsrc", FileMode.Open, FileAccess.Read); var dc6Stream = new FileStream("Samples/DiskCopy6.rsrc", FileMode.Open, FileAccess.Read);
ResourceFork rsrc = new ResourceFork(dc6Stream); var rsrc = new ResourceFork(dc6Stream);
uint[] types = rsrc.GetTypes(); uint[] types = rsrc.GetTypes();
Assert.AreEqual(0x53545220, types[0]); Assert.AreEqual(0x53545220, types[0]);
@@ -103,7 +106,7 @@ public class Test
short[] str_Ids = str_.GetIds(); short[] str_Ids = str_.GetIds();
Assert.AreEqual(-16396, str_Ids[0]); Assert.AreEqual(-16396, str_Ids[0]);
Assert.AreEqual(10, str_.GetLength(-16396)); Assert.AreEqual(10, str_.GetLength(-16396));
byte[] str1 = str_.GetResource(-16396); byte[] str1 = str_.GetResource(-16396);
Assert.AreEqual(DC42_Str, str1); Assert.AreEqual(DC42_Str, str1);
@@ -114,7 +117,7 @@ public class Test
Resource vers = rsrc.GetResource(0x76657273); Resource vers = rsrc.GetResource(0x76657273);
Assert.IsNotNull(vers); Assert.IsNotNull(vers);
short[] versIds = vers.GetIds(); short[] versIds = vers.GetIds();
Assert.AreEqual(1, versIds[0]); Assert.AreEqual(1, versIds[0]);
Assert.AreEqual(66, vers.GetLength(1)); Assert.AreEqual(66, vers.GetLength(1));
string versStr = vers.GetName(1); string versStr = vers.GetName(1);
@@ -136,25 +139,25 @@ public class Test
string bceSStr = bceS.GetName(128); string bceSStr = bceS.GetName(128);
Assert.IsNull(bceSStr); Assert.IsNull(bceSStr);
byte[] vers1 = vers.GetResource(1); byte[] vers1 = vers.GetResource(1);
Version versDec = new Version(vers1); var versDec = new Version(vers1);
Assert.AreEqual(6, versDec.MajorVersion); Assert.AreEqual(6, versDec.MajorVersion);
Assert.AreEqual(40, versDec.MinorVersion); Assert.AreEqual(40, versDec.MinorVersion);
Assert.AreEqual(Version.DevelopmentStage.Final, versDec.DevStage); Assert.AreEqual(Version.DevelopmentStage.Final, versDec.DevStage);
Assert.AreEqual(0, versDec.PreReleaseVersion); Assert.AreEqual(0, versDec.PreReleaseVersion);
Assert.AreEqual(0, versDec.RegionCode); Assert.AreEqual(0, versDec.RegionCode);
Assert.AreEqual("6.4 Disk Copy", versDec.VersionString); Assert.AreEqual("6.4 Disk Copy", versDec.VersionString);
Assert.AreEqual("Mac? OS HFS 1680K disk image\rCRC28: $07213FB7", versDec.VersionMessage); Assert.AreEqual("Mac? OS HFS 1680K disk image\rCRC28: $07213FB7", versDec.VersionMessage);
} }
[Test] [Test]
public void TestSMI() public void TestSMI()
{ {
FileStream smiStream = new FileStream("Samples/SelfMountingImage.rsrc", FileMode.Open, FileAccess.Read); var smiStream = new FileStream("Samples/SelfMountingImage.rsrc", FileMode.Open, FileAccess.Read);
ResourceFork rsrc = new ResourceFork(smiStream); var rsrc = new ResourceFork(smiStream);
uint[] types = rsrc.GetTypes(); uint[] types = rsrc.GetTypes();
Assert.AreEqual(29, types.Length); Assert.AreEqual(29, types.Length);
Assert.AreEqual(0x424E444C, types[0]); Assert.AreEqual(0x424E444C, types[0]);
Assert.AreEqual(0x434F4445, types[1]); Assert.AreEqual(0x434F4445, types[1]);
Assert.AreEqual(0x44415441, types[2]); Assert.AreEqual(0x44415441, types[2]);
@@ -170,8 +173,8 @@ public class Test
Resource code = rsrc.GetResource(0x434F4445); Resource code = rsrc.GetResource(0x434F4445);
Assert.IsNotNull(code); Assert.IsNotNull(code);
short[] codeIds = code.GetIds(); short[] codeIds = code.GetIds();
Assert.AreEqual(0, codeIds[0]); Assert.AreEqual(0, codeIds[0]);
Assert.AreEqual(1, codeIds[1]); Assert.AreEqual(1, codeIds[1]);
Assert.AreEqual(35130, code.GetLength(1)); Assert.AreEqual(35130, code.GetLength(1));
string codeStr = code.GetName(1); string codeStr = code.GetName(1);
Assert.AreEqual("First Segment", codeStr); //"First Segment" Assert.AreEqual("First Segment", codeStr); //"First Segment"
@@ -180,38 +183,38 @@ public class Test
Assert.IsNotNull(bndl); Assert.IsNotNull(bndl);
short[] bndlIds = bndl.GetIds(); short[] bndlIds = bndl.GetIds();
Assert.AreEqual(128, bndlIds[0]); Assert.AreEqual(128, bndlIds[0]);
Assert.AreEqual(28, bndl.GetLength(128)); Assert.AreEqual(28, bndl.GetLength(128));
string bndlStr = bndl.GetName(128); string bndlStr = bndl.GetName(128);
Assert.IsNull(bndlStr); Assert.IsNull(bndlStr);
Resource vers = rsrc.GetResource(0x76657273); Resource vers = rsrc.GetResource(0x76657273);
Assert.IsNotNull(vers); Assert.IsNotNull(vers);
byte[] vers1 = vers.GetResource(1); byte[] vers1 = vers.GetResource(1);
Version versDec = new Version(vers1); var versDec = new Version(vers1);
Assert.AreEqual(1, versDec.MajorVersion); Assert.AreEqual(1, versDec.MajorVersion);
Assert.AreEqual(10, versDec.MinorVersion); Assert.AreEqual(10, versDec.MinorVersion);
Assert.AreEqual(Version.DevelopmentStage.Beta, versDec.DevStage); Assert.AreEqual(Version.DevelopmentStage.Beta, versDec.DevStage);
Assert.AreEqual(6, versDec.PreReleaseVersion); Assert.AreEqual(6, versDec.PreReleaseVersion);
Assert.AreEqual(0, versDec.RegionCode); Assert.AreEqual(0, versDec.RegionCode);
Assert.AreEqual("1.1b6", versDec.VersionString); Assert.AreEqual("1.1b6", versDec.VersionString);
Assert.AreEqual("1.1b6, Copyright 1997-2001 Apple Computer, Inc.", versDec.VersionMessage); Assert.AreEqual("1.1b6, Copyright 1997-2001 Apple Computer, Inc.", versDec.VersionMessage);
} }
[Test] [Test]
public void TestUDIF() public void TestUDIF()
{ {
FileStream udifStream = new FileStream("Samples/UDIF.rsrc", FileMode.Open, FileAccess.Read); var udifStream = new FileStream("Samples/UDIF.rsrc", FileMode.Open, FileAccess.Read);
ResourceFork rsrc = new ResourceFork(udifStream); var rsrc = new ResourceFork(udifStream);
uint[] types = rsrc.GetTypes(); uint[] types = rsrc.GetTypes();
Assert.AreEqual(2, types.Length); Assert.AreEqual(2, types.Length);
Assert.AreEqual(0x626C6B78, types[0]); Assert.AreEqual(0x626C6B78, types[0]);
Assert.AreEqual(0x706C7374, types[1]); Assert.AreEqual(0x706C7374, types[1]);
Resource blkx = rsrc.GetResource(0x626C6B78); Resource blkx = rsrc.GetResource(0x626C6B78);
Assert.IsNotNull(blkx); Assert.IsNotNull(blkx);
short[] blkxIds = blkx.GetIds(); short[] blkxIds = blkx.GetIds();
Assert.AreEqual(0, blkxIds[0]); Assert.AreEqual(0, blkxIds[0]);
Assert.AreEqual(524, blkx.GetLength(0)); Assert.AreEqual(524, blkx.GetLength(0));
string blkxStr = blkx.GetName(0); string blkxStr = blkx.GetName(0);
Assert.AreEqual("Whole Device (Apple_XXX : 0)", blkxStr); //"First Segment" Assert.AreEqual("Whole Device (Apple_XXX : 0)", blkxStr); //"First Segment"
@@ -219,7 +222,7 @@ public class Test
Resource plst = rsrc.GetResource(0x706C7374); Resource plst = rsrc.GetResource(0x706C7374);
Assert.IsNotNull(plst); Assert.IsNotNull(plst);
short[] plstIds = plst.GetIds(); short[] plstIds = plst.GetIds();
Assert.AreEqual(0, plstIds[0]); Assert.AreEqual(0, plstIds[0]);
Assert.AreEqual(1544, plst.GetLength(0)); Assert.AreEqual(1544, plst.GetLength(0));
string plstStr = plst.GetName(0); string plstStr = plst.GetName(0);
Assert.IsNull(plstStr); Assert.IsNull(plstStr);

View File

@@ -60,6 +60,6 @@
</EmbeddedResource> </EmbeddedResource>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Resources\" /> <Folder Include="Resources\"/>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -29,37 +29,27 @@ using System.Text;
namespace Claunia.RsrcFork; namespace Claunia.RsrcFork;
/// <summary> /// <summary>Contains convertes between .NET and Pascal strings. Only ASCII supported right now.</summary>
/// Contains convertes between .NET and Pascal strings. Only ASCII supported right now.
/// </summary>
public static class PascalString public static class PascalString
{ {
/// <summary> /// <summary>Converts an ASCII Pascal string to a .NET string.</summary>
/// Converts an ASCII Pascal string to a .NET string.
/// </summary>
/// <returns>The .NET string.</returns> /// <returns>The .NET string.</returns>
/// <param name="PStr">The ASCII Pascal string.</param> /// <param name="PStr">The ASCII Pascal string.</param>
public static string GetString(byte[] PStr) public static string GetString(byte[] PStr) =>
{ PStr == null || PStr[0] >= PStr.Length ? null : Encoding.ASCII.GetString(PStr, 1, PStr[0]);
if(PStr == null || PStr[0] >= PStr.Length) return null;
return Encoding.ASCII.GetString(PStr, 1, PStr[0]); /// <summary>Converts a .NET string to an ASCII Pascal string.</summary>
}
/// <summary>
/// Converts a .NET string to an ASCII Pascal string.
/// </summary>
/// <returns>The ASCII Pascal string.</returns> /// <returns>The ASCII Pascal string.</returns>
/// <param name="str">The .NET string.</param> /// <param name="str">The .NET string.</param>
public static byte[] GetBytes(string str) public static byte[] GetBytes(string str)
{ {
if(str == null) return new byte[1]; if(str == null)
return new byte[1];
byte[] str_b = Encoding.ASCII.GetBytes(str); byte[] str_b = Encoding.ASCII.GetBytes(str);
byte[] PStr; byte[] PStr;
if(str_b.Length >= 256) PStr = new byte[256]; PStr = str_b.Length >= 256 ? new byte[256] : new byte[str_b.Length + 1];
else PStr = new byte[str_b.Length + 1];
Array.Copy(str_b, 0, PStr, 1, PStr.Length - 1); Array.Copy(str_b, 0, PStr, 1, PStr.Length - 1);
PStr[0] = (byte)(PStr.Length - 1); PStr[0] = (byte)(PStr.Length - 1);

View File

@@ -32,149 +32,127 @@ using System.Text;
namespace Claunia.RsrcFork; namespace Claunia.RsrcFork;
/// <summary> /// <summary>This class represents a resource type.</summary>
/// This class represents a resource type.
/// </summary>
public class Resource public class Resource
{ {
readonly List<short> ids; readonly List<short> _ids;
readonly Dictionary<short, byte[]> resourceCache; readonly Dictionary<short, byte[]> _resourceCache;
readonly Dictionary<short, string> resourceNames; readonly Dictionary<short, string> _resourceNames;
readonly Dictionary<short, ResourceData> resources; readonly Dictionary<short, ResourceData> _resources;
readonly Stream rsrcStream; readonly Stream _rsrcStream;
/// <summary> /// <summary>Initializates the specified resource type.</summary>
/// Initializates the specified resource type.
/// </summary>
/// <param name="stream">Stream where the resources of this reside.</param> /// <param name="stream">Stream where the resources of this reside.</param>
/// <param name="resources">How many resource of this type are.</param> /// <param name="resources">How many resource of this type are.</param>
/// <param name="referenceListOff">Offset from start of stream to reference list for this type.</param> /// <param name="referenceListOff">Offset from start of stream to reference list for this type.</param>
/// <param name="resourceNameOffset">Offset from start of stream to resource name list.</param> /// <param name="resourceNameOffset">Offset from start of stream to resource name list.</param>
/// <param name="resourceDataOffset">Offset from start of stream to resource data.</param> /// <param name="resourceDataOffset">Offset from start of stream to resource data.</param>
/// <param name="OSType">Resource type.</param> /// <param name="OSType">Resource type.</param>
internal Resource(Stream stream, ushort resources, long referenceListOff, long resourceNameOffset, internal Resource(Stream stream, ushort resources, long referenceListOff, long resourceNameOffset,
long resourceDataOffset, uint OSType) long resourceDataOffset, uint OSType)
{ {
rsrcStream = stream; _rsrcStream = stream;
Dictionary<short, ResourceTypeReferenceListItem> referenceLists = Dictionary<short, ResourceTypeReferenceListItem> referenceLists = new();
new Dictionary<short, ResourceTypeReferenceListItem>(); _resourceNames = new Dictionary<short, string>();
resourceNames = new Dictionary<short, string>(); _resources = new Dictionary<short, ResourceData>();
this.resources = new Dictionary<short, ResourceData>(); _ids = new List<short>();
ids = new List<short>();
byte[] tmp; byte[] tmp;
rsrcStream.Seek(referenceListOff + 2, SeekOrigin.Begin); _rsrcStream.Seek(referenceListOff + 2, SeekOrigin.Begin);
for(int i = 0; i < resources; i++) for(int i = 0; i < resources; i++)
{ {
ResourceTypeReferenceListItem item = new ResourceTypeReferenceListItem(); ResourceTypeReferenceListItem item = new();
tmp = new byte[2]; tmp = new byte[2];
rsrcStream.Read(tmp, 0, 2); _rsrcStream.Read(tmp, 0, 2);
item.id = BitConverter.ToInt16(tmp.Reverse().ToArray(), 0); item.Id = BitConverter.ToInt16(tmp.Reverse().ToArray(), 0);
rsrcStream.Read(tmp, 0, 2); _rsrcStream.Read(tmp, 0, 2);
item.nameOff = BitConverter.ToInt16(tmp.Reverse().ToArray(), 0); item.NameOff = BitConverter.ToInt16(tmp.Reverse().ToArray(), 0);
tmp = new byte[4]; tmp = new byte[4];
rsrcStream.Read(tmp, 0, 4); _rsrcStream.Read(tmp, 0, 4);
item.attributes = tmp[0]; item.Attributes = tmp[0];
tmp[0] = 0; tmp[0] = 0;
item.dataOff = BitConverter.ToInt32(tmp.Reverse().ToArray(), 0); item.DataOff = BitConverter.ToInt32(tmp.Reverse().ToArray(), 0);
rsrcStream.Read(tmp, 0, 4); _rsrcStream.Read(tmp, 0, 4);
item.handle = BitConverter.ToUInt32(tmp.Reverse().ToArray(), 0); item.Handle = BitConverter.ToUInt32(tmp.Reverse().ToArray(), 0);
referenceLists.Add(item.id, item); referenceLists.Add(item.Id, item);
ids.Add(item.id); _ids.Add(item.Id);
} }
foreach(ResourceTypeReferenceListItem item in referenceLists.Values) foreach(ResourceTypeReferenceListItem item in referenceLists.Values)
{ {
string name; string name;
ResourceData data = new ResourceData(); ResourceData data = new();
if(item.nameOff == -1) name = null; if(item.NameOff == -1)
name = null;
else else
{ {
rsrcStream.Seek(resourceNameOffset + item.nameOff, SeekOrigin.Begin); _rsrcStream.Seek(resourceNameOffset + item.NameOff, SeekOrigin.Begin);
byte nameLen = (byte)rsrcStream.ReadByte(); byte nameLen = (byte)_rsrcStream.ReadByte();
byte[] nameBytes = new byte[nameLen]; byte[] nameBytes = new byte[nameLen];
rsrcStream.Read(nameBytes, 0, nameLen); _rsrcStream.Read(nameBytes, 0, nameLen);
// TODO: Use MacRoman // TODO: Use MacRoman
name = Encoding.ASCII.GetString(nameBytes); name = Encoding.ASCII.GetString(nameBytes);
} }
rsrcStream.Seek(resourceDataOffset + item.dataOff, SeekOrigin.Begin); _rsrcStream.Seek(resourceDataOffset + item.DataOff, SeekOrigin.Begin);
tmp = new byte[4]; tmp = new byte[4];
rsrcStream.Read(tmp, 0, 4); _rsrcStream.Read(tmp, 0, 4);
data.offset = rsrcStream.Position; data.Offset = _rsrcStream.Position;
data.length = BitConverter.ToUInt32(tmp.Reverse().ToArray(), 0); data.Length = BitConverter.ToUInt32(tmp.Reverse().ToArray(), 0);
resourceNames.Add(item.id, name); _resourceNames.Add(item.Id, name);
this.resources.Add(item.id, data); _resources.Add(item.Id, data);
} }
resourceCache = new Dictionary<short, byte[]>(); _resourceCache = new Dictionary<short, byte[]>();
} }
/// <summary> /// <summary>Gets the name of the specified resource id, or null if there is no name.</summary>
/// Gets the name of the specified resource id, or null if there is no name.
/// </summary>
/// <returns>The name.</returns> /// <returns>The name.</returns>
/// <param name="id">Identifier.</param> /// <param name="id">Identifier.</param>
public string GetName(short id) public string GetName(short id) => _resourceNames.TryGetValue(id, out string name) ? name : null;
{
string name;
return resourceNames.TryGetValue(id, out name) ? name : null;
}
/// <summary> /// <summary>Gets the resource contents.</summary>
/// Gets the resource contents.
/// </summary>
/// <returns>The resource.</returns> /// <returns>The resource.</returns>
/// <param name="id">Identifier.</param> /// <param name="id">Identifier.</param>
public byte[] GetResource(short id) public byte[] GetResource(short id)
{ {
byte[] resource; if(_resourceCache.TryGetValue(id, out byte[] resource))
return resource;
if(resourceCache.TryGetValue(id, out resource)) return resource; if(!_resources.TryGetValue(id, out ResourceData data))
return null;
ResourceData data; resource = new byte[data.Length];
_rsrcStream.Seek(data.Offset, SeekOrigin.Begin);
_rsrcStream.Read(resource, 0, resource.Length);
if(!resources.TryGetValue(id, out data)) return null; _resourceCache.Add(id, resource);
resource = new byte[data.length];
rsrcStream.Seek(data.offset, SeekOrigin.Begin);
rsrcStream.Read(resource, 0, resource.Length);
resourceCache.Add(id, resource);
return resource; return resource;
} }
/// <summary> /// <summary>Gets the length of the resource specified by ID.</summary>
/// Gets the length of the resource specified by ID.
/// </summary>
/// <returns>The length.</returns> /// <returns>The length.</returns>
/// <param name="id">Resource identifier.</param> /// <param name="id">Resource identifier.</param>
public long GetLength(short id) public long GetLength(short id) => !_resources.TryGetValue(id, out ResourceData data) ? 0 : data.Length;
{
ResourceData data;
return !resources.TryGetValue(id, out data) ? 0 : data.length;
}
/// <summary> /// <summary>Gets the IDs of all the resources contained by this instance.</summary>
/// Gets the IDs of all the resources contained by this instance.
/// </summary>
/// <returns>The identifiers.</returns> /// <returns>The identifiers.</returns>
public short[] GetIds() => ids.ToArray(); public short[] GetIds() => _ids.ToArray();
/// <summary> /// <summary>Checks if the resource specified by ID is contained by this instance.</summary>
/// Checks if the resource specified by ID is contained by this instance.
/// </summary>
/// <returns><c>true</c>, if the resource is contained in this instance, <c>false</c> otherwise.</returns> /// <returns><c>true</c>, if the resource is contained in this instance, <c>false</c> otherwise.</returns>
/// <param name="id">Resource identifier.</param> /// <param name="id">Resource identifier.</param>
public bool ContainsId(short id) => ids.Contains(id); public bool ContainsId(short id) => _ids.Contains(id);
struct ResourceData struct ResourceData
{ {
public long offset; public long Offset;
public long length; public long Length;
} }
} }

View File

@@ -30,161 +30,146 @@ using System.Linq;
namespace Claunia.RsrcFork; namespace Claunia.RsrcFork;
/// <summary> /// <summary>This class represents a resource fork.</summary>
/// This class represents a resource fork.
/// </summary>
public class ResourceFork public class ResourceFork
{ {
ResourceHeader header; readonly Stream _rsrcStream;
ResourceMap map; ResourceHeader _header;
List<uint> osTypes; ResourceMap _map;
Dictionary<uint, Resource> resourceCache; List<uint> _osTypes;
Dictionary<uint, ResourceTypeListItem> resourceTypeList; Dictionary<uint, Resource> _resourceCache;
readonly Stream rsrcStream; Dictionary<uint, ResourceTypeListItem> _resourceTypeList;
/// <summary> /// <summary>Initializates a resource fork using a byte array as backend.</summary>
/// Initializates a resource fork using a byte array as backend.
/// </summary>
/// <param name="buffer">Buffer.</param> /// <param name="buffer">Buffer.</param>
public ResourceFork(byte[] buffer) public ResourceFork(byte[] buffer)
{ {
rsrcStream = new MemoryStream(buffer, false); _rsrcStream = new MemoryStream(buffer, false);
Init(); Init();
} }
/// <summary> /// <summary>Initializates a resource fork using a stream as backed.</summary>
/// Initializates a resource fork using a stream as backed.
/// </summary>
/// <param name="stream">Stream.</param> /// <param name="stream">Stream.</param>
public ResourceFork(Stream stream) public ResourceFork(Stream stream)
{ {
rsrcStream = stream; _rsrcStream = stream;
Init(); Init();
} }
/// <summary> /// <summary>Cleans up this instances and closes the underlying stream.</summary>
/// Cleans up this instances and closes the underlying stream. ~ResourceFork() => _rsrcStream?.Dispose();
/// </summary>
~ResourceFork()
{
if(rsrcStream != null) rsrcStream.Dispose();
}
/// <summary> /// <summary>Initializes this instance.</summary>
/// Initializes this instance.
/// </summary>
void Init() void Init()
{ {
header = new ResourceHeader(); _header = new ResourceHeader();
byte[] tmp = new byte[4]; byte[] tmp = new byte[4];
rsrcStream.Seek(0, SeekOrigin.Begin); _rsrcStream.Seek(0, SeekOrigin.Begin);
rsrcStream.Read(tmp, 0, 4); _rsrcStream.Read(tmp, 0, 4);
header.resourceDataOff = BitConverter.ToInt32(tmp.Reverse().ToArray(), 0); _header.ResourceDataOff = BitConverter.ToInt32(tmp.Reverse().ToArray(), 0);
rsrcStream.Read(tmp, 0, 4); _rsrcStream.Read(tmp, 0, 4);
header.resourceMapOff = BitConverter.ToInt32(tmp.Reverse().ToArray(), 0); _header.ResourceMapOff = BitConverter.ToInt32(tmp.Reverse().ToArray(), 0);
rsrcStream.Read(tmp, 0, 4); _rsrcStream.Read(tmp, 0, 4);
header.resourceDataLen = BitConverter.ToInt32(tmp.Reverse().ToArray(), 0); _header.ResourceDataLen = BitConverter.ToInt32(tmp.Reverse().ToArray(), 0);
rsrcStream.Read(tmp, 0, 4); _rsrcStream.Read(tmp, 0, 4);
header.resourceMapLen = BitConverter.ToInt32(tmp.Reverse().ToArray(), 0); _header.ResourceMapLen = BitConverter.ToInt32(tmp.Reverse().ToArray(), 0);
if(header.resourceDataOff <= 0 || header.resourceMapOff <= 0 || header.resourceDataLen <= 0 || if(_header.ResourceDataOff <= 0 ||
header.resourceMapLen <= 0) throw new InvalidCastException("Not a resource fork"); _header.ResourceMapOff <= 0 ||
_header.ResourceDataLen <= 0 ||
if(header.resourceDataOff + header.resourceDataLen > rsrcStream.Length || _header.ResourceMapLen <= 0)
header.resourceMapOff + header.resourceMapLen > rsrcStream.Length)
throw new InvalidCastException("Not a resource fork"); throw new InvalidCastException("Not a resource fork");
map = new ResourceMap(); if(_header.ResourceDataOff + _header.ResourceDataLen > _rsrcStream.Length ||
map.header = new ResourceHeader(); _header.ResourceMapOff + _header.ResourceMapLen > _rsrcStream.Length)
rsrcStream.Seek(header.resourceMapOff, SeekOrigin.Begin); throw new InvalidCastException("Not a resource fork");
rsrcStream.Read(tmp, 0, 4);
map.header.resourceDataOff = BitConverter.ToInt32(tmp.Reverse().ToArray(), 0);
rsrcStream.Read(tmp, 0, 4);
map.header.resourceMapOff = BitConverter.ToInt32(tmp.Reverse().ToArray(), 0);
rsrcStream.Read(tmp, 0, 4);
map.header.resourceDataLen = BitConverter.ToInt32(tmp.Reverse().ToArray(), 0);
rsrcStream.Read(tmp, 0, 4);
map.header.resourceMapLen = BitConverter.ToInt32(tmp.Reverse().ToArray(), 0);
if(map.header.resourceDataOff != header.resourceDataOff || _map = new ResourceMap
map.header.resourceDataLen != header.resourceDataLen || {
map.header.resourceMapOff != header.resourceMapOff || Header = new ResourceHeader()
map.header.resourceMapLen != header.resourceMapLen) };
_rsrcStream.Seek(_header.ResourceMapOff, SeekOrigin.Begin);
_rsrcStream.Read(tmp, 0, 4);
_map.Header.ResourceDataOff = BitConverter.ToInt32(tmp.Reverse().ToArray(), 0);
_rsrcStream.Read(tmp, 0, 4);
_map.Header.ResourceMapOff = BitConverter.ToInt32(tmp.Reverse().ToArray(), 0);
_rsrcStream.Read(tmp, 0, 4);
_map.Header.ResourceDataLen = BitConverter.ToInt32(tmp.Reverse().ToArray(), 0);
_rsrcStream.Read(tmp, 0, 4);
_map.Header.ResourceMapLen = BitConverter.ToInt32(tmp.Reverse().ToArray(), 0);
if(_map.Header.ResourceDataOff != _header.ResourceDataOff ||
_map.Header.ResourceDataLen != _header.ResourceDataLen ||
_map.Header.ResourceMapOff != _header.ResourceMapOff ||
_map.Header.ResourceMapLen != _header.ResourceMapLen)
throw new InvalidCastException("Header copy is not same as header."); throw new InvalidCastException("Header copy is not same as header.");
rsrcStream.Read(tmp, 0, 4); _rsrcStream.Read(tmp, 0, 4);
map.handleToNextMap = BitConverter.ToUInt32(tmp.Reverse().ToArray(), 0); _map.HandleToNextMap = BitConverter.ToUInt32(tmp.Reverse().ToArray(), 0);
tmp = new byte[2]; tmp = new byte[2];
rsrcStream.Read(tmp, 0, 2); _rsrcStream.Read(tmp, 0, 2);
map.fileRefNo = BitConverter.ToUInt16(tmp.Reverse().ToArray(), 0); _map.FileRefNo = BitConverter.ToUInt16(tmp.Reverse().ToArray(), 0);
rsrcStream.Read(tmp, 0, 2); _rsrcStream.Read(tmp, 0, 2);
map.attributes = BitConverter.ToUInt16(tmp.Reverse().ToArray(), 0); _map.Attributes = BitConverter.ToUInt16(tmp.Reverse().ToArray(), 0);
rsrcStream.Read(tmp, 0, 2); _rsrcStream.Read(tmp, 0, 2);
map.typeListOff = BitConverter.ToInt16(tmp.Reverse().ToArray(), 0); _map.TypeListOff = BitConverter.ToInt16(tmp.Reverse().ToArray(), 0);
rsrcStream.Read(tmp, 0, 2); _rsrcStream.Read(tmp, 0, 2);
map.nameListOff = BitConverter.ToInt16(tmp.Reverse().ToArray(), 0); _map.NameListOff = BitConverter.ToInt16(tmp.Reverse().ToArray(), 0);
// Number of types is part of the resource type list not of the map // Number of types is part of the resource type list not of the map
rsrcStream.Seek(header.resourceMapOff + map.typeListOff, SeekOrigin.Begin); _rsrcStream.Seek(_header.ResourceMapOff + _map.TypeListOff, SeekOrigin.Begin);
rsrcStream.Read(tmp, 0, 2); _rsrcStream.Read(tmp, 0, 2);
map.numberOfTypes = BitConverter.ToUInt16(tmp.Reverse().ToArray(), 0); _map.NumberOfTypes = BitConverter.ToUInt16(tmp.Reverse().ToArray(), 0);
resourceTypeList = new Dictionary<uint, ResourceTypeListItem>(); _resourceTypeList = new Dictionary<uint, ResourceTypeListItem>();
osTypes = new List<uint>(); _osTypes = new List<uint>();
for(int i = 0; i <= map.numberOfTypes; i++) for(int i = 0; i <= _map.NumberOfTypes; i++)
{ {
ResourceTypeListItem typeList = new ResourceTypeListItem(); ResourceTypeListItem typeList = new();
tmp = new byte[4]; tmp = new byte[4];
rsrcStream.Read(tmp, 0, 4); _rsrcStream.Read(tmp, 0, 4);
typeList.type = BitConverter.ToUInt32(tmp.Reverse().ToArray(), 0); typeList.Type = BitConverter.ToUInt32(tmp.Reverse().ToArray(), 0);
tmp = new byte[2]; tmp = new byte[2];
rsrcStream.Read(tmp, 0, 2); _rsrcStream.Read(tmp, 0, 2);
typeList.resources = BitConverter.ToUInt16(tmp.Reverse().ToArray(), 0); typeList.Resources = BitConverter.ToUInt16(tmp.Reverse().ToArray(), 0);
rsrcStream.Read(tmp, 0, 2); _rsrcStream.Read(tmp, 0, 2);
typeList.referenceOff = BitConverter.ToInt16(tmp.Reverse().ToArray(), 0); typeList.ReferenceOff = BitConverter.ToInt16(tmp.Reverse().ToArray(), 0);
resourceTypeList.Add(typeList.type, typeList); _resourceTypeList.Add(typeList.Type, typeList);
osTypes.Add(typeList.type); _osTypes.Add(typeList.Type);
} }
resourceCache = new Dictionary<uint, Resource>(); _resourceCache = new Dictionary<uint, Resource>();
} }
/// <summary> /// <summary>Gets the resources with indicated type</summary>
/// Gets the resources with indicated type
/// </summary>
/// <returns>The resource.</returns> /// <returns>The resource.</returns>
/// <param name="OSType">OSType.</param> /// <param name="OSType">OSType.</param>
public Resource GetResource(uint OSType) public Resource GetResource(uint OSType)
{ {
Resource rsrc; if(_resourceCache.TryGetValue(OSType, out Resource rsrc))
return rsrc;
if(resourceCache.TryGetValue(OSType, out rsrc)) return rsrc; if(!_resourceTypeList.TryGetValue(OSType, out ResourceTypeListItem typeList))
return null;
ResourceTypeListItem typeList; rsrc = new Resource(_rsrcStream, (ushort)(typeList.Resources + 1),
if(!resourceTypeList.TryGetValue(OSType, out typeList)) return null; _header.ResourceMapOff + _map.TypeListOff + typeList.ReferenceOff - 2,
_header.ResourceMapOff + _map.NameListOff, _header.ResourceDataOff, OSType);
rsrc = new Resource(rsrcStream, (ushort)(typeList.resources + 1), _resourceCache.Add(OSType, rsrc);
header.resourceMapOff + map.typeListOff + typeList.referenceOff - 2,
header.resourceMapOff + map.nameListOff,
header.resourceDataOff, OSType);
resourceCache.Add(OSType, rsrc);
return rsrc; return rsrc;
} }
/// <summary> /// <summary>Gets all OSTypes stored in this resource fork</summary>
/// Gets all OSTypes stored in this resource fork
/// </summary>
/// <returns>The types.</returns> /// <returns>The types.</returns>
public uint[] GetTypes() => osTypes.ToArray(); public uint[] GetTypes() => _osTypes.ToArray();
/// <summary> /// <summary>Returns true if the specified OSType is present in this resource fork.</summary>
/// Returns true if the specified OSType is present in this resource fork.
/// </summary>
/// <param name="OSType">OSType.</param> /// <param name="OSType">OSType.</param>
public bool ContainsKey(uint OSType) => resourceTypeList.ContainsKey(OSType); public bool ContainsKey(uint OSType) => _resourceTypeList.ContainsKey(OSType);
} }

View File

@@ -30,43 +30,27 @@ using Claunia.RsrcFork;
namespace Resources; namespace Resources;
/// <summary> /// <summary>This class handles the "VERS" resource fork</summary>
/// This class handles the "VERS" resource fork
/// </summary>
public class Version public class Version
{ {
/// <summary> /// <summary>Known development stages</summary>
/// Known development stages
/// </summary>
public enum DevelopmentStage : byte public enum DevelopmentStage : byte
{ {
/// <summary> /// <summary>Pre-alpha.</summary>
/// Pre-alpha.
/// </summary>
PreAlpha = 0x20, PreAlpha = 0x20,
/// <summary> /// <summary>Alpha.</summary>
/// Alpha.
/// </summary>
Alpha = 0x40, Alpha = 0x40,
/// <summary> /// <summary>Beta.</summary>
/// Beta.
/// </summary>
Beta = 0x60, Beta = 0x60,
/// <summary> /// <summary>Final release.</summary>
/// Final release.
/// </summary>
Final = 0x80 Final = 0x80
} }
/// <summary> /// <summary>Initializes a new instance of the <see cref="T:Resources.Version" /> class.</summary>
/// Initializes a new instance of the <see cref="T:Resources.Version" /> class.
/// </summary>
/// <param name="resource">Byte array containing the "VERS" resource.</param> /// <param name="resource">Byte array containing the "VERS" resource.</param>
public Version(byte[] resource) public Version(byte[] resource)
{ {
byte[] tmpShort, tmpStr, tmpMsg; byte[] tmpShort = new byte[2];
tmpShort = new byte[2];
MajorVersion = BCDToNumber(resource[0]); MajorVersion = BCDToNumber(resource[0]);
MinorVersion = BCDToNumber(resource[1]); MinorVersion = BCDToNumber(resource[1]);
@@ -74,81 +58,62 @@ public class Version
PreReleaseVersion = BCDToNumber(resource[3]); PreReleaseVersion = BCDToNumber(resource[3]);
Array.Copy(resource, 4, tmpShort, 0, 2); Array.Copy(resource, 4, tmpShort, 0, 2);
RegionCode = BitConverter.ToUInt16(tmpShort.Reverse().ToArray(), 0); RegionCode = BitConverter.ToUInt16(tmpShort.Reverse().ToArray(), 0);
tmpStr = new byte[resource[6] + 1]; byte[] tmpStr = new byte[resource[6] + 1];
Array.Copy(resource, 6, tmpStr, 0, tmpStr.Length); Array.Copy(resource, 6, tmpStr, 0, tmpStr.Length);
VersionString = PascalString.GetString(tmpStr); VersionString = PascalString.GetString(tmpStr);
tmpMsg = new byte[resource[6 + tmpStr.Length] + 1]; byte[] tmpMsg = new byte[resource[6 + tmpStr.Length] + 1];
Array.Copy(resource, 6 + tmpStr.Length, tmpMsg, 0, tmpMsg.Length); Array.Copy(resource, 6 + tmpStr.Length, tmpMsg, 0, tmpMsg.Length);
VersionMessage = PascalString.GetString(tmpMsg); VersionMessage = PascalString.GetString(tmpMsg);
} }
/// <summary> /// <summary>Gets the OSTYPE of this resource.</summary>
/// Gets the OSTYPE of this resource.
/// </summary>
/// <value>The OSTYPE.</value> /// <value>The OSTYPE.</value>
public static uint OSType { get; } = 0x76657273; public static uint OSType { get; } = 0x76657273;
/// <summary> /// <summary>Gets a byte array with the "VERS" resource contained by this instance.</summary>
/// Gets a byte array with the "VERS" resource contained by this instance.
/// </summary>
/// <returns>The "VERS" resource.</returns> /// <returns>The "VERS" resource.</returns>
public byte[] GetBytes() public byte[] GetBytes()
{ {
byte[] tmpShort, tmpStr, tmpMsg; byte[] tmpShort = BitConverter.GetBytes(RegionCode).Reverse().ToArray();
tmpShort = BitConverter.GetBytes(RegionCode).Reverse().ToArray(); byte[] tmpStr = PascalString.GetBytes(VersionString);
tmpStr = PascalString.GetBytes(VersionString); byte[] tmpMsg = PascalString.GetBytes(VersionMessage);
tmpMsg = PascalString.GetBytes(VersionMessage); byte[] vers = new byte[6 + tmpStr.Length + tmpMsg.Length];
byte[] vers = new byte[6 + tmpStr.Length + tmpMsg.Length];
vers[0] = NumberToBCD(MajorVersion); vers[0] = NumberToBCD(MajorVersion);
vers[1] = NumberToBCD(MinorVersion); vers[1] = NumberToBCD(MinorVersion);
vers[2] = (byte)DevStage; vers[2] = (byte)DevStage;
vers[3] = NumberToBCD(PreReleaseVersion); vers[3] = NumberToBCD(PreReleaseVersion);
Array.Copy(tmpShort, 0, vers, 4, 2); Array.Copy(tmpShort, 0, vers, 4, 2);
Array.Copy(tmpStr, 0, vers, 6, tmpStr.Length); Array.Copy(tmpStr, 0, vers, 6, tmpStr.Length);
Array.Copy(tmpMsg, 0, vers, 6 + tmpStr.Length, tmpMsg.Length); Array.Copy(tmpMsg, 0, vers, 6 + tmpStr.Length, tmpMsg.Length);
return vers; return vers;
} }
byte BCDToNumber(byte bcd) => Convert.ToByte(string.Format("{0:X2}", bcd), 10); byte BCDToNumber(byte bcd) => Convert.ToByte($"{bcd:X2}", 10);
byte NumberToBCD(byte number) byte NumberToBCD(byte number)
{ {
if(number >= 100) number = 99; if(number >= 100)
number = 99;
return Convert.ToByte(string.Format("{0:D2}", number), 16); return Convert.ToByte($"{number:D2}", 16);
} }
#region On-disk structure #region On-disk structure
/// <summary> /// <summary>Major version.</summary>
/// Major version.
/// </summary>
public byte MajorVersion; public byte MajorVersion;
/// <summary> /// <summary>Minor version.</summary>
/// Minor version.
/// </summary>
public byte MinorVersion; public byte MinorVersion;
/// <summary> /// <summary>Development stage.</summary>
/// Development stage.
/// </summary>
public DevelopmentStage DevStage; public DevelopmentStage DevStage;
/// <summary> /// <summary>Pre-release version.</summary>
/// Pre-release version.
/// </summary>
public byte PreReleaseVersion; public byte PreReleaseVersion;
/// <summary> /// <summary>Region code.</summary>
/// Region code.
/// </summary>
public ushort RegionCode; public ushort RegionCode;
/// <summary> /// <summary>Version string.</summary>
/// Version string.
/// </summary>
public string VersionString; public string VersionString;
/// <summary> /// <summary>Version message.</summary>
/// Version message.
/// </summary>
public string VersionMessage; public string VersionMessage;
#endregion #endregion
} }

View File

@@ -26,94 +26,56 @@
namespace Claunia.RsrcFork; namespace Claunia.RsrcFork;
struct ResourceHeader internal struct ResourceHeader
{ {
/// <summary> /// <summary>Offset from start of resource fork to resource data</summary>
/// Offset from start of resource fork to resource data public int ResourceDataOff;
/// </summary> /// <summary>Offset from start of resource fork to resource map</summary>
public int resourceDataOff; public int ResourceMapOff;
/// <summary> /// <summary>Length of resource data</summary>
/// Offset from start of resource fork to resource map public int ResourceDataLen;
/// </summary> /// <summary>Length of resource map</summary>
public int resourceMapOff; public int ResourceMapLen;
/// <summary>
/// Length of resource data
/// </summary>
public int resourceDataLen;
/// <summary>
/// Length of resource map
/// </summary>
public int resourceMapLen;
} }
struct ResourceMap internal struct ResourceMap
{ {
/// <summary> /// <summary>Copy of the resource fork header</summary>
/// Copy of the resource fork header public ResourceHeader Header;
/// </summary> /// <summary>Reserved for handle to next resource map</summary>
public ResourceHeader header; public uint HandleToNextMap;
/// <summary> /// <summary>Reserved for file reference number</summary>
/// Reserved for handle to next resource map public ushort FileRefNo;
/// </summary> /// <summary>Resource fork attributes</summary>
public uint handleToNextMap; public ushort Attributes;
/// <summary> /// <summary>Offset from start of resource map to resource type list</summary>
/// Reserved for file reference number public short TypeListOff;
/// </summary> /// <summary>Offset from start of resource map to resource name list</summary>
public ushort fileRefNo; public short NameListOff;
/// <summary> /// <summary>Number of types in the map minus 1</summary>
/// Resource fork attributes public ushort NumberOfTypes;
/// </summary>
public ushort attributes;
/// <summary>
/// Offset from start of resource map to resource type list
/// </summary>
public short typeListOff;
/// <summary>
/// Offset from start of resource map to resource name list
/// </summary>
public short nameListOff;
/// <summary>
/// Number of types in the map minus 1
/// </summary>
public ushort numberOfTypes;
} }
struct ResourceTypeListItem internal struct ResourceTypeListItem
{ {
/// <summary> /// <summary>Resource type</summary>
/// Resource type public uint Type;
/// </summary> /// <summary>Number of resources of this type minus 1</summary>
public uint type; public ushort Resources;
/// <summary> /// <summary>Offset from beginning of resource type list to reference list</summary>
/// Number of resources of this type minus 1 public short ReferenceOff;
/// </summary>
public ushort resources;
/// <summary>
/// Offset from beginning of resource type list to reference list
/// </summary>
public short referenceOff;
} }
struct ResourceTypeReferenceListItem internal struct ResourceTypeReferenceListItem
{ {
/// <summary> /// <summary>Resource ID</summary>
/// Resource ID public short Id;
/// </summary> /// <summary>Offset from beginning of resource name list to resource name. -1 if it does not have a name</summary>
public short id; public short NameOff;
/// <summary> /// <summary>Resource attributes</summary>
/// Offset from beginning of resource name list to resource name. -1 if it does not have a name public byte Attributes;
/// </summary> /// <summary>Offset from beginning of resource data to resource. First byte is <see cref="Attributes" />.</summary>
public short nameOff; public int DataOff;
/// <summary> /// <summary>Reserved for handle to resource</summary>
/// Resource attributes public uint Handle;
/// </summary>
public byte attributes;
/// <summary>
/// Offset from beginning of resource data to resource. First byte is <see cref="attributes" />.
/// </summary>
public int dataOff;
/// <summary>
/// Reserved for handle to resource
/// </summary>
public uint handle;
} }

View File

@@ -30,14 +30,10 @@ using System.Text;
namespace Claunia.RsrcFork; namespace Claunia.RsrcFork;
/// <summary> /// <summary>This class contains static methods for OSTYPE handling.</summary>
/// This class contains static methods for OSTYPE handling.
/// </summary>
public static class Types public static class Types
{ {
/// <summary> /// <summary>Gets a descriptive name of a resource from its OSTYPE.</summary>
/// Gets a descriptive name of a resource from its OSTYPE.
/// </summary>
/// <returns>The name corresponding to the specified OSTYPE.</returns> /// <returns>The name corresponding to the specified OSTYPE.</returns>
/// <param name="OSType">The OSTYPE.</param> /// <param name="OSType">The OSTYPE.</param>
public static string GetName(uint OSType) public static string GetName(uint OSType)
@@ -688,14 +684,13 @@ public static class Types
} }
} }
/// <summary> /// <summary>Gets a descriptive name of a resource from its OSTYPE.</summary>
/// Gets a descriptive name of a resource from its OSTYPE.
/// </summary>
/// <returns>The name corresponding to the specified OSTYPE.</returns> /// <returns>The name corresponding to the specified OSTYPE.</returns>
/// <param name="OSType">The OSTYPE.</param> /// <param name="OSType">The OSTYPE.</param>
public static string GetName(string OSType) public static string GetName(string OSType)
{ {
if(OSType.Length != 4) return null; if(OSType.Length != 4)
return null;
byte[] typB = Encoding.ASCII.GetBytes(OSType); byte[] typB = Encoding.ASCII.GetBytes(OSType);
uint type = BitConverter.ToUInt32(typB.Reverse().ToArray(), 0); uint type = BitConverter.ToUInt32(typB.Reverse().ToArray(), 0);