Browse Source

commit: import project

HOME 1 year ago
parent
commit
30b91009d9

BIN
Documents/CD-ROM_ISO9660.pdf


BIN
Documents/Ecma-119.pdf


+ 7 - 0
Iso9660/Constants.cs

@@ -0,0 +1,7 @@
+namespace IsoFilePatcher.Iso9660
+{
+    internal class Constants
+    {
+        public const int SectorSize = 2048;
+    }
+}

+ 59 - 0
Iso9660/ExtensionsMethods.cs

@@ -0,0 +1,59 @@
+using System;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace IsoFilePatcher.Iso9660
+{
+    internal static class ExtensionsMethods
+    {
+        public static string ReadString(this BinaryReader br, int len, Encoding encoding = null)
+        {
+            var buf = br.ReadBytes(len);
+            return (encoding ?? Encoding.ASCII).GetString(buf);
+        }
+
+        public static uint ReadUInt32LsbMsb(this BinaryReader br)
+        {
+            var a = br.ReadUInt32();
+            var b = br.ReadUInt32();
+            return BitConverter.IsLittleEndian ? a : b;
+        }
+
+        public static ushort ReadUInt16LsbMsb(this BinaryReader br)
+        {
+            var a = br.ReadUInt16();
+            var b = br.ReadUInt16();
+            return BitConverter.IsLittleEndian ? a : b;
+        }
+
+        public static DateTime ReadDecDateTime(this BinaryReader br)
+        {
+            var str = br.ReadString(16);
+            var tz = br.ReadByte();
+            if (str[0] == '\0' || str.All(p => p == '0')) return new DateTime();
+            var dt = DateTime.ParseExact(str, "yyyyMMddHHmmssff", CultureInfo.InvariantCulture);
+            return dt;
+        }
+
+        public static DateTime ReadFileRecordDate(this BinaryReader br)
+        {
+            var year = br.ReadByte();
+            var mon = br.ReadByte();
+            var day = br.ReadByte();
+            var hour = br.ReadByte();
+            var min = br.ReadByte();
+            var sec = br.ReadByte();
+            var tz = br.ReadByte();
+
+            var dt = new DateTime(year + 1900, mon, day, hour, min, sec);
+            return dt;
+        }
+
+        public static string ReadBytePrefixString(this BinaryReader br, Encoding encoding = null)
+        {
+            return (encoding ?? Encoding.ASCII).GetString(br.ReadBytes(br.ReadByte()));
+        }
+    }
+}

+ 120 - 0
Iso9660/PathEntry.cs

@@ -0,0 +1,120 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+
+namespace IsoFilePatcher.Iso9660
+{
+    [DebuggerDisplay("\\{ Name={Name} {ChildPathEntries} \\}")]
+    internal class PathEntry
+    {
+        public static PathEntry Parse(Stream stream, VolumeDescriptor volumeDescriptor)
+        {
+            var obj = new PathEntry();
+            obj.VolumeDescriptor = volumeDescriptor;
+            obj.Read(stream);
+            return obj;
+        }
+
+        public VolumeDescriptor VolumeDescriptor { get; set; }
+
+        private void Read(Stream stream)
+        {
+            var begin = stream.Position; // For DEBUGGING watch
+
+            var len = stream.ReadByte(); //this byte included in size
+            if (len == 0)
+            {
+                InvalidData = true;
+                return;
+            }
+
+            int nameByteLen;
+            using (var br = new BinaryReader(stream, Encoding.ASCII, true))
+            {
+                ExtendedAttributeRecordlength = br.ReadByte();
+                ExtentLba = br.ReadUInt32LsbMsb();
+                DataLength = br.ReadUInt32LsbMsb();
+                Date = br.ReadFileRecordDate();
+                FileFlags = br.ReadByte();
+                FileUnitSize = br.ReadByte();
+                InterleaveGapSize = br.ReadByte();
+                VolumeSequenceNumber = br.ReadUInt16LsbMsb();
+                nameByteLen = br.ReadByte();
+                Name = br.ReadString(nameByteLen, VolumeDescriptor.Encoding);
+                if (Name.EndsWith(";1"))
+                    Name = Name.Substring(0, Name.Length - 2);
+
+                if (nameByteLen % 2 == 0)
+                {
+                    PaddingByte = br.ReadByte();
+                    if (PaddingByte != 0)
+                    {
+                        throw new InvalidDataException("Invalid padding byte, data error?");
+                    }
+                }
+
+                var remain = len - (stream.Position - begin);
+                if (remain > 0)
+                    RemainBytes = br.ReadBytes((int)remain);
+            }
+        }
+
+        public byte? PaddingByte { get; set; }
+
+        public byte[] RemainBytes { get; set; }
+
+        public bool InvalidData { get; set; }
+
+        public string Name { get; set; }
+
+        public ushort VolumeSequenceNumber { get; set; }
+
+        public byte InterleaveGapSize { get; set; }
+
+        public byte FileUnitSize { get; set; }
+
+        public byte FileFlags { get; set; }
+
+        public DateTime Date { get; set; }
+
+        public uint DataLength { get; set; }
+
+        public uint ExtentLba { get; set; }
+
+        public byte ExtendedAttributeRecordlength { get; set; }
+
+        public bool IsHidden => (FileFlags & 1) != 0;
+        public bool IsDirectory => (FileFlags & (1 << 1)) != 0;
+        public bool IsAssociatedFile => (FileFlags & (1 << 2)) != 0;
+
+        public PathEntry[] ChildPathEntries { get; set; }
+
+        public void ScanChilds(Stream stream)
+        {
+            stream.Seek(ExtentLba * VolumeDescriptor.LogicalBlockSize, SeekOrigin.Begin);
+
+            var list = new List<PathEntry>();
+
+            var endofData = stream.Position + DataLength;
+            while (stream.Position < endofData)
+            {
+                var item = Parse(stream, VolumeDescriptor);
+                if (VolumeDescriptor.Type == 1)
+                    if (item.Name == "\0" || item.Name == "\u0001") continue;
+                if(VolumeDescriptor.Type==2)
+                    if (item.Name == "�" || item.Name == "\u0001") continue;
+                if (item.InvalidData) break;
+                list.Add(item);
+            }
+            ChildPathEntries = list.ToArray();
+
+            list.ForEach(p =>
+            {
+                if (p.IsDirectory)
+                    p.ScanChilds(stream);
+            });
+        }
+    }
+}

+ 164 - 0
Iso9660/VolumeDescriptor.cs

@@ -0,0 +1,164 @@
+using System;
+using System.IO;
+using System.Text;
+
+namespace IsoFilePatcher.Iso9660
+{
+    internal class VolumeDescriptor
+    {
+        public static VolumeDescriptor Parse(Stream stream)
+        {
+            var obj = new VolumeDescriptor();
+            obj.Read(stream);
+            return obj;
+        }
+
+        private void Read(Stream stream)
+        {
+            var begin = stream.Position; // For DEBUGGING watch
+
+            using (var br = new BinaryReader(stream, Encoding.ASCII, true))
+            {
+                Type = br.ReadByte();
+                StandardIdentifier = br.ReadString(5);
+
+                Version = br.ReadByte();
+
+                switch (Type)
+                {
+                    case 0:
+                        SystemIdentifier = br.ReadString(32);
+                        VolumeIdentifier = br.ReadString(32);
+                        BootData = br.ReadBytes(1977);
+                        break;
+
+                    default:
+                        //case 255:
+                        stream.Position += Constants.SectorSize - 6;
+                        break;
+
+                    case 1:
+                    case 2:
+                        Encoding = Encoding.ASCII;
+                        if (Type == 2) Encoding = Encoding.BigEndianUnicode;
+
+                        UnusedByte0007 = br.ReadByte();
+
+                        SystemIdentifier = br.ReadString(32, Encoding);
+                        VolumeIdentifier = br.ReadString(32, Encoding);
+
+                        UnusedField0072 = br.ReadBytes(8);
+
+                        VolumeSpaceSize = br.ReadUInt32LsbMsb();
+
+                        UnusedField0088 = br.ReadBytes(32);
+
+                        VolumeSetSize = br.ReadUInt16LsbMsb();
+                        VolumeSequenceNumber = br.ReadUInt16LsbMsb();
+
+                        LogicalBlockSize = br.ReadUInt16LsbMsb();
+                        PathTableSize = br.ReadUInt32LsbMsb();
+
+                        PathTableL = br.ReadUInt32();
+                        PathTableLOptional = br.ReadUInt32();
+
+                        PathTableM = br.ReadUInt32();
+                        PathTableMOptional = br.ReadUInt32();
+
+                        RootPathEntry = PathEntry.Parse(stream, this);
+
+                        VolumeSetIdentifier = br.ReadString(128, Encoding);
+                        PublisherIdentifier = br.ReadString(128, Encoding);
+                        DataPreparerIdentifier = br.ReadString(128, Encoding);
+                        ApplicationIdentifier = br.ReadString(128, Encoding);
+                        CopyrightFileIdentifier = br.ReadString(38, Encoding);
+                        AbstractFileIdentifier = br.ReadString(36, Encoding);
+                        BibliographicFileIdentifier = br.ReadString(37, Encoding);
+
+                        VolumeCreationDate = br.ReadDecDateTime();
+                        VolumeModificationDate = br.ReadDecDateTime();
+                        VolumeExpirationDate = br.ReadDecDateTime();
+                        VolumeEffectiveDate = br.ReadDecDateTime();
+
+                        FileStructureVersion = br.ReadByte();
+                        UnusedByte0882 = br.ReadByte();
+
+                        ApplicationUsed = br.ReadBytes(512);
+                        Reserved = br.ReadBytes(653);
+                        break;
+                }
+            }
+        }
+
+        public Encoding Encoding { get; set; }
+
+        public byte UnusedByte0882 { get; set; }
+
+        public byte[] BootData { get; set; }
+
+        public byte[] Reserved { get; set; }
+
+        public byte[] ApplicationUsed { get; set; }
+
+        public byte FileStructureVersion { get; set; }
+
+        public DateTime VolumeEffectiveDate { get; set; }
+
+        public DateTime VolumeExpirationDate { get; set; }
+
+        public DateTime VolumeModificationDate { get; set; }
+
+        public DateTime VolumeCreationDate { get; set; }
+
+        public string BibliographicFileIdentifier { get; set; }
+
+        public string AbstractFileIdentifier { get; set; }
+
+        public string CopyrightFileIdentifier { get; set; }
+
+        public string ApplicationIdentifier { get; set; }
+
+        public string DataPreparerIdentifier { get; set; }
+
+        public string PublisherIdentifier { get; set; }
+
+        public string VolumeSetIdentifier { get; set; }
+
+        public PathEntry RootPathEntry { get; set; }
+
+        public uint PathTableMOptional { get; set; }
+
+        public uint PathTableM { get; set; }
+
+        public uint PathTableLOptional { get; set; }
+
+        public uint PathTableL { get; set; }
+
+        public uint PathTableSize { get; set; }
+
+        public ushort LogicalBlockSize { get; set; }
+
+        public ushort VolumeSequenceNumber { get; set; }
+
+        public ushort VolumeSetSize { get; set; }
+
+        public byte[] UnusedField0088 { get; set; }
+
+        public uint VolumeSpaceSize { get; set; }
+
+        public byte[] UnusedField0072 { get; set; }
+
+        public string VolumeIdentifier { get; set; }
+
+        public string SystemIdentifier { get; set; }
+
+        public byte Version { get; set; }
+
+        public string StandardIdentifier { get; private set; }
+
+        public byte Type { get; private set; }
+
+        public bool IsVolumeDescriptorSetTerminator => Type == 0xff;
+        public byte UnusedByte0007 { get; set; }
+    }
+}

+ 76 - 0
IsoFilePatcher.csproj

@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{AC967DCC-5B16-4949-95C4-ECDFC97DD800}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>IsoFilePatcher</RootNamespace>
+    <AssemblyName>IsoFilePatcher</AssemblyName>
+    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup>
+    <StartupObject />
+  </PropertyGroup>
+  <PropertyGroup>
+    <RunPostBuildEvent>OnOutputUpdated</RunPostBuildEvent>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Deployment" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Net.Http" />
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Iso9660\PathEntry.cs" />
+    <Compile Include="Iso9660\Constants.cs" />
+    <Compile Include="Iso9660\ExtensionsMethods.cs" />
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Iso9660\VolumeDescriptor.cs" />
+    <None Include="packages.config" />
+  </ItemGroup>
+  <ItemGroup />
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <PropertyGroup>
+    <PostBuildEvent>if $(ConfigurationName) == Release if not exist $(TargetDir)Packed md $(TargetDir)Packed
+if $(ConfigurationName) == Release $(SolutionDir)packages\ILRepack.2.0.10\tools\ILRepack /ndebug /out:$(TargetDir)Packed\$(TargetFileName) $(TargetPath)</PostBuildEvent>
+  </PropertyGroup>
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

+ 30 - 0
IsoFilePatcher.sln

@@ -0,0 +1,30 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29728.190
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IsoFilePatcher", "IsoFilePatcher.csproj", "{AC967DCC-5B16-4949-95C4-ECDFC97DD800}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1EE6888C-3DE3-43A5-A377-EAB506699614}"
+	ProjectSection(SolutionItems) = preProject
+		README.md = README.md
+	EndProjectSection
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{AC967DCC-5B16-4949-95C4-ECDFC97DD800}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{AC967DCC-5B16-4949-95C4-ECDFC97DD800}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{AC967DCC-5B16-4949-95C4-ECDFC97DD800}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{AC967DCC-5B16-4949-95C4-ECDFC97DD800}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {BB5D61F1-CF14-402C-AEAD-B417C7F01569}
+	EndGlobalSection
+EndGlobal

+ 106 - 0
Program.cs

@@ -0,0 +1,106 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Windows.Forms;
+using IsoFilePatcher.Iso9660;
+
+namespace IsoFilePatcher
+{
+    internal static class Program
+    {
+        /// <summary>
+        /// 应用程序的主入口点。
+        /// </summary>
+        [STAThread]
+        private static void Main(string[] args)
+        {
+            try
+            {
+                MainInternal(args);
+            }
+            catch (Exception ex)
+            {
+
+                Console.WriteLine();
+                Console.WriteLine("----ERROR BEGIN----");
+                Console.WriteLine(ex);
+                Console.WriteLine("-----ERROR END-----");
+            }
+
+            Console.WriteLine();
+            Console.Write("Press ENTER to exit...");
+            Console.ReadLine();
+        }
+
+        private static void MainInternal(string[] args)
+        {
+            if (args.Length != 3)
+            {
+                Console.WriteLine($"Useage: {Path.GetFileName(Application.ExecutablePath)} <IsoFile> <Path> <DataToReplaceFrom>");
+                Console.WriteLine($"Example: {Path.GetFileName(Application.ExecutablePath)} C:\\PS3.ISO PS3_GAME\\USRDIR\\EBOOT.BIN C:\\RESIGNED_EBOOT.BIN");
+                return;
+            }
+
+            var isoFile = args[0];
+            var path = args[1];
+            var dataToReplaceFrom = args[2];
+
+            Console.WriteLine($"Opening {isoFile} ...");
+
+            using (var isoStream = new FileStream(isoFile, FileMode.Open, FileAccess.ReadWrite))
+            {
+                Console.WriteLine("Skipping system area...");
+                isoStream.Position = 16 * Constants.SectorSize;
+
+                Console.WriteLine("Parsing VolumeDescriptor...");
+                var descriptors = new List<VolumeDescriptor>();
+                do
+                {
+                    var item = VolumeDescriptor.Parse(isoStream);
+                    if (item.IsVolumeDescriptorSetTerminator) break;
+                    descriptors.Add(item);
+                } while (true);
+
+                Console.WriteLine("Parsing path entries...");
+                var root = (descriptors.FirstOrDefault(p => p.Type == 2) ?? descriptors[0]).RootPathEntry;
+                root.ScanChilds(isoStream);
+
+                Console.WriteLine("Locating file...");
+                var pathEntries = path.Split(Path.DirectorySeparatorChar);
+                var currentPath = root;
+                foreach (var item in pathEntries)
+                {
+                    var target = currentPath.ChildPathEntries.FirstOrDefault(p => 0 == string.Compare(p.Name, item, StringComparison.OrdinalIgnoreCase));
+                    if (target == null)
+                        throw new ArgumentException("Path not found");
+                    currentPath = target;
+                }
+
+                if (currentPath.IsDirectory)
+                    throw new ArgumentException("Path is a directory");
+
+                Console.WriteLine("Feasibility checking...");
+                var dataFile = new FileInfo(dataToReplaceFrom);
+                if (false == dataFile.Exists)
+                    throw new FileNotFoundException("File not found", dataToReplaceFrom);
+                if (dataFile.Length > currentPath.DataLength)
+                    throw new ArgumentException("File large than orignal, can not continue");
+
+                Console.WriteLine("Operation in progress...");
+                isoStream.Position = currentPath.ExtentLba * currentPath.VolumeDescriptor.LogicalBlockSize;
+                using (var stream = dataFile.OpenRead())
+                {
+                    stream.CopyTo(isoStream);
+                }
+                Console.WriteLine("Flushing file...");
+                isoStream.Flush();
+                Console.WriteLine("Closing file...");
+                isoStream.Close();
+                isoStream.Dispose();
+
+                Console.WriteLine("Operation completed successfully.");
+            }
+        }
+    }
+}

+ 36 - 0
Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 有关程序集的一般信息由以下
+// 控制。更改这些特性值可修改
+// 与程序集关联的信息。
+[assembly: AssemblyTitle("IsoFilePatcher")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("IsoFilePatcher")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2016")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+//将 ComVisible 设置为 false 将使此程序集中的类型
+//对 COM 组件不可见。  如果需要从 COM 访问此程序集中的类型,
+//请将此类型的 ComVisible 特性设置为 true。
+[assembly: ComVisible(false)]
+
+// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
+[assembly: Guid("ac967dcc-5b16-4949-95c4-ecdfc97dd800")]
+
+// 程序集的版本信息由下列四个值组成: 
+//
+//      主版本
+//      次版本
+//      生成号
+//      修订号
+//
+//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
+// 方法是按如下所示使用“*”: :
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 9 - 0
README.md

@@ -1,2 +1,11 @@
 # IsoFilePatcher-Archive
 
+## About ISO 9660 Format
+
+[CD-ROM_ISO9660.pdf](Documents/CD-ROM_ISO9660.pdf)
+
+[Ecma-119.pdf](Documents/Ecma-119.pdf)
+
+[ISO_9660 on osdev wiki](https://wiki.osdev.org/ISO_9660#System_Area)
+
+[ISO9960 on users.telenet.be](http://users.telenet.be/it3.consultants.bvba/handouts/ISO9960.html)

+ 4 - 0
packages.config

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="ILRepack" version="2.0.10" targetFramework="net461" />
+</packages>