├── TextureExtraction tool
├── Icon.ico
├── Scans
│ ├── Helper
│ │ └── ScanObjekt.cs
│ ├── Results
│ │ ├── ScanResults.cs
│ │ └── FinalizeResults.cs
│ ├── Options
│ │ └── TextureExtractorOptions.cs
│ ├── Compress.cs
│ └── Cutter.cs
├── App.config
├── LICENSE.TXT
├── Data
│ ├── ConsoleBar.cs
│ └── LogBase.cs
├── AppSettings.cs
└── DolphinTextureExtraction tool.csproj
├── lib
├── AuroraLip
│ ├── DiscImage
│ │ ├── RVZ
│ │ │ ├── DiscTypes.cs
│ │ │ ├── ImageType.cs
│ │ │ ├── ExceptListT.cs
│ │ │ ├── CompressionTypes.cs
│ │ │ ├── RvzGroupT.cs
│ │ │ ├── PartDataT.cs
│ │ │ ├── RawDataT.cs
│ │ │ ├── ExceptionT.cs
│ │ │ ├── PartT.cs
│ │ │ ├── RVZVersion.cs
│ │ │ └── Header.cs
│ │ ├── Revolution
│ │ │ ├── SigTyp.cs
│ │ │ ├── Ratings.cs
│ │ │ ├── SignedBlobHeader.cs
│ │ │ ├── HeaderBin.cs
│ │ │ ├── WiiKey.cs
│ │ │ └── CMD.cs
│ │ └── Dolphin
│ │ │ ├── Bi2Bin.cs
│ │ │ ├── FSTBin.cs
│ │ │ ├── GameHeader.cs
│ │ │ └── BootBin.cs
│ ├── Common
│ │ ├── Enums
│ │ │ ├── NotificationType.cs
│ │ │ └── FormatType.cs
│ │ ├── Reflection.cs
│ │ ├── Interfaces
│ │ │ ├── IFileSystemInfo.cs
│ │ │ ├── IFileRequest.cs
│ │ │ ├── IFileAccess.cs
│ │ │ └── IDataTime.cs
│ │ ├── Node
│ │ │ ├── NodeProcessor.cs
│ │ │ └── Interfaces
│ │ │ │ └── IBinaryObjectNode.cs
│ │ ├── Exceptions.cs
│ │ ├── Events.cs
│ │ ├── Extensions
│ │ │ └── MiscEX.cs
│ │ └── XORStream.cs
│ ├── Palette
│ │ ├── JUTTlut.cs
│ │ └── Formats
│ │ │ └── PLT0.cs
│ ├── Texture
│ │ ├── Interfaces
│ │ │ ├── IImageInfo.cs
│ │ │ └── IGXTextureInfo.cs
│ │ ├── Enums
│ │ │ ├── JUTTransparency.cs
│ │ │ ├── WrapMode.cs
│ │ │ ├── GXFilterMode.cs
│ │ │ ├── GXPaletteFormat.cs
│ │ │ └── UImageFormats.cs
│ │ ├── J3D
│ │ │ ├── Enums
│ │ │ │ ├── TangentMode.cs
│ │ │ │ └── LoopMode.cs
│ │ │ └── NameTableIO.cs
│ │ ├── Formats
│ │ │ ├── GBIX.cs
│ │ │ ├── GCIX.cs
│ │ │ ├── TPX.cs
│ │ │ ├── FIPAFTEX.cs
│ │ │ ├── S3G.cs
│ │ │ ├── TXD.cs
│ │ │ ├── GCNT.cs
│ │ │ ├── RES_NLG.cs
│ │ │ ├── GCT0.cs
│ │ │ ├── GTX1.cs
│ │ │ ├── text.cs
│ │ │ ├── PIM.cs
│ │ │ ├── TXTR.cs
│ │ │ ├── PIL.cs
│ │ │ └── TDL0.cs
│ │ ├── BlockFormats
│ │ │ ├── I8Block.cs
│ │ │ ├── IA4Block.cs
│ │ │ ├── IA8Block.cs
│ │ │ ├── RGB565Block.cs
│ │ │ ├── RGB5A3Block.cs
│ │ │ ├── I4Block.cs
│ │ │ ├── I14Block.cs
│ │ │ └── RGBA32Block.cs
│ │ └── JUTTexture.cs
│ ├── Compression
│ │ ├── Algorithms
│ │ │ ├── CRILAYLA.cs
│ │ │ └── Zstd.cs
│ │ └── CompressionReflection.cs
│ ├── Archives
│ │ └── Formats
│ │ │ ├── BUG.cs
│ │ │ ├── CMN.cs
│ │ │ ├── pBin.cs
│ │ │ ├── ONE_UN.cs
│ │ │ ├── TXAG.cs
│ │ │ ├── RVZ.cs
│ │ │ ├── MEDB.cs
│ │ │ ├── NEP.cs
│ │ │ ├── FBC.cs
│ │ │ ├── PCKG.cs
│ │ │ ├── RSC.cs
│ │ │ ├── GSAGTX.cs
│ │ │ ├── PAK_FE.cs
│ │ │ ├── RMHG.cs
│ │ │ ├── FBTI.cs
│ │ │ ├── FONT.cs
│ │ │ ├── NLCL.cs
│ │ │ ├── ONE_SB.cs
│ │ │ ├── AFS.cs
│ │ │ ├── NARC.cs
│ │ │ ├── PKX.cs
│ │ │ ├── CPK.cs
│ │ │ ├── PAC.cs
│ │ │ ├── PAKb.cs
│ │ │ ├── RTDP.cs
│ │ │ ├── PAK_TM2.cs
│ │ │ ├── TSET.cs
│ │ │ ├── ARC0.cs
│ │ │ ├── RKV2.cs
│ │ │ └── FTEX.cs
│ └── AuroraLib.csproj
├── AFSLib
│ ├── Entry.cs
│ ├── StreamEntryInfo.cs
│ ├── NullEntry.cs
│ ├── HeaderMagicType.cs
│ ├── NotificationType.cs
│ ├── FileEntry.cs
│ ├── AttributesInfoType.cs
│ ├── AFSLib.csproj
│ ├── StreamEntry.cs
│ ├── LICENSE
│ └── Utils.cs
├── LibCPK
│ ├── LibCPK.csproj
│ └── README.md
└── Hack.io
│ ├── Hack.io.csproj
│ └── README.md
├── Benchmark
├── Benchmarker.cs
├── Benchmark.csproj
└── Benchmarks
│ ├── ReadUInt64.cs
│ ├── ValuesRevers.cs
│ ├── CopyByte.cs
│ └── StringBuilder.cs
├── .gitattributes
├── LICENSE
└── .editorconfig
/TextureExtraction tool/Icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Venomalia/DolphinTextureExtraction-tool/HEAD/TextureExtraction tool/Icon.ico
--------------------------------------------------------------------------------
/lib/AuroraLip/DiscImage/RVZ/DiscTypes.cs:
--------------------------------------------------------------------------------
1 | namespace AuroraLib.DiscImage.RVZ
2 | {
3 | public enum DiscTypes : uint
4 | {
5 | GameCube = 1,
6 | Wii = 2,
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/lib/AuroraLip/DiscImage/RVZ/ImageType.cs:
--------------------------------------------------------------------------------
1 | namespace AuroraLib.DiscImage.RVZ
2 | {
3 | public enum ImageType : uint
4 | {
5 | WIA = 1464418561,
6 | RVZ = 1381390849,
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Common/Enums/NotificationType.cs:
--------------------------------------------------------------------------------
1 | namespace AuroraLib.Common
2 | {
3 | ///
4 | ///
5 | ///
6 | public enum NotificationType
7 | {
8 | Info,
9 | Warning,
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/lib/AuroraLip/DiscImage/RVZ/ExceptListT.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Cryptography;
2 |
3 | namespace AuroraLib.DiscImage.RVZ
4 | {
5 | public readonly struct ExceptListT
6 | {
7 | public readonly ushort Offset;
8 | public readonly UInt128 Hash;
9 |
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/lib/AFSLib/Entry.cs:
--------------------------------------------------------------------------------
1 | namespace AFSLib
2 | {
3 | ///
4 | /// Abstract class that represents an entry. All types of entries derive from Entry.
5 | ///
6 | public abstract class Entry
7 | {
8 | internal abstract Stream GetStream();
9 | }
10 | }
--------------------------------------------------------------------------------
/lib/AuroraLip/DiscImage/RVZ/CompressionTypes.cs:
--------------------------------------------------------------------------------
1 | namespace AuroraLib.DiscImage.RVZ
2 | {
3 | public enum CompressionTypes : uint
4 | {
5 | None = 0,
6 | PURGE = 1,
7 | BZIP2 = 2,
8 | LZMA = 3,
9 | LZMA2 = 4,
10 | Zstandard = 5,
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/lib/AuroraLip/DiscImage/Revolution/SigTyp.cs:
--------------------------------------------------------------------------------
1 | namespace AuroraLib.DiscImage.Revolution
2 | {
3 | ///
4 | /// Signature types
5 | ///
6 | public enum SigTyp : uint
7 | {
8 | RSA_4096 = 0x00010000,
9 | RSA_2048 = 0x00010001,
10 | EllipticCurve = 0x00010002,
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Benchmark/Benchmarker.cs:
--------------------------------------------------------------------------------
1 | using Benchmark.Benchmarks;
2 | using BenchmarkDotNet.Running;
3 | using System.Buffers.Binary;
4 |
5 | namespace Benchmark
6 | {
7 | public class Benchmarker
8 | {
9 | static void Main(string[] args)
10 | {
11 | var Result = BenchmarkRunner.Run();
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/lib/AFSLib/StreamEntryInfo.cs:
--------------------------------------------------------------------------------
1 | namespace AFSLib
2 | {
3 | internal struct StreamEntryInfo
4 | {
5 | public uint Offset;
6 | public string Name;
7 | public uint Size;
8 | public DateTime LastWriteTime;
9 | public uint UnknownAttribute;
10 |
11 | public bool IsNull => Offset == 0 || Size == 0;
12 | }
13 | }
--------------------------------------------------------------------------------
/lib/AuroraLip/Common/Reflection.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Compression;
2 | using AuroraLib.Core.Interfaces;
3 |
4 | namespace AuroraLib.Common
5 | {
6 | public static class Reflection
7 | {
8 | public static FileAccessReflection FileAccess = new();
9 |
10 | public static CompressionReflection Compression = new();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/lib/AFSLib/NullEntry.cs:
--------------------------------------------------------------------------------
1 | namespace AFSLib
2 | {
3 | ///
4 | /// Class that represents an empty entry with no data.
5 | ///
6 | public class NullEntry : Entry
7 | {
8 | internal NullEntry()
9 | {
10 |
11 | }
12 |
13 | internal override Stream GetStream()
14 | {
15 | return null;
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/lib/AuroraLip/Palette/JUTTlut.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Texture;
2 |
3 | namespace AuroraLib.Palette
4 | {
5 | public interface IJUTPalette
6 | {
7 | ///
8 | /// specifies how the data within the palette is stored.
9 | ///
10 | GXPaletteFormat Format { get; }
11 |
12 | ///
13 | /// Palette data
14 | ///
15 | byte[] Data { get; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Common/Interfaces/IFileSystemInfo.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Core.Interfaces;
2 |
3 | namespace AuroraLib.Common
4 | {
5 | ///
6 | /// Provides standard file properties.
7 | ///
8 | public interface IFileSystemInfo : IObjectName, IDataTime
9 | {
10 | ///
11 | /// Represents the full path of the directory or file.
12 | ///
13 | string FullPath { get; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Common/Interfaces/IFileRequest.cs:
--------------------------------------------------------------------------------
1 | using static AuroraLib.Common.Events;
2 |
3 | namespace AuroraLib.Common
4 | {
5 | ///
6 | /// Interface to request additional files if necessary.
7 | ///
8 | internal interface IFileRequest
9 | {
10 | ///
11 | /// Event that is called when the process needs an additional file.
12 | ///
13 | FileRequestDelegate FileRequest { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/lib/AuroraLip/DiscImage/RVZ/RvzGroupT.cs:
--------------------------------------------------------------------------------
1 | namespace AuroraLib.DiscImage.RVZ
2 | {
3 | public readonly struct RvzGroupT
4 | {
5 | private readonly uint dataOffset;
6 | private readonly uint packtDataSize;
7 | public readonly uint PackedSize;
8 |
9 | public readonly uint DataOffset => dataOffset << 2;
10 | public readonly uint DataSize => packtDataSize & 0x7FFFFFFF;
11 | public readonly bool IsCompressed => (packtDataSize & 0x80000000) != 0;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/lib/AuroraLip/DiscImage/Revolution/Ratings.cs:
--------------------------------------------------------------------------------
1 | namespace AuroraLib.DiscImage.Revolution
2 | {
3 | public struct Ratings
4 | {
5 | public byte CERO;
6 | public byte ESRB;
7 | private byte u0;
8 | public byte FSK;
9 | public byte PEGI;
10 | public byte PEGI_Finland;
11 | public byte PEGI_Portugal;
12 | public byte BBFC;
13 | public byte ACB;
14 | public byte GRAC;
15 | private readonly byte u1, u2, u3, u4, u5, u6;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/lib/AuroraLip/DiscImage/Dolphin/Bi2Bin.cs:
--------------------------------------------------------------------------------
1 | namespace AuroraLib.DiscImage.Dolphin
2 | {
3 | public struct Bi2Bin
4 | {
5 | public uint DebugMonitorSize; //0
6 | public uint SimulatedMemorySize; // 25165824
7 | public uint ArgumentOffset; //0
8 | public uint DebugFlag; //0
9 | public uint TrackLocation; //0
10 | public uint TrackSize; //0
11 | public uint CountryCode; //2
12 | public uint Unknown_1; //1
13 | public uint Unknown_2; //1
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/Interfaces/IImageInfo.cs:
--------------------------------------------------------------------------------
1 | namespace AuroraLib.Texture.Interfaces
2 | {
3 | ///
4 | /// Interface representing an image properties with width and height.
5 | ///
6 | public interface IImageInfo
7 | {
8 | ///
9 | /// The width of the image.
10 | ///
11 | int Width { get; }
12 |
13 | ///
14 | /// The height of the image.
15 | ///
16 | int Height { get; }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Common/Interfaces/IFileAccess.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Core.Interfaces;
2 |
3 | namespace AuroraLib.Common
4 | {
5 | ///
6 | /// Simple interface for a file access.
7 | ///
8 | public interface IFileAccess : IFormatRecognition
9 | {
10 | ///
11 | /// Can be read
12 | ///
13 | bool CanRead { get; }
14 |
15 | ///
16 | /// Can be Write
17 | ///
18 | bool CanWrite { get; }
19 |
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/TextureExtraction tool/Scans/Helper/ScanObjekt.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Common.Node;
3 |
4 | namespace DolphinTextureExtraction.Scans.Helper
5 | {
6 | public readonly ref struct ScanObjekt
7 | {
8 | public FormatInfo Format { get; }
9 | public int Deep { get; }
10 | public FileNode File { get; }
11 |
12 | public ScanObjekt(FileNode file, int deep)
13 | {
14 | Format = file.Data.Identify(file.Extension);
15 | Deep = deep;
16 | File = file;
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/lib/AFSLib/HeaderMagicType.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace AFSLib
3 | {
4 | ///
5 | /// Enumeration containing each type of header magic that can be found in an AFS archive.
6 | ///
7 | public enum HeaderMagicType
8 | {
9 | ///
10 | /// Some AFS files contain a 4-byte header magic with 'AFS' followed by 0x00.
11 | ///
12 | AFS_00,
13 |
14 | ///
15 | /// Some AFS files contain a 4-byte header magic with 'AFS' followed by 0x20.
16 | ///
17 | AFS_20
18 | }
19 | }
--------------------------------------------------------------------------------
/lib/AuroraLip/DiscImage/RVZ/PartDataT.cs:
--------------------------------------------------------------------------------
1 | namespace AuroraLib.DiscImage.RVZ
2 | {
3 | public readonly struct PartDataT
4 | {
5 | public readonly uint FirstSector;
6 | public readonly uint Sectors;
7 | public readonly uint GroupIndex;
8 | public readonly uint Groups;
9 |
10 | public PartDataT(uint firstSector, uint sectors, uint groupIndex, uint groups)
11 | {
12 | FirstSector = firstSector;
13 | Sectors = sectors;
14 | GroupIndex = groupIndex;
15 | Groups = groups;
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Common/Enums/FormatType.cs:
--------------------------------------------------------------------------------
1 | namespace AuroraLib.Common
2 | {
3 | ///
4 | /// The format type specifies the intended use of a file format.
5 | ///
6 | public enum FormatType
7 | {
8 | Unknown = default,
9 | Archive,
10 | Texture,
11 | Audio,
12 | Model,
13 | Collision,
14 | Video,
15 | Text,
16 | Font,
17 | Layout,
18 | Animation,
19 | Skript,
20 | Parameter,
21 | Executable,
22 | Effect,
23 | Shader,
24 | Rom,
25 | Iso,
26 | Else,
27 | Dummy
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/lib/AuroraLip/DiscImage/RVZ/RawDataT.cs:
--------------------------------------------------------------------------------
1 | namespace AuroraLib.DiscImage.RVZ
2 | {
3 | public readonly struct RawDataT
4 | {
5 | public readonly long DataOffset;
6 | public readonly long DataSize;
7 | public readonly uint GroupIndex;
8 | public readonly uint Groups;
9 |
10 | public readonly long DataEndOffset => DataOffset + DataSize;
11 |
12 | public RawDataT(long dataOffset, long dataSize, uint groupIndex, uint groups)
13 | {
14 | DataOffset = dataOffset;
15 | DataSize = dataSize;
16 | GroupIndex = groupIndex;
17 | Groups = groups;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/Enums/JUTTransparency.cs:
--------------------------------------------------------------------------------
1 | namespace AuroraLib.Texture
2 | {
3 | public enum JUTTransparency : byte
4 | {
5 | ///
6 | /// No Transperancy
7 | ///
8 | OPAQUE = 0x00,
9 |
10 | ///
11 | /// Only allows fully Transperant pixels to be see through
12 | ///
13 | CUTOUT = 0x01,
14 |
15 | ///
16 | /// Allows Partial Transperancy. Also known as XLUCENT
17 | ///
18 | TRANSLUCENT = 0x02,
19 |
20 | ///
21 | /// Unknown
22 | ///
23 | SPECIAL = 0xCC
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Benchmark/Benchmark.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net8.0
6 | enable
7 | enable
8 | True
9 | Benchmark.Benchmarker
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/lib/AuroraLip/DiscImage/RVZ/ExceptionT.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Core.Interfaces;
2 |
3 | namespace AuroraLib.DiscImage.RVZ
4 | {
5 | public class ExceptionT : IBinaryObject
6 | {
7 | public ushort Offset;
8 | public readonly byte[] Hash;
9 |
10 | public ExceptionT()
11 | => Hash = new byte[20];
12 |
13 | public void BinaryDeserialize(Stream source)
14 | {
15 | Offset = source.ReadUInt16(Endian.Big);
16 | source.Read(Hash);
17 | }
18 |
19 | public void BinarySerialize(Stream dest)
20 | {
21 | dest.Write(Offset);
22 | dest.Write(Hash);
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/J3D/Enums/TangentMode.cs:
--------------------------------------------------------------------------------
1 | namespace AuroraLib.Texture.J3D
2 | {
3 | public static partial class J3DGraph
4 | {
5 | ///
6 | /// J3D Tangent Modes
7 | ///
8 | public enum TangentMode : short
9 | {
10 | ///
11 | /// One tangent value is stored, used for both the incoming and outgoing tangents
12 | ///
13 | SYNC = 0x00,
14 |
15 | ///
16 | /// Two tangent values are stored, the incoming and outgoing tangents, respectively
17 | ///
18 | DESYNC = 0x01
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Common/Node/NodeProcessor.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Compression.Interfaces;
2 |
3 | namespace AuroraLib.Common.Node
4 | {
5 | public static class NodeProcessor
6 | {
7 | public static void Expand(this FileNode file, ICompressionDecoder decoder)
8 | {
9 | MemoryPoolStream dataDecompress = new();
10 | try
11 | {
12 | decoder.Decompress(file.Data, dataDecompress);
13 | file.Data.Dispose();
14 | file.Data = dataDecompress;
15 | }
16 | catch (Exception)
17 | {
18 | dataDecompress.Dispose();
19 | throw;
20 | }
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Common/Interfaces/IDataTime.cs:
--------------------------------------------------------------------------------
1 | namespace AuroraLib.Common
2 | {
3 | ///
4 | /// Provides typical data time properties.
5 | ///
6 | public interface IDataTime
7 | {
8 | ///
9 | /// The creation date and time in UTC format.
10 | ///
11 | DateTime CreationTimeUtc { get; }
12 |
13 | ///
14 | /// The last modification date and time in UTC format.
15 | ///
16 | DateTime LastWriteTimeUtc { get; }
17 |
18 | ///
19 | /// The last accessed date and time in UTC format.
20 | ///
21 | DateTime LastAccessTimeUtc { get; }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto eol=lf
3 |
4 | # Source files
5 | *.cs text diff=csharp
6 | *.cshtml text diff=html
7 | *.csx text diff=csharp
8 |
9 | # Project and solution files
10 | *.sln text eol=crlf
11 | *.csproj text eol=crlf
12 | *.vbproj text eol=crlf
13 | *.vcxproj text eol=crlf
14 | *.vcproj text eol=crlf
15 | *.dbproj text eol=crlf
16 | *.fsproj text eol=crlf
17 | *.lsproj text eol=crlf
18 | *.wixproj text eol=crlf
19 | *.modelproj text eol=crlf
20 | *.sqlproj text eol=crlf
21 | *.wwaproj text eol=crlf
22 | *.xproj text eol=crlf
23 | *.props text eol=crlf
24 | *.filters text eol=crlf
25 | *.vcxitems text eol=crlf
26 |
--------------------------------------------------------------------------------
/lib/AFSLib/NotificationType.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace AFSLib
3 | {
4 | ///
5 | /// Enumeration containing all types of notifications.
6 | ///
7 | public enum NotificationType
8 | {
9 | ///
10 | /// Notification considered as Information.
11 | ///
12 | Info,
13 |
14 | ///
15 | /// Notification considered as Warning.
16 | ///
17 | Warning,
18 |
19 | ///
20 | /// Notification considered as Error.
21 | ///
22 | Error,
23 |
24 | ///
25 | /// Notification considered as Success.
26 | ///
27 | Success
28 | }
29 | }
--------------------------------------------------------------------------------
/lib/AuroraLip/Common/Exceptions.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.Serialization;
2 |
3 | namespace AuroraLib.Common
4 | {
5 | public class PaletteException : Exception
6 | {
7 | public string ExpectedIdentifier { get; set; }
8 |
9 | public PaletteException()
10 | { }
11 |
12 | public PaletteException(string message) : base(message)
13 | {
14 | }
15 |
16 | public PaletteException(string message, Exception innerException) : base(message, innerException)
17 | {
18 | }
19 |
20 | [Obsolete(DiagnosticId = "SYSLIB0051")]
21 | protected PaletteException(SerializationInfo info, StreamingContext context) : base(info, context)
22 | {
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/Enums/WrapMode.cs:
--------------------------------------------------------------------------------
1 | namespace AuroraLib.Texture
2 | {
3 | ///
4 | /// Defines how textures handle going out of [0..1] range for texcoords.
5 | ///
6 | public enum GXWrapMode : byte
7 | {
8 | ///
9 | /// Clamps the texture to the last pixel at the edge.
10 | ///
11 | CLAMP = 0x00,
12 |
13 | ///
14 | /// Tiles the texture, creating a repeating pattern.
15 | ///
16 | REPEAT = 0x01,
17 |
18 | ///
19 | /// Tiles the texture, creating a repeating pattern by mirroring it at every integer boundary.
20 | ///
21 | MIRRORREAPEAT = 0x02
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/lib/AFSLib/FileEntry.cs:
--------------------------------------------------------------------------------
1 | namespace AFSLib
2 | {
3 | ///
4 | /// Class that represents an entry with data referenced from a file.
5 | ///
6 | public sealed class FileEntry : DataEntry
7 | {
8 | private readonly FileInfo fileInfo;
9 |
10 | internal FileEntry(string fileNamePath, string entryName)
11 | {
12 | fileInfo = new FileInfo(fileNamePath);
13 |
14 | Name = entryName;
15 | Size = (uint)fileInfo.Length;
16 | LastWriteTime = fileInfo.LastWriteTime;
17 | UnknownAttribute = (uint)fileInfo.Length;
18 | }
19 |
20 | internal override Stream GetStream()
21 | {
22 | return fileInfo.OpenRead();
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/lib/AFSLib/AttributesInfoType.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace AFSLib
3 | {
4 | ///
5 | /// Enumeration that contains all possible attribute info locations in an AFS archive.
6 | ///
7 | public enum AttributesInfoType
8 | {
9 | ///
10 | /// The AFS file doesn't contain an attributes block.
11 | ///
12 | NoAttributes,
13 |
14 | ///
15 | /// Info about the attributes block is located at the beginning of the attributes info block.
16 | ///
17 | InfoAtBeginning,
18 |
19 | ///
20 | /// Info about the attributes block is located at the end of the attributes info block.
21 | ///
22 | InfoAtEnd
23 | }
24 | }
--------------------------------------------------------------------------------
/lib/LibCPK/LibCPK.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Library
5 | net8.0
6 | {BA3A00E4-4F51-4AB4-A8FB-F4B64A874449}
7 | enable
8 | disable
9 | False
10 | LibCPK
11 | $(AssemblyTitle)
12 | False
13 | AnyCPU
14 | true
15 | Copyright © 2016-present
16 | LibCPK
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/lib/AuroraLip/DiscImage/RVZ/PartT.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Core.Interfaces;
2 |
3 | namespace AuroraLib.DiscImage.RVZ
4 | {
5 | public class PartT : IBinaryObject
6 | {
7 | public readonly byte[] PartKey;
8 | public PartDataT[] PartData;
9 |
10 | public PartT()
11 | {
12 | PartKey = new byte[0x10];
13 | PartData = new PartDataT[2];
14 | }
15 |
16 | public void BinaryDeserialize(Stream source)
17 | {
18 | source.Read(PartKey);
19 | source.Read(PartData, Endian.Big);
20 | }
21 |
22 | public void BinarySerialize(Stream dest)
23 | {
24 | dest.Write(PartKey);
25 | dest.Write(PartData, Endian.Big);
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/TextureExtraction tool/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/Formats/GBIX.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Core.Interfaces;
2 |
3 | namespace AuroraLib.Texture.Formats
4 | {
5 | public class GBIX : GVRT
6 | {
7 | public override bool CanWrite => false;
8 |
9 | public override IIdentifier Identifier => _identifier;
10 |
11 | private static readonly Identifier32 _identifier = new("GBIX");
12 |
13 | protected override void Read(Stream stream)
14 | {
15 | stream.MatchThrow(_identifier);
16 | uint startOfGVRT = stream.ReadUInt32();
17 | uint GlobalIndex = stream.ReadUInt32(Endian.Big);
18 |
19 | stream.Seek(startOfGVRT + 8, SeekOrigin.Begin);
20 | base.Read(stream); //GVRT
21 | }
22 |
23 | protected override void Write(Stream stream)
24 | {
25 | throw new NotImplementedException();
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/Formats/GCIX.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Core.Interfaces;
2 |
3 | namespace AuroraLib.Texture.Formats
4 | {
5 | public class GCIX : GVRT
6 | {
7 | public override bool CanWrite => false;
8 |
9 | public override IIdentifier Identifier => _identifier;
10 |
11 | private static readonly Identifier32 _identifier = new("GCIX");
12 |
13 | protected override void Read(Stream stream)
14 | {
15 | stream.MatchThrow(_identifier);
16 | uint startOfGVRT = stream.ReadUInt32();
17 | uint GlobalIndex = stream.ReadUInt32(Endian.Big);
18 |
19 | stream.Seek(startOfGVRT + 8, SeekOrigin.Begin);
20 | base.Read(stream); //GVRT
21 | }
22 |
23 | protected override void Write(Stream stream)
24 | {
25 | throw new NotImplementedException();
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Benchmark/Benchmarks/ReadUInt64.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Core;
2 | using BenchmarkDotNet.Attributes;
3 | using System.Buffers.Binary;
4 | using System.Runtime.CompilerServices;
5 | using System.Runtime.InteropServices;
6 |
7 | namespace Benchmark.Benchmarks
8 | {
9 | [MemoryDiagnoser]
10 | public class ReadUInt64
11 | {
12 | private const int n = 10000;
13 |
14 | private const ulong SIZE = 32;
15 |
16 | [Benchmark]
17 | public void BinaryPrimitives_Read()
18 | {
19 | for (var i = 0; i < n; ++i)
20 | {
21 | BinaryPrimitives.ReverseEndianness(SIZE);
22 | }
23 | }
24 |
25 | [Benchmark]
26 | public void MemoryMarshal_Read()
27 | {
28 | for (var i = 0; i < n; ++i)
29 | {
30 | BitConverterX.Swap(SIZE);
31 | }
32 | }
33 |
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/lib/AuroraLip/DiscImage/Revolution/SignedBlobHeader.cs:
--------------------------------------------------------------------------------
1 | namespace AuroraLib.DiscImage.Revolution
2 | {
3 | public abstract class SignedBlobHeader
4 | {
5 | public SigTyp SignatureType { get; } //Signature type (always 65537 for RSA-2048)
6 | public readonly byte[] Certificate = new byte[256];
7 | public readonly byte[] SigPad = new byte[60];
8 |
9 | public SignedBlobHeader(Stream source)
10 | {
11 | SignatureType = source.Read(Endian.Big);
12 | source.Read(Certificate);
13 | source.Read(SigPad);
14 | }
15 |
16 | public void Write(Stream dest)
17 | {
18 | dest.Write(SignatureType, Endian.Big);
19 | dest.Write(Certificate);
20 | dest.Write(SigPad);
21 | WriteData(dest);
22 | }
23 |
24 | protected abstract void WriteData(Stream dest);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/lib/AFSLib/AFSLib.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Library
5 | net8.0
6 | {09C23352-8261-447B-9BB5-4C82DAF3CFFD}
7 | enable
8 | disable
9 | False
10 | MIT
11 | AFSLib
12 | $(AssemblyTitle)
13 | False
14 | AFSLib is a library that can extract, create and manipulate AFS files. The AFS format is used in many games from companies like Sega.
15 | AFSLib
16 | Copyright © MaikelChan 2022-present
17 | MaikelChan
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Compression/Algorithms/CRILAYLA.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Compression.Interfaces;
2 | using AuroraLib.Core.Interfaces;
3 | using System.IO.Compression;
4 |
5 | namespace AuroraLib.Compression.Algorithms
6 | {
7 | public class CRILAYLA : ICompressionAlgorithm, IHasIdentifier
8 | {
9 | public virtual IIdentifier Identifier => _identifier;
10 |
11 | private static readonly Identifier64 _identifier = new("CRILAYLA");
12 |
13 | public bool IsMatch(Stream stream, ReadOnlySpan extension = default)
14 | => stream.Length > 0x10 && stream.Match(_identifier);
15 |
16 | public void Decompress(Stream source, Stream destination)
17 | => LibCPK.CRILAYLA.Decompress(source, destination);
18 |
19 | public void Compress(ReadOnlySpan source, Stream destination, CompressionLevel level = CompressionLevel.Optimal)
20 | => LibCPK.CRILAYLA.Compress(source, destination);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/lib/AFSLib/StreamEntry.cs:
--------------------------------------------------------------------------------
1 | namespace AFSLib
2 | {
3 | ///
4 | /// Class that represents an entry with data referenced from a stream.
5 | ///
6 | public sealed class StreamEntry : DataEntry
7 | {
8 | private readonly Stream baseStream;
9 | private readonly uint baseStreamDataOffset;
10 |
11 | internal StreamEntry(Stream baseStream, StreamEntryInfo info)
12 | {
13 | this.baseStream = baseStream;
14 | baseStreamDataOffset = info.Offset;
15 |
16 | Name = info.Name;
17 | Size = info.Size;
18 | LastWriteTime = info.LastWriteTime;
19 | UnknownAttribute = info.UnknownAttribute;
20 | }
21 |
22 | internal override Stream GetStream()
23 | {
24 | baseStream.Position = baseStreamDataOffset;
25 | return new SubStream(baseStream, 0, Size, true);
26 | }
27 |
28 | public Stream GetSubStream() => GetStream();
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Common/Node/Interfaces/IBinaryObjectNode.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Core.Interfaces;
2 |
3 | namespace AuroraLib.Common.Node.Interfaces
4 | {
5 | ///
6 | /// Represents a node object that can be serialized and deserialized.
7 | ///
8 | public interface IBinaryObjectNode : IBinaryObject, IDisposable, IObjectName, IDataTime, IFileAccess
9 | {
10 | ///
11 | /// Deserializes the binary data for this node from the specified .
12 | ///
13 | /// The containing the binary data to deserialize.
14 | void BinaryDeserialize(FileNode source);
15 |
16 | ///
17 | /// Serializes the binary data of this node as a .
18 | ///
19 | /// A containing the serialized binary data.
20 | FileNode BinarySerialize();
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/lib/Hack.io/Hack.io.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Library
5 | net8.0
6 | {CD2CA20A-E6AD-4B1E-9D04-FB98970B61D5}
7 | enable
8 | disable
9 | False
10 | Hack.io
11 | $(AssemblyTitle)
12 | False
13 | Hack.io
14 | Copyright © 2022-present
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/Benchmark/Benchmarks/ValuesRevers.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 |
3 | namespace Benchmark.Benchmarks
4 | {
5 | [MemoryDiagnoser]
6 | public class ReverseArray
7 | {
8 | private const int n = 10000;
9 |
10 | private const int SIZE = 32;
11 | private readonly byte[] src = new byte[SIZE];
12 |
13 | [Benchmark]
14 | public void ArrayReverse()
15 | {
16 | for (var i = 0; i < n; ++i)
17 | {
18 | for (var offset = 0; offset < SIZE - 1; offset += 4)
19 | {
20 | Array.Reverse(src, offset, 4);
21 | }
22 | }
23 | }
24 |
25 | [Benchmark]
26 | public void SpanSliceReverse()
27 | {
28 | for (var i = 0; i < n; ++i)
29 | {
30 | for (var offset = 0; offset < SIZE - 1; offset += 4)
31 | {
32 | src.AsSpan().Slice(offset, 4).Reverse();
33 | }
34 | }
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Archives/Formats/BUG.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Common.Node;
3 | using AuroraLib.Core.Interfaces;
4 |
5 | namespace AuroraLib.Archives.Formats
6 | {
7 | ///
8 | /// UbiSoft BUG Archive
9 | ///
10 | public class BUG : BIG
11 | {
12 | public override IIdentifier Identifier => _identifier;
13 |
14 | private static readonly Identifier32 _identifier = new((byte)'B', (byte)'U', (byte)'G', 0);
15 |
16 | private static readonly byte[] _key = new[] { (byte)0xB3, (byte)0x98, (byte)0xCC, (byte)0x66 };
17 |
18 | public BUG()
19 | {
20 | }
21 |
22 | public BUG(string name) : base(name)
23 | {
24 | }
25 |
26 | public BUG(FileNode source) : base(source)
27 | {
28 | }
29 |
30 | protected override void Deserialize(Stream ArchiveFile)
31 | {
32 | ArchiveFile.MatchThrow(Identifier);
33 | XORStream stream = new(ArchiveFile, _key);
34 | ReadData(stream);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/AuroraLip/DiscImage/Revolution/HeaderBin.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.DiscImage.Dolphin;
2 |
3 | namespace AuroraLib.DiscImage.Revolution
4 | {
5 | public class HeaderBin : GameHeader
6 | {
7 | ///
8 | /// 'False' don't work on retail consoles
9 | ///
10 | public bool UseVerification;
11 |
12 | ///
13 | /// 'False' don't work on retail consoles
14 | ///
15 | public bool UseEncryption;
16 |
17 | public HeaderBin(Stream source) : base(source)
18 | { }
19 |
20 | protected override void ReadData(Stream dest)
21 | {
22 | GameName = dest.ReadString(64);
23 | UseVerification = dest.ReadUInt8() == 0;
24 | UseEncryption = dest.ReadUInt8() == 0;
25 | }
26 |
27 | protected override void WriteData(Stream dest)
28 | {
29 | dest.WriteString(GameName, 64, 0);
30 | dest.WriteByte((byte)(UseVerification ? 0 : 1));
31 | dest.WriteByte((byte)(UseEncryption ? 0 : 1));
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/Enums/GXFilterMode.cs:
--------------------------------------------------------------------------------
1 | namespace AuroraLib.Texture
2 | {
3 | ///
4 | /// FilterMode specifies what type of filtering the file should use for min/mag.
5 | ///
6 | public enum GXFilterMode : byte
7 | {
8 | ///
9 | /// Point Sampling, No Mipmap
10 | ///
11 | Nearest = 0x00,
12 |
13 | ///
14 | /// Bilinear Filtering, No Mipmap
15 | ///
16 | Linear = 0x01,
17 |
18 | ///
19 | /// Point Sampling, Discrete Mipmap
20 | ///
21 | NearestMipmapNearest = 0x02,
22 |
23 | ///
24 | /// Bilinear Filtering, Discrete Mipmap
25 | ///
26 | NearestMipmapLinear = 0x03,
27 |
28 | ///
29 | /// Point Sampling, Linear MipMap
30 | ///
31 | LinearMipmapNearest = 0x04,
32 |
33 | ///
34 | /// Trilinear Filtering
35 | ///
36 | LinearMipmapLinear = 0x05
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/BlockFormats/I8Block.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Texture.PixelFormats;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace AuroraLib.Texture.BlockFormats
5 | {
6 | ///
7 | /// Represents a block of I8 (Intensity 8-bit) pixels. Each block has a size of 8x4 pixels.
8 | ///
9 | public readonly struct I8Block : IBlock
10 | {
11 | ///
12 | public int BlockWidth => 8;
13 |
14 | ///
15 | public int BlockHeight => 4;
16 |
17 | ///
18 | public int BitsPerPixel => 8;
19 |
20 | ///
21 | public void DecodeBlock(ReadOnlySpan data, Span pixels)
22 | {
23 | ReadOnlySpan temp = MemoryMarshal.Cast(data);
24 | temp.CopyTo(pixels);
25 | }
26 |
27 | ///
28 | public void EncodeBlock(Span pixels, Span data)
29 | {
30 | ReadOnlySpan temp = MemoryMarshal.Cast(pixels);
31 | temp.CopyTo(data);
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Venomalia
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/lib/AFSLib/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 MaikelChan
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/TextureExtraction tool/LICENSE.TXT:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Venomalia
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/BlockFormats/IA4Block.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Texture.PixelFormats;
2 | using System.Runtime.InteropServices;
3 | using SixLabors.ImageSharp.PixelFormats;
4 |
5 | namespace AuroraLib.Texture.BlockFormats
6 | {
7 | ///
8 | /// Represents a block of IA4 pixels. Each block has a size of 8x4 pixels.
9 | ///
10 | public readonly struct IA4Block : IBlock
11 | {
12 | ///
13 | public int BlockWidth => 8;
14 |
15 | ///
16 | public int BlockHeight => 4;
17 |
18 | ///
19 | public int BitsPerPixel => 8;
20 |
21 | ///
22 | public void DecodeBlock(ReadOnlySpan data, Span pixels)
23 | {
24 | ReadOnlySpan temp = MemoryMarshal.Cast(data);
25 | temp.CopyTo(pixels);
26 | }
27 |
28 | ///
29 | public void EncodeBlock(Span pixels, Span data)
30 | {
31 | ReadOnlySpan temp = MemoryMarshal.Cast(pixels);
32 | temp.CopyTo(data);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/J3D/Enums/LoopMode.cs:
--------------------------------------------------------------------------------
1 | namespace AuroraLib.Texture.J3D
2 | {
3 | public static partial class J3DGraph
4 | {
5 | ///
6 | /// J3D Looping Modes
7 | ///
8 | public enum LoopMode : byte
9 | {
10 | ///
11 | /// Play Once then Stop.
12 | ///
13 | ONCE = 0x00,
14 |
15 | ///
16 | /// Play Once then Stop and reset to the first frame.
17 | ///
18 | ONCERESET = 0x01,
19 |
20 | ///
21 | /// Constantly play the animation.
22 | ///
23 | REPEAT = 0x02,
24 |
25 | ///
26 | /// Play the animation to the end. then reverse the animation and play to the start, then Stop.
27 | ///
28 | ONCEANDMIRROR = 0x03,
29 |
30 | ///
31 | /// Play the animation to the end. then reverse the animation and play to the start, repeat.
32 | ///
33 | REPEATANDMIRROR = 0x04
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/lib/AFSLib/Utils.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 |
3 | namespace AFSLib
4 | {
5 | internal static class Utils
6 | {
7 | internal static uint Pad(uint value, uint alignment)
8 | {
9 | uint mod = value % alignment;
10 | if (mod != 0) return value + (alignment - mod);
11 | else return value;
12 | }
13 |
14 | internal static void FillStreamWithZeroes(Stream stream, uint length)
15 | {
16 | byte[] padding = new byte[length];
17 | stream.Write(padding, 0, (int)length);
18 | }
19 |
20 | internal static void CopySliceTo(this Stream origin, Stream destination, int bytesCount)
21 | {
22 | byte[] buffer = new byte[65536];
23 | int count;
24 |
25 | while ((count = origin.Read(buffer, 0, Math.Min(buffer.Length, bytesCount))) != 0)
26 | {
27 | destination.Write(buffer, 0, count);
28 | bytesCount -= count;
29 | }
30 | }
31 |
32 | internal static string GetStringFromBytes(byte[] bytes)
33 | {
34 | return Encoding.Default.GetString(bytes).Replace("\0", "");
35 | }
36 | }
37 | }
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/Enums/GXPaletteFormat.cs:
--------------------------------------------------------------------------------
1 | namespace AuroraLib.Texture
2 | {
3 | ///
4 | /// PaletteFormat specifies how the data within the palette is stored.
5 | /// Only C4, C8, and C14X2 use palettes. For all other formats the type is zero.
6 | ///
7 | public enum GXPaletteFormat : byte
8 | {
9 | ///
10 | /// The IA8 format is used for storing 8 bit intensity values, along with a separate alpha channel.
11 | /// Greyscale + Alpha - 16 bits/pixel (bpp) | Block Width: 4 | Block height: 4 | Block size: 32 bytes
12 | ///
13 | IA8 = 0x00,
14 |
15 | ///
16 | /// 16 bit color values without alpha. alpha use 0xff.
17 | /// Colour - 16 bits/pixel (bpp) | Block Width: 4 | Block height: 4 | Block size: 32 bytes
18 | ///
19 | RGB565 = 0x01,
20 |
21 | ///
22 | /// It is used for storing either 15 bit color values without alpha, or 12 bit color values with a 3 bit alpha channel.
23 | /// Colour + Alpha - 16 bits/pixel (bpp) | Block Width: 4 | Block height: 4 | Block size: 32 bytes
24 | ///
25 | RGB5A3 = 0x02
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/Formats/TPX.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Core.Interfaces;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace AuroraLib.Texture.Formats
10 | {
11 | public class TPX : JUTTexture, IFileAccess, IHasIdentifier
12 | {
13 | public bool CanRead => true;
14 |
15 | public bool CanWrite => false;
16 |
17 | public virtual IIdentifier Identifier => Magic;
18 |
19 | public static readonly Identifier32 Magic = new(302581280);
20 |
21 | public bool IsMatch(Stream stream, ReadOnlySpan extension = default)
22 | => stream.Length > 12 && stream.Match(Magic) && stream.At(0x100, s => s.Match(TPL.Magic));
23 |
24 | protected override void Read(Stream stream)
25 | {
26 | stream.MatchThrow(Magic);
27 | stream.Position += 252;
28 | long HeaderStart = stream.Position;
29 | stream.MatchThrow(TPL.Magic);
30 | TPL.ProcessStream(stream, HeaderStart, this);
31 | }
32 |
33 | protected override void Write(Stream stream) => throw new NotImplementedException();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Common/Events.cs:
--------------------------------------------------------------------------------
1 | namespace AuroraLib.Common
2 | {
3 | ///
4 | /// Events that make it possible to influence the behavior of the library.
5 | ///
6 | public static class Events
7 | {
8 | ///
9 | /// Event that is called when a process wants to report something.
10 | ///
11 | public static NotificationDelegate NotificationEvent = DefaultNotification;
12 |
13 | ///
14 | /// Represents the method that will handle the NotificationEvent.
15 | ///
16 | /// Type of notification.
17 | /// The notification message.
18 | public delegate void NotificationDelegate(NotificationType type, string message);
19 |
20 | ///
21 | /// Represents the method to request a missing file.
22 | ///
23 | ///
24 | ///
25 | public delegate Stream FileRequestDelegate(string Name);
26 |
27 | private static void DefaultNotification(NotificationType type, string message)
28 | => Console.WriteLine($"{type}: {message}");
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/lib/AuroraLip/DiscImage/Revolution/WiiKey.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 |
3 | namespace AuroraLib.DiscImage.Revolution
4 | {
5 | public static class WiiKey
6 | {
7 | ///
8 | /// Wii Common Key
9 | ///
10 | public static readonly byte[] CKey = new byte[] { 176, 123, 5, 203, 217, 74, 35, 21, 134, 80, 232, 7, 220, 219, 48, 86 };
11 |
12 | ///
13 | /// Wii Korean Common Key
14 | ///
15 | public static readonly byte[] KKey = new byte[] { 108, 141, 91, 182, 36, 20, 57, 157, 189, 2, 191, 156, 37, 193, 106, 141 };
16 |
17 | ///
18 | /// vWii Common Key
19 | ///
20 | public static readonly byte[] VKey = new byte[] { 118, 189, 189, 122, 244, 60, 10, 171, 19, 1, 75, 60, 41, 170, 112, 86 };
21 |
22 | ///
23 | /// Generates the keys
24 | ///
25 | static WiiKey()
26 | {
27 | byte[] gKey = MiscEX.RKey(42, 16);
28 | byte[] gIV = MiscEX.RKey(13, 16);
29 | MiscEX.AESDecrypt(CKey, gKey, gIV);
30 | MiscEX.AESDecrypt(KKey, gKey, gIV);
31 | MiscEX.AESDecrypt(VKey, gKey, gIV);
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/TextureExtraction tool/Scans/Results/ScanResults.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace DolphinTextureExtraction.Scans.Results
8 | {
9 | public class ScanResults
10 | {
11 | ///
12 | /// the time the scan process has taken
13 | ///
14 | public TimeSpan TotalTime { get; internal set; }
15 |
16 | ///
17 | ///
18 | ///
19 | public bool IsCompleted { get; internal set; }
20 |
21 | ///
22 | /// Size of all files to be searched in bytes.
23 | ///
24 | public double WorkeLength { get; internal set; }
25 |
26 | ///
27 | /// Size of all already searched files in bytes.
28 | ///
29 | public double ProgressLength { get; internal set; } = 0;
30 |
31 | ///
32 | /// Full path to the log file.
33 | ///
34 | public string LogFullPath { get; internal set; }
35 |
36 | public override string ToString()
37 | {
38 | StringBuilder sb = new();
39 | sb.AppendLine($"Scan time: {TotalTime.TotalSeconds:.000}s");
40 | return sb.ToString();
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/BlockFormats/IA8Block.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Texture.PixelFormats;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace AuroraLib.Texture.BlockFormats
5 | {
6 | ///
7 | /// Represents a block of IA8 pixels. Each block has a size of 4x4 pixels.
8 | ///
9 | public readonly struct IA8Block : IBlock
10 | {
11 | ///
12 | public int BlockWidth => 4;
13 |
14 | ///
15 | public int BlockHeight => 4;
16 |
17 | ///
18 | public int BitsPerPixel => 16;
19 |
20 | ///
21 | public void DecodeBlock(ReadOnlySpan data, Span pixels)
22 | {
23 | for (int i = 0; i < pixels.Length; i++)
24 | {
25 | pixels[i] = MemoryMarshal.AsRef(data.Slice(i * 2, 2));
26 | pixels[i].PackedValue = BitConverterX.Swap(pixels[i].PackedValue);
27 | }
28 | }
29 |
30 | ///
31 | public void EncodeBlock(Span pixels, Span data)
32 | {
33 | for (int i = 0; i < pixels.Length; i++)
34 | {
35 | ushort value = BitConverterX.Swap(pixels[i].PackedValue);
36 | MemoryMarshal.Write(data.Slice(i * 2, 2), ref value);
37 | }
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/lib/AuroraLip/DiscImage/Revolution/CMD.cs:
--------------------------------------------------------------------------------
1 | namespace AuroraLib.DiscImage.Revolution
2 | {
3 | public class CMD
4 | {
5 | public uint ContentId;
6 | public ushort Index;
7 | public ContentType Type;
8 | public ulong Size;
9 | public readonly byte[] Hash = new byte[20];
10 |
11 | public CMD(Stream stream)
12 | {
13 | ContentId = stream.ReadUInt32(Endian.Big);
14 | Index = stream.ReadUInt16(Endian.Big);
15 | Type = stream.Read(Endian.Big);
16 | Size = stream.ReadUInt64(Endian.Big);
17 | stream.Read(Hash);
18 | }
19 |
20 | public void Write(Stream dest)
21 | {
22 | dest.Write(ContentId, Endian.Big);
23 | dest.Write(Index, Endian.Big);
24 | dest.Write(Type, Endian.Big);
25 | dest.Write(Size, Endian.Big);
26 | dest.Write(Hash);
27 | }
28 |
29 | public enum ContentType : ushort
30 | {
31 | Normal = 0x0001,
32 | DLC = 0x4001,
33 | Shared = 0x8001,
34 | }
35 |
36 | public byte[] GetContentIV()
37 | {
38 | byte[] iv_bits = BitConverter.GetBytes(Index);
39 | byte[] iv = new byte[16];
40 | iv[0] = iv_bits[1];
41 | iv[1] = iv_bits[0];
42 | return iv;
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/BlockFormats/RGB565Block.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Texture.PixelFormats;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace AuroraLib.Texture.BlockFormats
5 | {
6 | ///
7 | /// Represents a block of RGB565 pixels. Each block has a size of 4x4 pixels.
8 | ///
9 | public readonly struct RGB565Block : IBlock
10 | {
11 | ///
12 | public int BlockWidth => 4;
13 |
14 | ///
15 | public int BlockHeight => 4;
16 |
17 | ///
18 | public int BitsPerPixel => 16;
19 |
20 | ///
21 | public void DecodeBlock(ReadOnlySpan data, Span pixels)
22 | {
23 | for (int i = 0; i < pixels.Length; i++)
24 | {
25 | pixels[i] = MemoryMarshal.AsRef(data.Slice(i * 2, 2));
26 | pixels[i].PackedValue = BitConverterX.Swap(pixels[i].PackedValue);
27 | }
28 | }
29 |
30 | ///
31 | public void EncodeBlock(Span pixels, Span data)
32 | {
33 | for (int i = 0; i < pixels.Length; i++)
34 | {
35 | ushort value = BitConverterX.Swap(pixels[i].PackedValue);
36 | MemoryMarshal.Write(data.Slice(i * 2, 2), ref value);
37 | }
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/BlockFormats/RGB5A3Block.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Texture.PixelFormats;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace AuroraLib.Texture.BlockFormats
5 | {
6 | ///
7 | /// Represents a block of RGB5A3 pixels. Each block has a size of 4x4 pixels.
8 | ///
9 | public readonly struct RGB5A3Block : IBlock
10 | {
11 | ///
12 | public int BlockWidth => 4;
13 |
14 | ///
15 | public int BlockHeight => 4;
16 |
17 | ///
18 | public int BitsPerPixel => 16;
19 |
20 | ///
21 | public void DecodeBlock(ReadOnlySpan data, Span pixels)
22 | {
23 | for (int i = 0; i < pixels.Length; i++)
24 | {
25 | pixels[i] = MemoryMarshal.AsRef(data.Slice(i * 2, 2));
26 | pixels[i].PackedValue = BitConverterX.Swap(pixels[i].PackedValue);
27 | }
28 | }
29 |
30 | ///
31 | public void EncodeBlock(Span pixels, Span data)
32 | {
33 | for (int i = 0; i < pixels.Length; i++)
34 | {
35 | ushort value = BitConverterX.Swap(pixels[i].PackedValue);
36 | MemoryMarshal.Write(data.Slice(i * 2, 2), ref value);
37 | }
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/lib/AuroraLip/DiscImage/RVZ/RVZVersion.cs:
--------------------------------------------------------------------------------
1 | namespace AuroraLib.DiscImage.RVZ
2 | {
3 | public readonly struct RvzVersion : IComparable
4 | {
5 | public readonly byte Major;
6 | public readonly byte Minor;
7 | public readonly byte Build;
8 | private readonly byte beta;
9 |
10 | public RvzVersion(byte major, byte minor = 0, byte build = 0, byte beta = 0)
11 | {
12 | Major = major;
13 | Minor = minor;
14 | Build = build;
15 | this.beta = beta;
16 | }
17 |
18 | public readonly bool IsBeta => beta != 0x00 && beta != 0xff;
19 |
20 | public override string ToString()
21 | {
22 | string versionString = Build == 0 ? $"{Major}.{Minor}" : $"{Major}.{Minor}.{Build}";
23 | if (IsBeta)
24 | {
25 | versionString += $" beta {beta}";
26 | }
27 | return versionString;
28 | }
29 |
30 | public unsafe int CompareTo(RvzVersion other)
31 | {
32 | if (Major != other.Major)
33 | return Major.CompareTo(other.Major);
34 | if (Minor != other.Minor)
35 | return Minor.CompareTo(other.Minor);
36 | if (Build != other.Build)
37 | return Build.CompareTo(other.Build);
38 | return beta.CompareTo(other.beta);
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Common/Extensions/MiscEX.cs:
--------------------------------------------------------------------------------
1 | using System.Security.Cryptography;
2 |
3 | namespace AuroraLib.Common
4 | {
5 | public static class MiscEX
6 | {
7 | public static byte[] RKey(int value, int length)
8 | {
9 | byte[] data = new byte[length];
10 | new Random(value).NextBytes(data);
11 | return data;
12 | }
13 |
14 | public static void AESDecrypt(byte[] cipherData, byte[] key, byte[] IV, CipherMode cipherMode = CipherMode.CBC, PaddingMode paddingMode = PaddingMode.Zeros)
15 | {
16 | Aes aes = Aes.Create();
17 | aes.KeySize = key.Length * 8;
18 | aes.Mode = cipherMode;
19 | aes.Padding = paddingMode;
20 | aes.Key = key;
21 | aes.IV = IV;
22 | aes.CreateDecryptor().TransformBlock(cipherData, 0, cipherData.Length, cipherData,0);
23 | }
24 |
25 | public static void AESEncrypt(byte[] cipherData, byte[] key, byte[] IV, CipherMode cipherMode = CipherMode.CBC, PaddingMode paddingMode = PaddingMode.Zeros)
26 | {
27 | Aes aes = Aes.Create();
28 | aes.KeySize = key.Length * 8;
29 | aes.Mode = cipherMode;
30 | aes.Padding = paddingMode;
31 | aes.Key = key;
32 | aes.IV = IV;
33 | aes.CreateEncryptor().TransformBlock(cipherData, 0, cipherData.Length, cipherData, 0);
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | end_of_line = lf
6 | indent_style = space
7 | insert_final_newline = true
8 | trim_trailing_whitespace = true
9 |
10 | [*.{sln,csproj}]
11 | end_of_line = crlf
12 | charset = utf-8-bom
13 |
14 | [*.sln]
15 | indent_style = tab
16 |
17 | [*.csproj]
18 | indent_style = space
19 | indent_size = 2
20 |
21 | [*.cs]
22 | indent_size = 4
23 | csharp_style_var_elsewhere = false:none
24 | csharp_style_var_for_built_in_types = false:suggestion
25 | csharp_style_var_when_type_is_apparent = false:suggestion
26 | csharp_prefer_braces = when_multiline:suggestion
27 | csharp_style_expression_bodied_methods = when_on_single_line:suggestion
28 | csharp_style_expression_bodied_constructors = when_on_single_line:suggestion
29 | csharp_style_expression_bodied_operators = when_on_single_line:suggestion
30 | csharp_style_expression_bodied_properties = when_on_single_line:suggestion
31 | csharp_style_expression_bodied_indexers = when_on_single_line:suggestion
32 | csharp_style_expression_bodied_accessors = when_on_single_line:suggestion
33 | csharp_style_expression_bodied_lambdas = when_on_single_line:suggestion
34 | csharp_style_expression_bodied_local_functions = when_on_single_line:suggestion
35 | csharp_new_line_before_open_brace = all
36 | csharp_style_unused_value_assignment_preference = unused_local_variable:suggestion
37 |
38 | # IDE0058: Expression value is never used
39 | dotnet_diagnostic.IDE0058.severity = none
40 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/BlockFormats/I4Block.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Texture.PixelFormats;
2 |
3 | namespace AuroraLib.Texture.BlockFormats
4 | {
5 | ///
6 | /// Represents a block of I4 (Intensity 4-bit) pixels. Each block has a size of 8x8 pixels.
7 | ///
8 | public readonly struct I4Block : IBlock
9 | {
10 | ///
11 | public int BlockWidth => 8;
12 |
13 | ///
14 | public int BlockHeight => 8;
15 |
16 | ///
17 | public int BitsPerPixel => 4;
18 |
19 | ///
20 | public void DecodeBlock(ReadOnlySpan data, Span pixels)
21 | {
22 | for (int i = 0; i < data.Length; i++)
23 | {
24 | pixels[i * 2].PackedValue = (byte)((data[i] & 0xF0) | (data[i] >> 4));
25 | pixels[i * 2 + 1].PackedValue = (byte)((data[i] << 4) | (data[i] & 0x0F));
26 | }
27 | }
28 |
29 | ///
30 | public void EncodeBlock(Span pixels, Span data)
31 | {
32 | for (int i = 0; i < data.Length; i++)
33 | {
34 | byte highNibble = (byte)(pixels[i * 2].PackedValue & 0x0F);
35 | byte lowNibble = (byte)(pixels[i * 2 + 1].PackedValue & 0x0F);
36 | data[i] = (byte)((highNibble << 4) | lowNibble);
37 | }
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/lib/LibCPK/README.md:
--------------------------------------------------------------------------------
1 | CriPakTools-mod
2 | ===========
3 | forked from uyjulian/CriPakTools
4 |
5 | This tool is based off of code by Falo , Nanashi3 ,esperknight and uyjulian
6 |
7 | I forked and added batch reimport and compress code .
8 |
9 | Thanks for KenTse 's CRILAYLA compression method
10 |
11 |
12 | * Add Batch Mode
13 | * Add compression option
14 | * Fix GTOC & ETOC
15 | * Fix CPK header
16 |
17 | * Still need to do:
18 | * Add GUI
19 |
20 |
21 |
22 | ===========
23 |
24 | Tool to extract/update contents of CRIWARE's CPK archive format. (aka CRI FileMajik)
25 | This is based off of code uploaded by Falo's code released on the Xentax forums (http://forum.xentax.com/viewtopic.php?f=10&t=10646) which was futher modified by Nanashi3 (http://forums.fuwanovel.org/index.php?/topic/1785-request-for-psp-hackers/page-4), which is then further modified by esperknight (https://github.com/esperknight/CriPakTools).
26 | I cleaned up the command line flags and enable to extract 0 byte CRILAYLA compressed files.
27 | If something breaks, open an issue.
28 | To print out options see CriPackTools -h
29 |
30 | Compiling
31 | =========
32 | Change directory to where the `CriPakTools.sln` file is located, then run `xbuild` if you have Mono. Output file should be in `CriPakTools/bin/CriPackTools.exe`. Otherwise, just open the `CriPakTools.sln` file in Visual Studio 2013 and build.
33 |
34 | TODO:
35 | * Add more error checking
36 | * Clean up code
37 | * Add option to create an archive
38 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Palette/Formats/PLT0.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Core.Interfaces;
3 | using AuroraLib.Texture;
4 |
5 | namespace AuroraLib.Palette.Formats
6 | {
7 | public class PLT0 : IHasIdentifier, IJUTPalette
8 | {
9 | public GXPaletteFormat Format { get; set; }
10 |
11 | public byte[] Data { get; set; }
12 |
13 | public virtual IIdentifier Identifier => _identifier;
14 |
15 | private static readonly Identifier32 _identifier = new("PLT0");
16 |
17 | public PLT0(Stream stream) => Read(stream);
18 |
19 | protected void Read(Stream stream)
20 | {
21 | stream.MatchThrow(_identifier);
22 | uint TotalSize = stream.ReadUInt32(Endian.Big);
23 | uint FormatVersion = stream.ReadUInt32(Endian.Big);
24 | uint Offset = stream.ReadUInt32(Endian.Big);
25 |
26 | uint SectionOffsets = stream.ReadUInt32(Endian.Big);
27 | uint StringOffset = stream.ReadUInt32(Endian.Big);
28 | Format = (GXPaletteFormat)stream.ReadUInt32(Endian.Big);
29 | short colors = stream.ReadInt16(Endian.Big);
30 | ushort pad = stream.ReadUInt16(Endian.Big);
31 | uint PathOffset = stream.ReadUInt32(Endian.Big);
32 | uint DataOffset = stream.ReadUInt32(Endian.Big);
33 | stream.Seek(SectionOffsets, SeekOrigin.Begin);
34 | Data = new byte[colors * 2];
35 | stream.Read(Data);
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/BlockFormats/I14Block.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Texture.PixelFormats;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace AuroraLib.Texture.BlockFormats
5 | {
6 | ///
7 | /// Represents a block of I14 (Intensity 14-bit) pixels. Each block has a size of 8x4 pixels.
8 | ///
9 | public readonly struct I14Block : IBlock
10 | {
11 | ///
12 | public int BlockWidth => 4;
13 |
14 | ///
15 | public int BlockHeight => 4;
16 |
17 | ///
18 | public int BitsPerPixel => 16;
19 |
20 | ///
21 | public void DecodeBlock(ReadOnlySpan data, Span pixels)
22 | {
23 | for (int i = 0; i < pixels.Length; i++)
24 | {
25 | pixels[i] = MemoryMarshal.AsRef(data.Slice(i * 2, 2));
26 | pixels[i].PackedValue = BitConverterX.Swap(pixels[i].PackedValue);
27 | pixels[i].PackedValue &= 0x3FFF;
28 | }
29 | }
30 |
31 | ///
32 | public void EncodeBlock(Span pixels, Span data)
33 | {
34 | for (int i = 0; i < pixels.Length; i++)
35 | {
36 | pixels[i].PackedValue &= 0x3FFF;
37 | ushort value = BitConverterX.Swap(pixels[i].PackedValue);
38 | MemoryMarshal.Write(data.Slice(i * 2, 2), ref value);
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Archives/Formats/CMN.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Common.Node;
3 | using System;
4 |
5 | namespace AuroraLib.Archives.Formats
6 | {
7 | ///
8 | /// Treyarch CMN Archive.
9 | ///
10 | public sealed class CMN : ArchiveNode
11 | {
12 | public override bool CanWrite => false;
13 |
14 | public CMN()
15 | {
16 | }
17 |
18 | public CMN(string name) : base(name)
19 | {
20 | }
21 |
22 | public CMN(FileNode source) : base(source)
23 | {
24 | }
25 |
26 | public override bool IsMatch(Stream stream, ReadOnlySpan extension = default)
27 | => extension.Contains(".cmn", StringComparison.InvariantCultureIgnoreCase) && stream.ReadUInt32() < 2048 && stream.ReadUInt32() != 0;
28 |
29 | protected override void Deserialize(Stream source)
30 | {
31 | uint files = source.ReadUInt32();
32 | for (int i = 0; i < files; i++)
33 | {
34 | FileEntrie entrie = source.Read();
35 | Add(new FileNode($"File_{i}_{entrie.Type}_{entrie.Hash}", new SubStream(source, entrie.Size, entrie.Offset)));
36 | }
37 | }
38 |
39 | protected override void Serialize(Stream dest) => throw new NotImplementedException();
40 |
41 | private struct FileEntrie
42 | {
43 | public uint Hash; // ?
44 | public uint Type; //0x0 - 0x1
45 | public uint Offset;
46 | public uint Size;
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Benchmark/Benchmarks/CopyByte.cs:
--------------------------------------------------------------------------------
1 | using BenchmarkDotNet.Attributes;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace Benchmark.Benchmarks
5 | {
6 | [MemoryDiagnoser]
7 | public class CopyByte
8 | {
9 | private const int n = 10000;
10 |
11 | private const int SIZE = 32;
12 | private readonly byte[] src = new byte[SIZE];
13 | private readonly byte[] dst = new byte[SIZE];
14 |
15 | [Benchmark]
16 | public void ArrayCopy()
17 | {
18 | for (var i = 0; i < n; ++i)
19 | {
20 | Array.Copy(src, dst, SIZE);
21 | }
22 | }
23 |
24 | [Benchmark]
25 | public void SpanCopyTo()
26 | {
27 | for (var i = 0; i < n; ++i)
28 | {
29 | src.AsSpan().CopyTo(dst.AsSpan());
30 | }
31 | }
32 |
33 | [Benchmark]
34 | public void BufferBlockCopy()
35 | {
36 | for (var i = 0; i < n; ++i)
37 | {
38 | Buffer.BlockCopy(src, 0, dst, 0, SIZE);
39 | }
40 | }
41 |
42 | [Benchmark]
43 | public void MarshalCopy()
44 | {
45 | for (var i = 0; i < n; ++i)
46 | {
47 | GCHandle handle = GCHandle.Alloc(dst, GCHandleType.Pinned);
48 | try
49 | {
50 | IntPtr rawDataPtr = handle.AddrOfPinnedObject();
51 | Marshal.Copy(src, 0, rawDataPtr, SIZE);
52 | }
53 | finally
54 | {
55 | handle.Free();
56 | }
57 | }
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Archives/Formats/pBin.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common.Node;
2 | using AuroraLib.Core.Interfaces;
3 |
4 | namespace AuroraLib.Archives.Formats
5 | {
6 | ///
7 | /// Natsume Harvest Moon: Animal Parade Archive
8 | ///
9 | public sealed class PBin : ArchiveNode, IHasIdentifier
10 | {
11 | public override bool CanWrite => false;
12 |
13 | public IIdentifier Identifier => _identifier;
14 |
15 | private static readonly Identifier32 _identifier = new("pBin");
16 |
17 | public override bool IsMatch(Stream stream, ReadOnlySpan extension = default)
18 | => stream.Match(_identifier);
19 |
20 | protected override void Deserialize(Stream source)
21 | {
22 | source.MatchThrow(_identifier);
23 |
24 | uint unknown1 = source.ReadUInt32(Endian.Big);
25 | uint unknown2 = source.ReadUInt32(Endian.Big);
26 | uint unknown3 = source.ReadUInt32(Endian.Big);
27 | uint unknown4 = source.ReadUInt32(Endian.Big);
28 | uint count = source.ReadUInt32(Endian.Big);
29 |
30 | for (int i = 0; i < count; i++)
31 | {
32 | uint size = source.ReadUInt32(Endian.Big);
33 | uint offset = source.ReadUInt32(Endian.Big);
34 | string type = source.ReadString(4);
35 | uint unknown = source.ReadUInt32(Endian.Big);
36 | FileNode file = new($"Entry{i}_{type}", new SubStream(source, size, offset));
37 | Add(file);
38 | }
39 | }
40 |
41 | protected override void Serialize(Stream dest) => throw new NotImplementedException();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Archives/Formats/ONE_UN.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Common.Node;
3 | using AuroraLib.Core.Interfaces;
4 |
5 | namespace AuroraLib.Archives.Formats
6 | {
7 | ///
8 | /// Archive use in Sonic Unleashed
9 | ///
10 | public sealed class ONE_UN : ArchiveNode, IHasIdentifier
11 | {
12 | public override bool CanWrite => false;
13 |
14 | public IIdentifier Identifier => _identifier;
15 |
16 | private static readonly Identifier32 _identifier = new("one.");
17 |
18 | public ONE_UN()
19 | {
20 | }
21 |
22 | public ONE_UN(string name) : base(name)
23 | {
24 | }
25 |
26 | public ONE_UN(FileNode source) : base(source)
27 | {
28 | }
29 |
30 | public override bool IsMatch(Stream stream, ReadOnlySpan extension = default)
31 | => stream.Match(_identifier) && stream.At(4, S => stream.ReadUInt32()) <= 1024 * 4;
32 |
33 | protected override void Deserialize(Stream source)
34 | {
35 | source.MatchThrow(_identifier);
36 |
37 | uint numEntries = source.ReadUInt32();
38 | for (int i = 0; i < numEntries; i++)
39 | {
40 | string entryFilename = source.ReadString(56);
41 | uint entryOffset = source.ReadUInt32();
42 | uint entryLength = source.ReadUInt32();
43 |
44 | FileNode Sub = new(entryFilename, new SubStream(source, entryLength, entryOffset));
45 | Add(Sub);
46 | }
47 | }
48 |
49 | protected override void Serialize(Stream dest) => throw new NotImplementedException();
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/lib/AuroraLip/DiscImage/RVZ/Header.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Core.Interfaces;
2 | using System.Buffers;
3 |
4 | namespace AuroraLib.DiscImage.RVZ
5 | {
6 | public class Header : IBinaryObject
7 | {
8 | public ImageType Magic;
9 | public RvzVersion Version;
10 | public RvzVersion VersionCompatible;
11 | public uint DiscTSize;
12 | public readonly byte[] DiscHash;
13 | public long IsoFileSize;
14 | public long ThisFileSize;
15 | public readonly byte[] HeaderHash;
16 |
17 | public Header()
18 | {
19 | DiscHash = new byte[0x14];
20 | HeaderHash = new byte[0x14];
21 | }
22 |
23 | public Header(Stream source) : this() => BinaryDeserialize(source);
24 |
25 | public void BinaryDeserialize(Stream source)
26 | {
27 | Magic = source.Read(Endian.Big);
28 | Version = source.Read(Endian.Big);
29 | VersionCompatible = source.Read(Endian.Big);
30 | DiscTSize = source.Read(Endian.Big);
31 | source.Read(DiscHash);
32 | IsoFileSize = source.Read(Endian.Big);
33 | ThisFileSize = source.Read(Endian.Big);
34 | source.Read(HeaderHash);
35 | }
36 |
37 | public void BinarySerialize(Stream dest)
38 | {
39 | dest.Write(Magic);
40 | dest.Write(Version);
41 | dest.Write(VersionCompatible);
42 | dest.Write(DiscTSize);
43 | dest.Write(DiscHash);
44 | dest.Write(IsoFileSize);
45 | dest.Write(ThisFileSize);
46 | dest.Write(HeaderHash);
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/TextureExtraction tool/Scans/Options/TextureExtractorOptions.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Texture;
2 | using DolphinTextureExtraction.Scans.Results;
3 | using System.Text;
4 |
5 | namespace DolphinTextureExtraction.Scans.Options
6 | {
7 | public class TextureExtractorOptions : ScanOptions
8 | {
9 | ///
10 | /// Should Mipmaps files be extracted?
11 | ///
12 | public bool Mips = AppSettings.Mips;
13 |
14 | ///
15 | /// use Arbitrary Mipmap Detection.
16 | ///
17 | public bool ArbitraryMipmapDetection = AppSettings.ArbitraryMipmapDetection;
18 |
19 | ///
20 | /// Extracts all raw images that are found
21 | ///
22 | public bool Raw = AppSettings.Raw;
23 |
24 | ///
25 | /// Tries to Imitate dolphin mipmap detection.
26 | ///
27 | public bool DolphinMipDetection = AppSettings.DolphinMipDetection;
28 |
29 | ///
30 | /// Combine texture pairs to get an RGBA texture.
31 | ///
32 | public bool CombinedRGBA = AppSettings.CombinedRGBA;
33 |
34 | public override string ToString()
35 | {
36 | StringBuilder sb = new();
37 | ToString(sb);
38 | sb.Append(", Enable Mips:");
39 | sb.Append(Mips);
40 | sb.Append(", Raw:");
41 | sb.Append(Raw);
42 | sb.Append(", DolphinMipDetection:");
43 | sb.Append(DolphinMipDetection);
44 | sb.Append(", ArbitraryMipmapDetection:");
45 | sb.Append(ArbitraryMipmapDetection);
46 | return sb.ToString();
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Archives/Formats/TXAG.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Common.Node;
3 | using AuroraLib.Core.Interfaces;
4 |
5 | namespace AuroraLib.Archives.Formats
6 | {
7 | public sealed class TXAG : ArchiveNode, IHasIdentifier
8 | {
9 | public override bool CanWrite => false;
10 |
11 | public IIdentifier Identifier => _identifier;
12 |
13 | private static readonly Identifier32 _identifier = new("TXAG");
14 |
15 | public TXAG()
16 | {
17 | }
18 |
19 | public TXAG(string name) : base(name)
20 | {
21 | }
22 |
23 | public TXAG(FileNode source) : base(source)
24 | {
25 | }
26 |
27 | public override bool IsMatch(Stream stream, ReadOnlySpan extension = default)
28 | => stream.Match(_identifier);
29 |
30 | protected override void Deserialize(Stream source)
31 | {
32 | source.MatchThrow(_identifier);
33 |
34 | ushort unk = source.ReadUInt16(Endian.Big);
35 | ushort fileCount = source.ReadUInt16(Endian.Big);
36 |
37 | for (int i = 0; i < fileCount; i++)
38 | {
39 | uint offset = source.ReadUInt32(Endian.Big);
40 | uint length = source.ReadUInt32(Endian.Big);
41 | string fileName = source.ReadString(32);
42 |
43 | if (string.IsNullOrWhiteSpace(fileName))
44 | fileName = $"entry{i}.GVR";
45 |
46 | FileNode file = new(fileName, new SubStream(source, length, offset));
47 | Add(file);
48 | }
49 | }
50 |
51 | protected override void Serialize(Stream dest) => throw new NotImplementedException();
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/BlockFormats/RGBA32Block.cs:
--------------------------------------------------------------------------------
1 | using SixLabors.ImageSharp.PixelFormats;
2 |
3 | namespace AuroraLib.Texture.BlockFormats
4 | {
5 | ///
6 | /// Represents a block of RGBA32 pixels. Each block has a size of 4x4 pixels.
7 | /// The 64-byte block is organized in a zigzag pattern.
8 | ///
9 | public readonly struct RGBA32Block : IBlock
10 | {
11 | ///
12 | public int BlockWidth => 4;
13 |
14 | ///
15 | public int BlockHeight => 4;
16 |
17 | ///
18 | public int BitsPerPixel => 32;
19 |
20 | /*
21 | * The pixel data is separated into two groups:
22 | * A and R are encoded in the first group, and G and B are encoded in the second group.
23 | * The data is organized as follows:
24 | * ARARARARARARARAR
25 | * ARARARARARARARAR
26 | * GBGBGBGBGBGBGBGB
27 | * GBGBGBGBGBGBGBGB
28 | */
29 |
30 | ///
31 | public void DecodeBlock(ReadOnlySpan data, Span pixels)
32 | {
33 | for (int i = 0; i < pixels.Length; i++)
34 | pixels[i] = new Rgba32(data[(i * 2) + 1], data[(i * 2) + 32], data[(i * 2) + 33], data[(i * 2)]);
35 | }
36 |
37 | ///
38 | public void EncodeBlock(Span pixels, Span data)
39 | {
40 | for (int i = 0; i < pixels.Length; i++)
41 | {
42 | data[i * 2] = pixels[i].A;
43 | data[(i * 2) + 01] = pixels[i].R;
44 | data[(i * 2) + 32] = pixels[i].G;
45 | data[(i * 2) + 33] = pixels[i].B;
46 | }
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/Formats/FIPAFTEX.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Core.Exceptions;
3 | using AuroraLib.Core.Interfaces;
4 |
5 | namespace AuroraLib.Texture.Formats
6 | {
7 | // The actual file type is likely 'FIPA'
8 | // with a switch on subtypes (ex: 'FTEX')
9 | // but that would be more complicated
10 | // to deal with!
11 | public class FIPAFTEX : JUTTexture, IFileAccess, IHasIdentifier
12 | {
13 | public bool CanRead => true;
14 |
15 | public bool CanWrite => false;
16 |
17 | public IIdentifier Identifier => magic;
18 |
19 | private static readonly Identifier64 magic = new("FIPAFTEX");
20 |
21 | public static bool Matcher(Stream stream, ReadOnlySpan extension = default)
22 | {
23 | if (!stream.Match(magic))
24 | return false;
25 |
26 | return true;
27 | }
28 |
29 | public bool IsMatch(Stream stream, ReadOnlySpan extension = default)
30 | => Matcher(stream, extension);
31 |
32 | protected override void Read(Stream stream)
33 | {
34 | stream.MatchThrow(magic);
35 |
36 | // These files contain one or more TPLs
37 | // so we use a helper function to parse the TPL
38 | // after finding the start of the stream
39 | while (stream.Search(TPL.Magic.AsSpan().ToArray()))
40 | {
41 | long HeaderStart = stream.Position;
42 | stream.Skip(4); // skip TPL magic
43 | TPL.ProcessStream(stream, HeaderStart, this);
44 | }
45 | }
46 |
47 | protected override void Write(Stream ArchiveFile)
48 | {
49 | throw new NotImplementedException();
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Archives/Formats/RVZ.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Archives.Formats.Nintendo;
2 | using AuroraLib.Core.Interfaces;
3 | using AuroraLib.DiscImage.Dolphin;
4 | using AuroraLib.DiscImage.Revolution;
5 | using AuroraLib.DiscImage.RVZ;
6 |
7 | namespace AuroraLib.Archives.Formats
8 | {
9 | public sealed partial class RVZ : WiiDisk, IHasIdentifier
10 | {
11 | public override bool CanWrite => false;
12 |
13 | public IIdentifier Identifier => _identifier;
14 |
15 | private static readonly Identifier32 _identifier = new(82, 86, 90, 1);
16 |
17 | private RvzStream rvzStream;
18 |
19 | public new GameHeader Header { get => header; set => header = value; }
20 |
21 | public override bool IsMatch(Stream stream, ReadOnlySpan extension = default)
22 | => stream.Match(_identifier);
23 |
24 | protected override void Deserialize(Stream source)
25 | {
26 | rvzStream = new(source);
27 | if (rvzStream.RVZDiscT.DiscType == DiscTypes.GameCube)
28 | {
29 | ProcessData(rvzStream, this);
30 | }
31 | else
32 | {
33 | Header = new HeaderBin(rvzStream)
34 | {
35 | UseVerification = false,
36 | UseEncryption = false
37 | };
38 | ProcessPartitionData(rvzStream);
39 | }
40 | }
41 |
42 | protected override void Serialize(Stream dest) => throw new NotImplementedException();
43 |
44 | protected override void Dispose(bool disposing)
45 | {
46 | base.Dispose(disposing);
47 | if (disposing)
48 | {
49 | rvzStream?.Dispose();
50 | }
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Archives/Formats/MEDB.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Common.Node;
3 | using AuroraLib.Core.Interfaces;
4 |
5 | namespace AuroraLib.Archives.Formats
6 | {
7 | ///
8 | /// Rune Factory (Tides) archive format
9 | ///
10 | public sealed class MEDB : ArchiveNode, IHasIdentifier
11 | {
12 | public override bool CanWrite => false;
13 |
14 | public IIdentifier Identifier => _identifier;
15 |
16 | private static readonly Identifier32 _identifier = new("MEDB");
17 |
18 | public override bool IsMatch(Stream stream, ReadOnlySpan extension = default)
19 | => stream.Match(_identifier);
20 |
21 | protected override void Deserialize(Stream source)
22 | {
23 | source.MatchThrow(_identifier);
24 |
25 | // We know there are textures here, just search for them
26 | while (source.Search("HXTB"))
27 | {
28 | long entrystart = source.Position;
29 | if (!source.Match("HXTB"))
30 | continue;
31 | source.Seek(0x14, SeekOrigin.Current);
32 | uint total_size = source.ReadUInt32(Endian.Big);
33 |
34 | if (total_size > source.Length - entrystart)
35 | {
36 | source.Search("HXTB");
37 | total_size = (uint)(source.Position - entrystart);
38 | }
39 |
40 | FileNode Sub = new($"entry_{Count + 1}.hxtb", new SubStream(source, total_size, entrystart));
41 | Add(Sub);
42 |
43 | source.Position = entrystart + total_size;
44 | }
45 | }
46 |
47 | protected override void Serialize(Stream dest) => throw new NotImplementedException();
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/Formats/S3G.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 |
3 | namespace AuroraLib.Texture.Formats
4 | {
5 | public class S3G : JUTTexture, IFileAccess
6 | {
7 | public bool CanRead => true;
8 |
9 | public bool CanWrite => false;
10 |
11 | public static string Extension => ".s3g";
12 |
13 | public bool IsMatch(Stream stream, ReadOnlySpan extension = default)
14 | {
15 | if (stream.Length <= 0x20 || !extension.Contains(Extension, StringComparison.InvariantCultureIgnoreCase))
16 | {
17 | return false;
18 | }
19 |
20 | Header header = stream.Read();
21 | int size = GXImageFormat.CMPR.CalculatedDataSize((int)header.Width, (int)header.Height);
22 | return size + stream.Position == stream.Length;
23 | }
24 |
25 | protected override void Read(Stream stream)
26 | {
27 | Header header = stream.Read();
28 | Add(new(stream, Span.Empty, GXImageFormat.CMPR, GXPaletteFormat.RGB5A3, 0, (int)header.Width, (int)header.Height, 0)
29 | {
30 | LODBias = 0,
31 | MagnificationFilter = GXFilterMode.Nearest,
32 | MinificationFilter = GXFilterMode.Nearest,
33 | WrapS = GXWrapMode.CLAMP,
34 | WrapT = GXWrapMode.CLAMP,
35 | EnableEdgeLOD = false,
36 | MinLOD = 0,
37 | MaxLOD = 0
38 | });
39 | }
40 |
41 | protected override void Write(Stream stream) => throw new NotImplementedException();
42 |
43 | public struct Header
44 | {
45 | public uint unk;
46 | public uint unk2; //Images
47 | public uint Width;
48 | public uint Height;
49 | public uint unk3; // mips?
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/TextureExtraction tool/Data/ConsoleBar.cs:
--------------------------------------------------------------------------------
1 | namespace DolphinTextureExtraction
2 | {
3 | public class ConsoleBar
4 | {
5 |
6 | public ConsoleColor Color { get; private set; }
7 | public double Max { get; private set; }
8 | public int Length { get; private set; }
9 | public double Value { get; set; } = 0;
10 |
11 | public int CursorTop { get; set; }
12 | public int CursorLeft { get; set; }
13 |
14 | public ConsoleBar(double max, int length = 30, ConsoleColor color = ConsoleColor.Green)
15 | {
16 | CursorTop = Console.CursorTop;
17 | CursorLeft = Console.CursorLeft;
18 | Max = max;
19 | Length = length;
20 | Color = color;
21 | }
22 |
23 | public void Print()
24 | {
25 | lock (Console.Out)
26 | lock (Console.Error)
27 | {
28 | Console.SetCursorPosition(CursorLeft, CursorTop);
29 | ConsoleColor color = Console.ForegroundColor;
30 | Console.ForegroundColor = Color;
31 |
32 | Console.Write("│");
33 | float PL = (float)(Value * Length / Max);
34 | if (PL >= 1) Console.Write("".PadLeft((int)PL, '█'));
35 | if (PL < Length)
36 | {
37 | if ((PL - (int)PL) >= 0.75) Console.Write('▓');
38 | else if ((PL - (int)PL) >= 0.5) Console.Write('▒');
39 | else if ((PL - (int)PL) >= 0.25) Console.Write('░');
40 | else Console.Write(' ');
41 | Console.Write("".PadLeft(Length - (int)PL - 1, ' '));
42 | }
43 | Console.Write("│");
44 | Console.ForegroundColor = color;
45 | }
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Archives/Formats/NEP.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Common.Node;
3 |
4 | namespace AuroraLib.Archives.Formats
5 | {
6 | ///
7 | /// SEGA NEP Archive
8 | ///
9 | public sealed class NEP : ArchiveNode
10 | {
11 | public override bool CanWrite => false;
12 |
13 | public NEP()
14 | {
15 | }
16 |
17 | public NEP(string name) : base(name)
18 | {
19 | }
20 |
21 | public NEP(FileNode source) : base(source)
22 | {
23 | }
24 |
25 | public override bool IsMatch(Stream stream, ReadOnlySpan extension = default) => extension == ".NEP";
26 |
27 | protected override void Deserialize(Stream source)
28 | {
29 | while (source.Position + 0x20 < source.Length)
30 | {
31 | long pos = source.Position;
32 | Entry entry = source.Read(Endian.Big);
33 | string name = source.ReadCString();
34 | name = name.Replace("..\\", string.Empty);
35 | if (!Contains(name))
36 | {
37 | FileNode Sub = new(name, new SubStream(source, entry.Size, pos + entry.Offset));
38 | Add(Sub);
39 | }
40 | source.Seek(pos + entry.TotalSize, SeekOrigin.Begin);
41 | }
42 | }
43 |
44 | protected override void Serialize(Stream dest) => throw new NotImplementedException();
45 |
46 | private struct Entry
47 | {
48 | public Types Type;
49 | public uint Offset;
50 | public uint Size;
51 | public uint TotalSize;
52 |
53 | public enum Types : uint
54 | {
55 | GVR = 0, //texture
56 | GNM = 1, //model
57 | PEF = 2,
58 | }
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Archives/Formats/FBC.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common.Node;
2 |
3 | namespace AuroraLib.Archives.Formats
4 | {
5 | ///
6 | /// H.a.n.d. Fables Chocobo archive.
7 | ///
8 | public sealed class FBC : ArchiveNode
9 | {
10 | public override bool CanWrite => false;
11 |
12 | public override bool IsMatch(Stream stream, ReadOnlySpan extension = default)
13 | => extension.SequenceEqual("FBC");
14 |
15 | private const string Bres = "bresþÿ";
16 |
17 | public FBC()
18 | {
19 | }
20 |
21 | public FBC(string name) : base(name)
22 | {
23 | }
24 |
25 | public FBC(FileNode source) : base(source)
26 | {
27 | }
28 |
29 | protected override void Deserialize(Stream source)
30 | {
31 | //we do not know the header, so we skip it
32 | source.Seek(150, SeekOrigin.Begin);
33 |
34 | //FBC seem to contain only bres files
35 | while (source.Search(Bres))
36 | {
37 | long entrystart = source.Position;
38 | if (!source.Match(Bres))
39 | continue;
40 | ushort Version = source.ReadUInt16(Endian.Big);
41 | uint TotalSize = source.ReadUInt32(Endian.Big);
42 |
43 | if (TotalSize > source.Length - entrystart)
44 | {
45 | source.Search(Bres);
46 | TotalSize = (uint)(source.Position - entrystart);
47 | }
48 |
49 | FileNode Sub = new($"entry_{Count + 1}.bres", new SubStream(source, TotalSize, entrystart));
50 | Add(Sub);
51 |
52 | source.Position = entrystart + TotalSize;
53 | }
54 | }
55 |
56 | protected override void Serialize(Stream dest) => throw new NotImplementedException();
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/lib/AuroraLip/AuroraLib.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Library
5 | net8.0
6 | {CE629181-0090-46D0-81BC-16682E497573}
7 | enable
8 | disable
9 | False
10 | 1.0.$([System.DateTime]::Now.ToString(`MMdd.HHmm`))
11 | $(Version)
12 | $(Version)
13 | MIT
14 | AuroraLib
15 | $(AssemblyTitle)
16 | False
17 | true
18 | AuroraLip
19 | Copyright © 2022-present
20 |
21 |
22 |
23 | False
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Archives/Formats/PCKG.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Common.Node;
3 | using AuroraLib.Core.Interfaces;
4 |
5 | namespace AuroraLib.Archives.Formats
6 | {
7 | ///
8 | /// Cing Little King's Story Archive
9 | ///
10 | public sealed class PCKG : ArchiveNode, IHasIdentifier
11 | {
12 | public override bool CanWrite => false;
13 |
14 | public IIdentifier Identifier => _identifier;
15 |
16 | private static readonly Identifier32 _identifier = new("PCKG");
17 |
18 | public override bool IsMatch(Stream stream, ReadOnlySpan extension = default)
19 | => stream.Match(_identifier);
20 |
21 | private const string Bres = "bresþÿ";
22 |
23 | public PCKG()
24 | {
25 | }
26 |
27 | public PCKG(string name) : base(name)
28 | {
29 | }
30 |
31 | public PCKG(FileNode source) : base(source)
32 | {
33 | }
34 |
35 | protected override void Deserialize(Stream source)
36 | {
37 | //PCKG_CING seem to contain only bres files
38 | while (source.Search(Bres))
39 | {
40 | long entrystart = source.Position;
41 | if (!source.Match(Bres))
42 | continue;
43 | ushort Version = source.ReadUInt16(Endian.Big);
44 | uint TotalSize = source.ReadUInt32(Endian.Big);
45 |
46 | if (TotalSize > source.Length - entrystart)
47 | {
48 | source.Search(Bres);
49 | TotalSize = (uint)(source.Position - entrystart);
50 | }
51 |
52 | FileNode file = new($"entry_{Count + 1}.bres", new SubStream(source, TotalSize, entrystart));
53 | Add(file);
54 |
55 | source.Position = entrystart + TotalSize;
56 | }
57 | }
58 |
59 | protected override void Serialize(Stream dest) => throw new NotImplementedException();
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Archives/Formats/RSC.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Common.Node;
3 | using System.Xml.Linq;
4 |
5 | namespace AuroraLib.Archives.Formats
6 | {
7 | ///
8 | /// Treasure Wario World archive
9 | ///
10 | public sealed class RSC : ArchiveNode
11 | {
12 | public override bool CanWrite => false;
13 |
14 | public RSC()
15 | {
16 | }
17 |
18 | public RSC(string name) : base(name)
19 | {
20 | }
21 |
22 | public RSC(FileNode source) : base(source)
23 | {
24 | }
25 |
26 | public override bool IsMatch(Stream stream, ReadOnlySpan extension = default)
27 | => Matcher(stream, extension);
28 |
29 | public static bool Matcher(Stream stream, ReadOnlySpan extension = default)
30 | => extension.SequenceEqual(".RSC");
31 |
32 | protected override void Deserialize(Stream source)
33 | {
34 | Span unk = stackalloc byte[32];
35 | source.Read(unk);
36 |
37 | do
38 | {
39 | Entry entry = source.Read(Endian.Big);
40 | FileNode file = new($"{entry.Flag}_entry{Count}", new SubStream(source, (int)entry.Size));
41 | Add(file);
42 | if (entry.NextOffset == 0)
43 | {
44 | break;
45 | }
46 | source.Seek(entry.NextOffset, SeekOrigin.Begin);
47 | }
48 | while (true);
49 | }
50 |
51 | protected override void Serialize(Stream dest) => throw new NotImplementedException();
52 |
53 | private struct Entry
54 | {
55 | public uint Flag; //0-14, 1 = TPL
56 | public uint Size;
57 | public uint NextOffset;
58 | public uint Pad12;
59 |
60 | public uint Pad16;
61 | public uint Pad20;
62 | public uint Pad24;
63 | public uint Pad26;
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/Benchmark/Benchmarks/StringBuilder.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Core.Text;
3 | using BenchmarkDotNet.Attributes;
4 | using System.Text;
5 |
6 | namespace Benchmark.Benchmarks
7 | {
8 | [MemoryDiagnoser]
9 | public class StringBuild
10 | {
11 | private const int n = 2500;
12 | private const int n2 = 5;
13 |
14 | private const string text = "ABC0XXX.exe";
15 |
16 | [Benchmark]
17 | public void Add()
18 | {
19 | for (var i = 0; i < n; ++i)
20 | {
21 | string s = text;
22 | for (var i2 = 0; i2 < n2; ++i2)
23 | {
24 | s += text[..7];
25 | }
26 | }
27 | }
28 |
29 |
30 | [Benchmark]
31 | public void Concat()
32 | {
33 | for (var i = 0; i < n; ++i)
34 | {
35 | string s = text;
36 | for (var i2 = 0; i2 < n2; ++i2)
37 | {
38 | s = string.Concat(s, text.AsSpan()[..7]);
39 | }
40 | }
41 | }
42 |
43 | [Benchmark]
44 | public void StringBuilder()
45 | {
46 | for (var i = 0; i < n; ++i)
47 | {
48 | StringBuilder sb = new(text);
49 | for (var i2 = 0; i2 < n2; ++i2)
50 | {
51 | sb.Append(text.AsSpan()[..7]);
52 | }
53 | sb.ToString();
54 | }
55 | }
56 |
57 | [Benchmark]
58 | public void ValueStringBuilder()
59 | {
60 | for (var i = 0; i < n; ++i)
61 | {
62 | ValueStringBuilder sb = new();
63 | sb.Append(text.AsSpan());
64 | sb.Dispose();
65 | for (var i2 = 0; i2 < n2; ++i2)
66 | {
67 | sb.Append(text.AsSpan()[..7]);
68 | }
69 | sb.AsSpan();
70 | }
71 | }
72 |
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Archives/Formats/GSAGTX.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Common.Node;
3 | using System.Xml.Linq;
4 |
5 | namespace AuroraLib.Archives.Formats
6 | {
7 | ///
8 | /// Genius Sonority "GSAGTX" file format, although the real file extension is unknown.
9 | /// It basically contains an GTX texture with frames/"windows" into the texture.
10 | /// Based on Pokémon XD (GXXP01).
11 | ///
12 | public sealed class GSAGTX : ArchiveNode, IFileAccess
13 | {
14 | public override bool CanWrite => false;
15 |
16 | public GSAGTX()
17 | {
18 | }
19 |
20 | public GSAGTX(string name) : base(name)
21 | {
22 | }
23 |
24 | public GSAGTX(FileNode source) : base(source)
25 | {
26 | }
27 |
28 | public override bool IsMatch(Stream stream, ReadOnlySpan extension = default)
29 | => Matcher(stream, extension);
30 |
31 | public static bool Matcher(Stream stream, ReadOnlySpan extension = default)
32 | => extension.SequenceEqual(".GSAGTX") && stream.Length > 128;
33 |
34 | protected override void Deserialize(Stream stream)
35 | {
36 | Header header = stream.Read(Endian.Big);
37 | FileNode file = new("BaseTexture.GTX", new SubStream(stream, stream.Length - header.TextureOffset, header.TextureOffset));
38 | Add(file);
39 | }
40 |
41 | protected override void Serialize(Stream dest) => throw new NotImplementedException();
42 |
43 | public struct Header
44 | {
45 | public uint Header00;
46 |
47 | ///
48 | /// Contrains entries to "windows" into the texture to display
49 | ///
50 | public uint FramesOffset;
51 |
52 | public uint Header08;
53 |
54 | ///
55 | /// Offset from the file to an GTX texture used as the base.
56 | ///
57 | public uint TextureOffset;
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Archives/Formats/PAK_FE.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Common.Node;
3 | using AuroraLib.Core.Buffers;
4 | using AuroraLib.Core.Interfaces;
5 |
6 | namespace AuroraLib.Archives.Formats
7 | {
8 | ///
9 | /// Intelligent Systems Fire Emblem Archive
10 | ///
11 | public sealed class PAK_FE : ArchiveNode, IHasIdentifier
12 | {
13 | public override bool CanWrite => false;
14 |
15 | public IIdentifier Identifier => _identifier;
16 |
17 | private static readonly Identifier32 _identifier = new("pack");
18 |
19 | public PAK_FE()
20 | {
21 | }
22 |
23 | public PAK_FE(string name) : base(name)
24 | {
25 | }
26 |
27 | public PAK_FE(FileNode source) : base(source)
28 | {
29 | }
30 |
31 | public override bool IsMatch(Stream stream, ReadOnlySpan extension = default)
32 | => stream.Match(_identifier);
33 |
34 | protected override void Deserialize(Stream source)
35 | {
36 | source.MatchThrow(_identifier);
37 |
38 | ushort NrEntries = source.ReadUInt16(Endian.Big);
39 | ushort Unk = source.ReadUInt16(Endian.Big);
40 |
41 | using SpanBuffer entries = new (NrEntries);
42 | source.Read(entries, Endian.Big);
43 |
44 | for (int i = 0; i < NrEntries; i++)
45 | {
46 | source.Seek(entries[i].name, SeekOrigin.Begin);
47 | string name = source.ReadCString();
48 |
49 | FileNode file = new(name, new SubStream(source, entries[i].size, entries[i].data));
50 | Add(file);
51 | }
52 | }
53 |
54 | protected override void Serialize(Stream dest) => throw new NotImplementedException();
55 |
56 | private readonly struct Entrie
57 | {
58 | public readonly uint Unk;
59 | public readonly uint name;
60 | public readonly uint data;
61 | public readonly uint size;
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Archives/Formats/RMHG.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Common.Node;
3 | using AuroraLib.Core.Interfaces;
4 |
5 | namespace AuroraLib.Archives.Formats
6 | {
7 | ///
8 | /// Grasshopper Manufacture RMHG Archive
9 | ///
10 | // base https://github.com/Zheneq/Noesis-Plugins/blob/b47579012af3b43c1e10e06639325d16ece81f71/fmt_fatalframe_rsl.py
11 | public sealed class RMHG : ArchiveNode, IHasIdentifier
12 | {
13 | public override bool CanWrite => false;
14 |
15 | public IIdentifier Identifier => _identifier;
16 |
17 | private static readonly Identifier32 _identifier = new("RMHG");
18 |
19 | public RMHG()
20 | {
21 | }
22 |
23 | public RMHG(string name) : base(name)
24 | {
25 | }
26 |
27 | public RMHG(FileNode source) : base(source)
28 | {
29 | }
30 |
31 | public override bool IsMatch(Stream stream, ReadOnlySpan extension = default)
32 | => stream.Match(_identifier);
33 |
34 | protected override void Deserialize(Stream source)
35 | {
36 | source.MatchThrow(_identifier);
37 |
38 | uint count = source.ReadUInt32();
39 | uint DataOffset = source.ReadUInt32();
40 | uint unknown2 = source.ReadUInt32();
41 | uint dataSize = source.ReadUInt32();
42 |
43 | source.Seek(DataOffset, SeekOrigin.Begin);
44 |
45 | for (int i = 0; i < count; i++)
46 | {
47 | uint offset = source.ReadUInt32();
48 | uint size = source.ReadUInt32();
49 | uint[] unknown = new uint[6];// 0-2 unknown | 3-5 padding ?
50 | for (int r = 0; r < 6; r++)
51 | {
52 | unknown[r] = source.ReadUInt32();
53 | }
54 | if (size != 0)
55 | Add(new FileNode("Entry" + i, new SubStream(source, size, offset)));
56 | }
57 | }
58 |
59 | protected override void Serialize(Stream dest) => throw new NotImplementedException();
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Archives/Formats/FBTI.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Common.Node;
3 | using AuroraLib.Core.Interfaces;
4 |
5 | namespace AuroraLib.Archives.Formats
6 | {
7 | ///
8 | /// Rune Factory (Frontier) archive format
9 | ///
10 | public sealed class FBTI : ArchiveNode, IHasIdentifier
11 | {
12 | public override bool CanWrite => false;
13 |
14 | public IIdentifier Identifier => _identifier;
15 |
16 | private static readonly Identifier32 _identifier = new("FBTI");
17 |
18 | public FBTI()
19 | {
20 | }
21 |
22 | public FBTI(string name) : base(name)
23 | {
24 | }
25 |
26 | public FBTI(FileNode source) : base(source)
27 | {
28 | }
29 |
30 | public override bool IsMatch(Stream stream, ReadOnlySpan extension = default)
31 | => stream.Match(_identifier);
32 |
33 | protected override void Deserialize(Stream source)
34 | {
35 | source.MatchThrow(_identifier);
36 | int version = int.Parse(source.ReadString(4));
37 | uint file_count = source.ReadUInt32(Endian.Big);
38 | uint start_offset = source.ReadUInt32(Endian.Big); // always 0x10
39 |
40 | Span entries = stackalloc FileEntry[(int)file_count];
41 | source.Read(entries, Endian.Big);
42 |
43 | for (int i = 0; i < file_count; i++)
44 | {
45 | string name = NLCM.GetName(source, entries[i].Offset, entries[i].Size, i);
46 | Add(new FileNode(name, new SubStream(source, entries[i].Size, entries[i].Offset)));
47 | }
48 | }
49 |
50 | protected override void Serialize(Stream dest) => throw new NotImplementedException();
51 |
52 | private readonly struct FileEntry
53 | {
54 | public readonly uint Offset;
55 | public readonly uint Size;
56 |
57 | public FileEntry(uint offset, uint size)
58 | {
59 | Offset = offset;
60 | Size = size;
61 | }
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Archives/Formats/FONT.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common.Node;
2 | using AuroraLib.Core.Interfaces;
3 | using static AuroraLib.Texture.Formats.TXTRCC;
4 |
5 | namespace AuroraLib.Archives.Formats
6 | {
7 | ///
8 | /// Square Enix FFCC Font data archive.
9 | ///
10 | public sealed class FONT : ArchiveNode, IHasIdentifier
11 | {
12 | public override bool CanWrite => false;
13 |
14 | public IIdentifier Identifier => _identifier;
15 |
16 | private static readonly Identifier32 _identifier = new("FONT");
17 |
18 | public FONT()
19 | {
20 | }
21 |
22 | public FONT(string name) : base(name)
23 | {
24 | }
25 |
26 | public FONT(FileNode source) : base(source)
27 | {
28 | }
29 |
30 | public override bool IsMatch(Stream stream, ReadOnlySpan extension = default)
31 | => stream.Length > 0xD0 && stream.Match(_identifier) && stream.ReadUInt32(Endian.Big) + 0x10 == stream.Length;
32 |
33 | protected override void Deserialize(Stream source)
34 | {
35 | CCPropertieNote root = source.Read(Endian.Big);
36 |
37 | long contentSize = source.Position + root.ContentSize - 0x10;
38 | while (source.Position < contentSize)
39 | {
40 | long offset = source.Position;
41 | CCPropertieNote propertie = source.Read(Endian.Big);
42 | FileNode file = new(propertie.Identifier.ToString(), new SubStream(source, propertie.ContentSize + 0x10, offset));
43 |
44 | if (propertie.Identifier == 1381259348)
45 | {
46 | CCPropertieNote nameNote = source.Read(Endian.Big);
47 | file.Name = source.ReadString((int)nameNote.ContentSize);
48 | }
49 | Add(file);
50 | source.Seek(offset + propertie.ContentSize + 0x10, SeekOrigin.Begin);
51 | }
52 | }
53 |
54 | protected override void Serialize(Stream dest) => throw new NotImplementedException();
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Archives/Formats/NLCL.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Common.Node;
3 | using AuroraLib.Core.Interfaces;
4 |
5 | namespace AuroraLib.Archives.Formats
6 | {
7 | ///
8 | /// Rune Factory (Tides) archive format
9 | ///
10 | public sealed class NLCL : ArchiveNode, IHasIdentifier
11 | {
12 | public override bool CanWrite => false;
13 |
14 | public IIdentifier Identifier => _identifier;
15 |
16 | private static readonly Identifier32 _identifier = new("NLCL");
17 |
18 | public NLCL()
19 | {
20 | }
21 |
22 | public NLCL(string name) : base(name)
23 | {
24 | }
25 |
26 | public NLCL(FileNode source) : base(source)
27 | {
28 | }
29 |
30 | public override bool IsMatch(Stream stream, ReadOnlySpan extension = default)
31 | => stream.Match(_identifier);
32 |
33 | protected override void Deserialize(Stream source)
34 | {
35 | source.MatchThrow(_identifier);
36 |
37 | // This archive can have other things in it. But it
38 | // isn't clear to me how the each file is sourced
39 | // there is a count but no offset...
40 | while (source.Search("HXTB"))
41 | {
42 | long entrystart = source.Position;
43 | if (!source.Match("HXTB"))
44 | continue;
45 | source.Seek(0x14, SeekOrigin.Current);
46 | uint total_size = source.ReadUInt32(Endian.Big);
47 |
48 | if (total_size > source.Length - entrystart)
49 | {
50 | source.Search("HXTB");
51 | total_size = (uint)(source.Position - entrystart);
52 | }
53 |
54 | FileNode Sub = new($"entry_{Count + 1}.hxtb", new SubStream(source, total_size, entrystart));
55 | Add(Sub);
56 |
57 | source.Position = entrystart + total_size;
58 | }
59 | }
60 |
61 | protected override void Serialize(Stream dest) => throw new NotImplementedException();
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Archives/Formats/ONE_SB.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common.Node;
2 |
3 | namespace AuroraLib.Archives.Formats
4 | {
5 | ///
6 | /// Archive use in the Sonic Storybook Series
7 | ///
8 | public sealed class ONE_SB : ArchiveNode
9 | {
10 | public override bool CanWrite => false;
11 |
12 | public int Version = -1;
13 |
14 | public ONE_SB()
15 | {
16 | }
17 |
18 | public ONE_SB(string name) : base(name)
19 | {
20 | }
21 |
22 | public ONE_SB(FileNode source) : base(source)
23 | {
24 | }
25 |
26 | public override bool IsMatch(Stream stream, ReadOnlySpan extension = default)
27 | => Matcher(stream, extension);
28 |
29 | public static bool Matcher(Stream stream, ReadOnlySpan extension = default)
30 | => extension.Contains(".one", StringComparison.InvariantCultureIgnoreCase) && stream.At(4, SeekOrigin.Begin, S => S.ReadUInt32(Endian.Big)) == 16;
31 |
32 | protected override void Deserialize(Stream source)
33 | {
34 | uint numEntries = source.ReadUInt32(Endian.Big);
35 | uint offset = source.ReadUInt32(Endian.Big); //16
36 | uint unk = source.ReadUInt32(Endian.Big);
37 | Version = source.ReadInt32(Endian.Big); // 0 Sonic and the Secret Rings or -1 for Sonic and the Black Knight
38 |
39 | source.Seek(offset, SeekOrigin.Begin);
40 |
41 | for (int i = 0; i < numEntries; i++)
42 | {
43 | string entryFilename = source.ReadString(32) + ".prs";
44 |
45 | uint entryIndex = source.ReadUInt32(Endian.Big);
46 | uint entryOffset = source.ReadUInt32(Endian.Big);
47 | uint entryLength = source.ReadUInt32(Endian.Big);
48 | uint entryUnk = source.ReadUInt32(Endian.Big);
49 |
50 | FileNode Sub = new(entryFilename, new SubStream(source, entryLength, entryOffset));
51 | Add(Sub);
52 | }
53 | }
54 |
55 | protected override void Serialize(Stream dest) => throw new NotImplementedException();
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Archives/Formats/AFS.cs:
--------------------------------------------------------------------------------
1 | using AFSLib;
2 | using AuroraLib.Common.Node;
3 | using AuroraLib.Core.Interfaces;
4 |
5 | namespace AuroraLib.Archives.Formats
6 | {
7 | ///
8 | /// CRIWARE AFS archive
9 | ///
10 | public sealed class AFS : ArchiveNode, IHasIdentifier
11 | {
12 | public override bool CanWrite => false;
13 |
14 | public IIdentifier Identifier => _identifierA;
15 |
16 | public static readonly Identifier32 _identifierA = new("AFS ");
17 |
18 | public static readonly Identifier32 _identifierB = new((byte)'A', (byte)'F', (byte)'S', 0);
19 |
20 | private AFSLib.AFS AFSBase;
21 |
22 | public AFS()
23 | {
24 | }
25 |
26 | public AFS(string name) : base(name)
27 | {
28 | }
29 |
30 | public AFS(FileNode source) : base(source)
31 | {
32 | }
33 |
34 | public override bool IsMatch(Stream stream, ReadOnlySpan extension = default)
35 | {
36 | Identifier32 identifier = stream.Read();
37 | return identifier == _identifierA || identifier == _identifierB;
38 | }
39 |
40 | protected override void Deserialize(Stream source)
41 | {
42 | AFSBase = new AFSLib.AFS(source);
43 |
44 | foreach (Entry item in AFSBase.Entries)
45 | {
46 | if (item is StreamEntry Streamitem)
47 | {
48 | Add(new FileNode(Streamitem.SanitizedName, Streamitem.GetSubStream()));
49 | }
50 | }
51 | }
52 |
53 | protected override void Serialize(Stream dest) => throw new NotImplementedException();
54 |
55 | private bool disposedValue;
56 |
57 | protected override void Dispose(bool disposing)
58 | {
59 | // Call base class implementation.
60 | base.Dispose(disposing);
61 | if (!disposedValue)
62 | {
63 | if (disposing && AFSBase != null)
64 | {
65 | AFSBase.Dispose();
66 | }
67 | disposedValue = true;
68 | }
69 |
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Archives/Formats/NARC.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Common.Node;
3 | using AuroraLib.Core.Buffers;
4 | using AuroraLib.Core.Interfaces;
5 |
6 | namespace AuroraLib.Archives.Formats
7 | {
8 | ///
9 | /// Treasure Sin and Punishment archive
10 | ///
11 | public sealed class NARC : ArchiveNode, IHasIdentifier
12 | {
13 | public override bool CanWrite => false;
14 |
15 | public IIdentifier Identifier => _identifier;
16 |
17 | private static readonly Identifier32 _identifier = new("NARC");
18 |
19 | public NARC()
20 | {
21 | }
22 |
23 | public NARC(string name) : base(name)
24 | {
25 | }
26 |
27 | public NARC(FileNode source) : base(source)
28 | {
29 | }
30 |
31 | public override bool IsMatch(Stream stream, ReadOnlySpan extension = default)
32 | => stream.Length > 0x20 && stream.Match(_identifier);
33 |
34 | protected override void Deserialize(Stream source)
35 | {
36 | source.MatchThrow(_identifier);
37 | uint NrEntries = source.ReadUInt32(Endian.Big);
38 | uint StringTableSize = source.ReadUInt32(Endian.Big);
39 | uint dataTableOffset = source.ReadUInt32(Endian.Big);
40 |
41 | using SpanBuffer entries = new(NrEntries);
42 | source.Read(entries,Endian.Big);
43 | long nameTableOffset = source.Position;
44 |
45 | foreach (NARCEntry entry in entries)
46 | {
47 | source.Position = nameTableOffset + entry.NameOffset;
48 | FileNode Sub = new(source.ReadCString(), new SubStream(source, entry.DataSize, dataTableOffset + entry.DataOffset));
49 | Add(Sub);
50 | }
51 | }
52 |
53 | protected override void Serialize(Stream dest) => throw new NotImplementedException();
54 |
55 | private readonly struct NARCEntry
56 | {
57 | public readonly uint Unknown;
58 | public readonly uint NameOffset;
59 | public readonly uint DataOffset;
60 | public readonly uint DataSize;
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Compression/Algorithms/Zstd.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Compression.Interfaces;
2 | using AuroraLib.Core.Buffers;
3 | using AuroraLib.Core.Interfaces;
4 | using System.IO.Compression;
5 | using ZstdSharp;
6 |
7 | namespace AuroraLib.Compression.Algorithms
8 | {
9 | public class Zstd : ICompressionAlgorithm, IHasIdentifier
10 | {
11 | public IIdentifier Identifier => _identifier;
12 |
13 | private static readonly Identifier32 _identifier = new(0xFD2FB528);
14 |
15 | public bool IsMatch(Stream stream, ReadOnlySpan extension = default)
16 | => stream.Length > 0x10 && stream.Match(_identifier);
17 |
18 | public void Compress(ReadOnlySpan source, Stream destination, CompressionLevel level = CompressionLevel.Optimal)
19 | {
20 | int zslevel = level switch
21 | {
22 | CompressionLevel.NoCompression => 0,
23 | CompressionLevel.Fastest => 5,
24 | CompressionLevel.Optimal => 10,
25 | CompressionLevel.SmallestSize => 20,
26 | _ => throw new NotImplementedException(),
27 | };
28 | Compress(source, destination, zslevel);
29 | }
30 |
31 | public static void Compress(ReadOnlySpan source, Stream destination, int level)
32 | {
33 | using SpanBuffer destinationSpan = new(Compressor.GetCompressBound(source.Length));
34 | using Compressor compressor = new(level);
35 | int length = compressor.Wrap(source, destinationSpan);
36 | destination.Write(destinationSpan.Span[..length]);
37 | }
38 |
39 | public void Decompress(Stream source, Stream destination)
40 | {
41 | using SpanBuffer sourceSpan = new((int)(source.Length - source.Position));
42 | source.Read(sourceSpan);
43 | ulong DecompressedSize = Decompressor.GetDecompressedSize(sourceSpan);
44 | using SpanBuffer destinationSpan = new((int)DecompressedSize);
45 | using Decompressor decompressor = new();
46 | int length = decompressor.Unwrap(sourceSpan, destinationSpan);
47 | destination.Write(destinationSpan.Span[..length]);
48 | }
49 |
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/Formats/TXD.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Core.Interfaces;
3 | using RenderWareNET.Enums;
4 | using RenderWareNET.Plugins;
5 | using RenderWareNET.Structs;
6 |
7 | namespace AuroraLib.Texture.Formats
8 | {
9 | public class TXD : JUTTexture, IHasIdentifier, IFileAccess
10 | {
11 | public bool CanRead => true;
12 |
13 | public bool CanWrite => false;
14 |
15 | public virtual IIdentifier Identifier => _identifier;
16 |
17 | private static readonly Identifier32 _identifier = new(22);
18 |
19 | public bool IsMatch(Stream stream, ReadOnlySpan extension = default)
20 | {
21 | RWPluginHeader mainHeader = stream.Read();
22 | RWPluginHeader structHeader = stream.Read();
23 | return mainHeader.Identifier == PluginID.TextureDictionary && mainHeader.Version == structHeader.Version && structHeader.Identifier == PluginID.Struct;
24 | }
25 |
26 | protected override void Read(Stream stream)
27 | {
28 | TextureDictionary textureDictionary = new(stream);
29 | foreach (TextureNative tx in textureDictionary)
30 | {
31 | if (tx.Properties.Platform != TexturePlatformID.GC)
32 | {
33 | throw new NotSupportedException();
34 | }
35 | using MemoryStream ms = new(tx.Properties.ImageData);
36 | GXImageFormat format = (GXImageFormat)tx.Properties.Format;
37 | GXPaletteFormat palettFormat = tx.Properties.TLOTFormat switch
38 | {
39 | FourCCType.IA8 => GXPaletteFormat.IA8,
40 | FourCCType.RGB565 => GXPaletteFormat.RGB565,
41 | FourCCType.RGB5A3 => GXPaletteFormat.RGB5A3,
42 | _ => GXPaletteFormat.IA8,
43 | };
44 | TexEntry entry = new(ms, tx.Properties.TLOT, format, palettFormat, format.GetMaxPaletteColours(), tx.Properties.Width, tx.Properties.Height, tx.Properties.Images - 1);
45 | Add(entry);
46 | }
47 | }
48 |
49 | protected override void Write(Stream stream) => throw new NotImplementedException();
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/JUTTexture.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Core.Interfaces;
2 |
3 | namespace AuroraLib.Texture
4 | {
5 | /*
6 | * base on https://github.com/SuperHackio/Hack.io
7 | */
8 |
9 | ///
10 | /// The base class of all textures.
11 | ///
12 | public abstract partial class JUTTexture : List, IDisposable, IObjectName
13 | {
14 | ///
15 | /// The full path of this file.
16 | ///
17 | public string Name { get; set; } = null;
18 |
19 | public JUTTexture()
20 | { }
21 |
22 | public JUTTexture(Stream stream) => Read(stream);
23 |
24 | public JUTTexture(string filepath)
25 | {
26 | FileStream fs = new(filepath, FileMode.Open);
27 | Read(fs);
28 | fs.Close();
29 | Name = filepath;
30 | }
31 |
32 | public virtual void Save(string filepath)
33 | {
34 | FileStream fs = new(filepath, FileMode.Create);
35 | Write(fs);
36 | fs.Close();
37 | Name = filepath;
38 | }
39 |
40 | public virtual void Save(Stream stream) => Write(stream);
41 |
42 | public virtual void Open(Stream stream) => Read(stream);
43 |
44 | protected abstract void Read(Stream stream);
45 |
46 | protected abstract void Write(Stream stream);
47 |
48 | public override int GetHashCode()
49 | => HashCode.Combine(base.GetHashCode(), Name);
50 |
51 | #region Dispose
52 |
53 | private bool disposedValue;
54 |
55 | protected virtual void Dispose(bool disposing)
56 | {
57 | if (!disposedValue)
58 | {
59 | if (disposing)
60 | {
61 | foreach (var item in this)
62 | item.Dispose();
63 | }
64 | disposedValue = true;
65 | }
66 | }
67 |
68 | ~JUTTexture()
69 | {
70 | Dispose(disposing: true);
71 | }
72 |
73 | public void Dispose()
74 | {
75 | Dispose(disposing: true);
76 | GC.SuppressFinalize(this);
77 | }
78 |
79 | #endregion Dispose
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Archives/Formats/PKX.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common.Node;
2 |
3 | namespace AuroraLib.Archives.Formats
4 | {
5 | ///
6 | /// Genius Senority (Pokémon XD Gale of Darkness) PKX file (pokémon and some models?)
7 | ///
8 | public sealed class PKX : ArchiveNode
9 | {
10 | public override bool CanWrite => false;
11 |
12 | public PKX()
13 | {
14 | }
15 |
16 | public PKX(string name) : base(name)
17 | {
18 | }
19 |
20 | public PKX(FileNode source) : base(source)
21 | {
22 | }
23 |
24 | public override bool IsMatch(Stream stream, ReadOnlySpan extension = default)
25 | => Matcher(stream, extension);
26 |
27 | public static bool Matcher(Stream stream, ReadOnlySpan extension = default)
28 | => extension.Contains(".pkx", StringComparison.InvariantCultureIgnoreCase) && stream.At(0x1A, s => s.ReadUInt16(Endian.Big) == 0x0C);
29 |
30 | protected override void Deserialize(Stream source)
31 | {
32 | Header header = source.Read(Endian.Big);
33 |
34 | if (header.Unknown1A == 0x0C)
35 | {
36 | uint archive_begin = 0x84 + header.NumEntries * 208;
37 | archive_begin = (archive_begin + 31) & ~(uint)31; // Round to next 32-byte boundary
38 | archive_begin = (archive_begin + header.Unknown08 + 31) & ~(uint)31;
39 |
40 | FileNode Sub = new("thing.GSscene", new SubStream(source, header.ArchiveSize, archive_begin));
41 | Add(Sub);
42 | }
43 | else
44 | {
45 | throw new NotImplementedException($"Unknown header value {header.Unknown1A}");
46 | }
47 | }
48 |
49 | protected override void Serialize(Stream dest) => throw new NotImplementedException();
50 |
51 | public struct Header
52 | {
53 | public uint ArchiveSize;
54 | public uint Unknown04;
55 | public uint Unknown08;
56 | public uint Unknown0C;
57 | public uint NumEntries;
58 | public uint Unknown14;
59 | public ushort Unknown18;
60 | public ushort Unknown1A;
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/TextureExtraction tool/Data/LogBase.cs:
--------------------------------------------------------------------------------
1 | namespace DolphinTextureExtraction
2 | {
3 | public class LogBase : StreamWriter
4 | {
5 | protected static readonly object Lock = new();
6 |
7 | public string FullPath { get; private set; }
8 |
9 | public LogBase(Stream FullPath) : base(FullPath)
10 | => this.FullPath = string.Empty;
11 |
12 | public LogBase(string FullPath) : base(FullPath, new FileStreamOptions() { Access = FileAccess.Write, Mode = FileMode.Create, Share = FileShare.Read })
13 | => this.FullPath = FullPath;
14 |
15 | public LogBase(string FullPath, bool append) : base(FullPath, append)
16 | => this.FullPath = FullPath;
17 |
18 | ///
19 | /// Convert a thread's id to a base 1 index, increasing in increments of 1 (Makes logs prettier)
20 | ///
21 | protected int ThreadIndex
22 | {
23 | get
24 | {
25 | int managed = Environment.CurrentManagedThreadId;
26 | if (!ThreadIndices.TryGetValue(managed, out int id))
27 | ThreadIndices.Add(managed, id = ThreadIndices.Count + 1);
28 |
29 | return id;
30 | }
31 | }
32 | private readonly Dictionary ThreadIndices = new();
33 |
34 | public override void WriteLine()
35 | {
36 | lock (Lock)
37 | {
38 | base.WriteLine();
39 | }
40 | }
41 |
42 | public override void WriteLine(string value)
43 | {
44 | lock (Lock)
45 | {
46 | base.WriteLine(value);
47 | }
48 | }
49 |
50 | public override void Write(string value)
51 | {
52 | lock (Lock)
53 | {
54 | base.Write(value);
55 | }
56 | }
57 |
58 | public override void Write(ReadOnlySpan value)
59 | {
60 | lock (Lock)
61 | {
62 | base.Write(value);
63 | }
64 | }
65 |
66 | public override void Write(char[] value)
67 | {
68 | lock (Lock)
69 | {
70 | base.Write(value);
71 | }
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/TextureExtraction tool/Scans/Results/FinalizeResults.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Texture;
2 | using System.Text;
3 |
4 | namespace DolphinTextureExtraction.Scans.Results
5 | {
6 | public class FinalizeResults : ScanResults
7 | {
8 | private readonly List Hash = new();
9 |
10 | public int Optimizations { get; private set; } = 0;
11 | public int Duplicates { get; private set; } = 0;
12 |
13 | public long NewSize { get; private set; } = 0;
14 | public long OldSize { get; private set; } = 0;
15 |
16 | public double OptimizationRate => ((double)NewSize / OldSize) * 100 - 100;
17 |
18 | public override string ToString()
19 | {
20 | StringBuilder sb = new();
21 | if (Hash.Count > 1)
22 | sb.AppendLine($"Textures processed: {Hash.Count}");
23 | if (Optimizations > 0)
24 | sb.AppendLine($"Optimizations: {Optimizations}");
25 | if (Duplicates > 0)
26 | sb.AppendLine($"Duplicates: {Duplicates}");
27 | if (Optimizations > 0)
28 | {
29 | sb.AppendLine($"File size from {PathX.AddSizeSuffix(OldSize, 2)} to {PathX.AddSizeSuffix(NewSize, 2)}");
30 | sb.AppendLine($"File size ratio: {OptimizationRate:+#.##;-#.##;0.00}%");
31 | }
32 | sb.AppendLine($"Scan time: {TotalTime.TotalSeconds:.000}s");
33 | return sb.ToString();
34 | }
35 |
36 | internal void AddOptimization()
37 | {
38 | lock (this)
39 | {
40 | Optimizations++;
41 | }
42 | }
43 |
44 | internal void AddSize(long oldSize, long newSize)
45 | {
46 | lock (this)
47 | {
48 | OldSize += oldSize;
49 | NewSize += newSize;
50 | }
51 | }
52 |
53 | internal bool AddHashIfNeeded(int hash)
54 | {
55 | lock (Hash)
56 | {
57 | //Skip duplicate textures
58 | if (Hash.Contains(hash))
59 | {
60 | Duplicates++;
61 | return true;
62 | }
63 | Hash.Add(hash);
64 | }
65 | return false;
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/lib/AuroraLip/DiscImage/Dolphin/FSTBin.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common.Node;
2 |
3 | namespace AuroraLib.DiscImage.Dolphin
4 | {
5 | public class FSTBin
6 | {
7 | public FSTEntry[] Entires;
8 | public long stringTableOffset;
9 |
10 | private readonly bool _IsGC;
11 |
12 | public FSTBin(Stream stream, bool isGC = true)
13 | {
14 | _IsGC = isGC;
15 | var root = stream.Read(Endian.Big);
16 | Entires = stream.For((int)root.Data - 1, S => S.Read(Endian.Big));
17 | stringTableOffset = stream.Position;
18 | }
19 |
20 | public void ProcessEntres(Stream stream, DirectoryNode directory)
21 | => ProcessEntres(stream, directory, 0, Entires.Length);
22 |
23 | private int ProcessEntres(Stream stream, DirectoryNode directory, int i, int l)
24 | {
25 | while (i < l)
26 | {
27 | stream.Seek(stringTableOffset + (int)Entires[i].NameOffset, SeekOrigin.Begin);
28 | string name = stream.ReadCString();
29 | if (Entires[i].IsDirectory)
30 | {
31 | DirectoryNode subdir = new(name);
32 | directory.Add(subdir);
33 | i = ProcessEntres(stream, subdir, i + 1, (int)Entires[i].Data - 1);
34 | }
35 | else
36 | {
37 | if (_IsGC)
38 | directory.Add(new FileNode(name, new SubStream(stream, Entires[i].Data, Entires[i].Offset)));
39 | else
40 | directory.Add(new FileNode(name, new SubStream(stream, Entires[i].Data, Entires[i].Offset << 2)));
41 | i++;
42 | }
43 | }
44 | return l;
45 | }
46 |
47 | public struct FSTEntry
48 | {
49 | public byte Flag { get; set; }
50 | public UInt24 NameOffset { get; set; }
51 | public uint Offset { get; set; } // file or parent Offset
52 | public uint Data { get; set; } // fileSize or numberOfFiles Offset
53 |
54 | public bool IsDirectory
55 | {
56 | readonly get => Flag != 0;
57 | set => Flag = (byte)(value ? 1 : 0);
58 | }
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/TextureExtraction tool/Scans/Compress.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Compression;
2 | using AuroraLib.Compression.Interfaces;
3 | using DolphinTextureExtraction.Scans.Helper;
4 | using DolphinTextureExtraction.Scans.Options;
5 | using DolphinTextureExtraction.Scans.Results;
6 |
7 | namespace DolphinTextureExtraction.Scans
8 | {
9 | public class Compress : ScanBase
10 | {
11 | private readonly Type algorithm;
12 |
13 | public double CompressionRate { get; private set; } = 0;
14 |
15 | public static ScanResults StartScan(string meindirectory, string savedirectory, Type Algorithm, ScanOptions options, string logDirectory = null)
16 | => StartScan_Async(meindirectory, savedirectory, Algorithm, options, logDirectory).Result;
17 |
18 | public static async Task StartScan_Async(string meindirectory, string savedirectory, Type Algorithm, ScanOptions options, string logDirectory = null)
19 | {
20 | Compress Extractor = new(meindirectory, savedirectory, Algorithm, options, logDirectory);
21 | return await Extractor.StartScan_Async();
22 | }
23 |
24 | internal Compress(string scanDirectory, string saveDirectory, Type Algorithm, ScanOptions options = null, string logDirectory = null) : base(scanDirectory, saveDirectory, options, logDirectory)
25 | => algorithm = Algorithm;
26 |
27 | protected override void Scan(ScanObjekt so)
28 | {
29 | ICompressionAlgorithm algo = (ICompressionAlgorithm)Activator.CreateInstance(algorithm);
30 | using FileStream destination = new(GetFullSaveDirectory(so.File.GetFullPath()), FileMode.CreateNew, FileAccess.ReadWrite, FileShare.Read);
31 | algo.Compress(so.File.Data.ToArray(), destination);
32 | AddResult(so, destination);
33 | }
34 |
35 | private void AddResult(ScanObjekt so, Stream destination)
36 | {
37 | double compressionRate = ((double)destination.Length / so.File.Data.Length - 1) * 100;
38 | lock (Result)
39 | {
40 | CompressionRate = (CompressionRate + compressionRate) / 2;
41 | }
42 | Log.Write(FileAction.Compress, so.File.GetFullPath() + $" ~{PathX.AddSizeSuffix(destination.Length, 2)}", $"Algo:{algorithm.Name} Rate:{compressionRate:+#.##;-#.##;0.00}%");
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/Formats/GCNT.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Core.Interfaces;
3 |
4 | namespace AuroraLib.Texture.Formats
5 | {
6 | public class GCNT : JUTTexture, IHasIdentifier, IFileAccess
7 | {
8 | public virtual bool CanRead => true;
9 |
10 | public virtual bool CanWrite => false;
11 |
12 | public virtual IIdentifier Identifier => _identifier;
13 |
14 | private static readonly Identifier32 _identifier = new("GCNT");
15 | private static readonly Identifier32 _alt = new("SIZE");
16 |
17 | public bool IsMatch(Stream stream, ReadOnlySpan extension = default)
18 | => stream.Length > 0x10 && (stream.Match(_identifier) || stream.At(8, s => s.Match(_identifier)));
19 |
20 | protected override void Read(Stream stream)
21 | {
22 | long HeaderStart = stream.Position;
23 |
24 | if (!stream.Match(_identifier))
25 | {
26 | HeaderStart = stream.Position += 4;
27 | stream.MatchThrow(_identifier);
28 | }
29 |
30 | ImageHeader ImageHeader = stream.Read(Endian.Big);
31 |
32 | TexEntry current = new(stream, ImageHeader.Format, ImageHeader.PaletteFormat, ImageHeader.Width, ImageHeader.Height, ImageHeader.Mipmaps)
33 | {
34 | LODBias = 0,
35 | MagnificationFilter = default,
36 | MinificationFilter = default,
37 | WrapS = default,
38 | WrapT = default,
39 | EnableEdgeLOD = default,
40 | MinLOD = 0,
41 | MaxLOD = ImageHeader.Mipmaps+1
42 | };
43 | Add(current);
44 | }
45 |
46 | protected override void Write(Stream stream) => throw new NotImplementedException();
47 |
48 | private struct ImageHeader
49 | {
50 | public uint Unknown; //0x3
51 | public ushort Offset;
52 | public ushort Version;//?
53 | public uint Size;
54 | public ushort Width;
55 | public ushort Height;
56 | public GXImageFormat Format;
57 | public GXPaletteFormat PaletteFormat;
58 | public byte Mipmaps;
59 | public byte Padding23;
60 | public uint Padding24;
61 | public uint Padding28;
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/J3D/NameTableIO.cs:
--------------------------------------------------------------------------------
1 | namespace AuroraLib.Texture.J3D
2 | {
3 | /*
4 | * Super Hackio Incorporated
5 | * "Copyright © Super Hackio Incorporated 2020-2021"
6 | * https://github.com/SuperHackio/Hack.io
7 | */
8 |
9 | public static class NameTableIO
10 | {
11 | public static List ReadStringTable(this Stream stream, int offset)
12 | {
13 | List names = new List();
14 |
15 | stream.Position = offset;
16 |
17 | short stringCount = stream.ReadInt16(Endian.Big);
18 | stream.Position += 0x02;
19 |
20 | for (int i = 0; i < stringCount; i++)
21 | {
22 | stream.Position += 0x02;
23 | short nameOffset = stream.ReadInt16(Endian.Big);
24 | long saveReaderPos = stream.Position;
25 | stream.Position = offset + nameOffset;
26 |
27 | names.Add(stream.ReadCString());
28 |
29 | stream.Position = saveReaderPos;
30 | }
31 |
32 | return names;
33 | }
34 |
35 | public static void WriteStringTable(this Stream writer, List names)
36 | {
37 | long start = writer.Position;
38 |
39 | writer.Write((short)names.Count, Endian.Big);
40 | writer.Write(new byte[2] { 0xFF, 0xFF }, 0, 2);
41 |
42 | foreach (string st in names)
43 | {
44 | writer.Write(HashString(st), Endian.Big);
45 | writer.Write(new byte[2], 0, 2);
46 | }
47 |
48 | long curOffset = writer.Position;
49 | for (int i = 0; i < names.Count; i++)
50 | {
51 | writer.Seek((int)(start + (6 + i * 4)), SeekOrigin.Begin);
52 | writer.Write((short)(curOffset - start), Endian.Big);
53 | writer.Seek((int)curOffset, SeekOrigin.Begin);
54 |
55 | writer.WriteString(names[i], 0x00);
56 |
57 | curOffset = writer.Position;
58 | }
59 | }
60 |
61 | private static ushort HashString(string str)
62 | {
63 | ushort hash = 0;
64 |
65 | foreach (char c in str)
66 | {
67 | hash *= 3;
68 | hash += (ushort)c;
69 | }
70 |
71 | return hash;
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/Formats/RES_NLG.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 |
3 | namespace AuroraLib.Texture.Formats
4 | {
5 | public class RES_NLG : JUTTexture, IFileAccess
6 | {
7 | public bool CanRead => true;
8 |
9 | public bool CanWrite => false;
10 |
11 | public const string Extension = ".res";
12 | public const string Extension2 = ".dmn";
13 |
14 | public bool IsMatch(Stream stream, ReadOnlySpan extension = default)
15 | => Matcher(stream, extension);
16 |
17 | public static bool Matcher(Stream stream, ReadOnlySpan extension = default)
18 | => (extension.Contains(Extension, StringComparison.InvariantCultureIgnoreCase) || extension.Contains(Extension2, StringComparison.InvariantCultureIgnoreCase) && stream.ReadInt32(Endian.Big) == 0x20 && stream.ReadInt32(Endian.Big) != 0 && stream.ReadInt32(Endian.Big) == 1);
19 |
20 | protected override void Read(Stream stream)
21 | {
22 | Header header = stream.Read(Endian.Big);
23 | stream.Seek(header.Offset, SeekOrigin.Begin);
24 | Entry[] entries = stream.For((int)header.Entrys, s => s.Read(Endian.Big));
25 | for (int i = 0; i < entries.Length; i++)
26 | {
27 | stream.Seek(entries[i].Offset, SeekOrigin.Begin);
28 |
29 | if (PTLG.ReadTexture(stream, entries[i].Size, out TexEntry current))
30 | {
31 | Add(current);
32 | }
33 |
34 | }
35 | }
36 |
37 | protected override void Write(Stream stream) => throw new NotImplementedException();
38 |
39 | private struct Header
40 | {
41 | public uint Offset; // 0x20
42 | public uint Entrys;
43 | public uint Version; //1
44 | private uint firstEntry;
45 |
46 | public long FirstEntryOffset
47 | {
48 | get => firstEntry << 5;
49 | set => firstEntry = (uint)(value >> 5);
50 | }
51 | }
52 |
53 | private struct Entry
54 | {
55 | public uint Hash;
56 | private uint offset;
57 | public uint Size;
58 |
59 | public long Offset
60 | {
61 | get => offset << 5;
62 | set => offset = (uint)(value >> 5);
63 | }
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/TextureExtraction tool/AppSettings.cs:
--------------------------------------------------------------------------------
1 | using LibCPK;
2 | using System.Collections.Specialized;
3 | using System.Configuration;
4 |
5 | namespace DolphinTextureExtraction
6 | {
7 | internal static class AppSettings
8 | {
9 | public static readonly NameValueCollection Config;
10 |
11 | public static readonly bool UseConfig;
12 |
13 | public static bool DryRun = false;
14 |
15 | public static bool Force = false;
16 |
17 | public static uint Deep = 0;
18 |
19 | public static bool Mips = false;
20 |
21 | public static bool ArbitraryMipmapDetection = true;
22 |
23 | public static bool Raw = false;
24 |
25 | public static bool DolphinMipDetection = true;
26 |
27 | public static bool CombinedRGBA = false;
28 |
29 | #if DEBUG
30 | public static ParallelOptions Parallel = new() { MaxDegreeOfParallelism = 1 };
31 | #else
32 | public static readonly ParallelOptions Parallel = new() { MaxDegreeOfParallelism = 4 };
33 | #endif
34 |
35 | static AppSettings()
36 | {
37 | Config = ConfigurationManager.AppSettings;
38 | UseConfig = Config.HasKeys() && bool.TryParse(Config.Get("UseConfig"), out bool value) && value;
39 |
40 | if (UseConfig)
41 | {
42 | if (bool.TryParse(Config.Get("DryRun"), out value))
43 | DryRun = value;
44 | if (bool.TryParse(Config.Get("Force"), out value))
45 | Force = value;
46 | if (uint.TryParse(Config.Get("Deep"), out uint deep))
47 | Deep = deep;
48 | if (int.TryParse(Config.Get("Tasks"), out int thing))
49 | Parallel.MaxDegreeOfParallelism = thing <= 0 ? 1 : thing;
50 | if (bool.TryParse(Config.Get("Mips"), out value))
51 | Mips = value;
52 | if (bool.TryParse(Config.Get("Raw"), out value))
53 | Raw = value;
54 | if (bool.TryParse(Config.Get("DolphinMipDetection"), out value))
55 | DolphinMipDetection = value;
56 | if (bool.TryParse(Config.Get("ArbitraryMipmapDetection"), out value))
57 | ArbitraryMipmapDetection = value;
58 | if (bool.TryParse(Config.Get("CombinedRGBA"), out value))
59 | CombinedRGBA = value;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/TextureExtraction tool/DolphinTextureExtraction tool.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net8.0
6 | {89776DB8-07A1-4B36-BE77-7AB5E4237E3A}
7 | enable
8 | disable
9 | False
10 | 1.8.0.$([System.DateTime]::Now.ToString(`MMdd`))
11 | $(Version)
12 | $(Version)
13 | MIT
14 | DolphinTextureExtraction.tool
15 | DolphinTextureExtraction
16 | False
17 | DolphinTextureExtraction.Program
18 | Icon.ico
19 | Dumps GC and Wii textures, compatible with the Dolphin texture hash.
20 | Copyright © Venomalia 2022-present
21 | https://github.com/Venomalia/DolphinTextureExtraction-tool
22 | Dolphin Texture Extraction Tool
23 | Venomalia
24 | True
25 | False
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | PreserveNewest
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/Formats/GCT0.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Core.Interfaces;
3 |
4 | namespace AuroraLib.Texture.Formats
5 | {
6 | public class GCT0 : JUTTexture, IHasIdentifier, IFileAccess
7 | {
8 | public bool CanRead => true;
9 |
10 | public bool CanWrite => false;
11 |
12 | public virtual IIdentifier Identifier => _identifier;
13 |
14 | private static readonly Identifier32 _identifier = new("GCT0");
15 |
16 | public bool IsMatch(Stream stream, ReadOnlySpan extension = default)
17 | => stream.Match(_identifier);
18 |
19 | protected override void Read(Stream stream)
20 | {
21 | stream.MatchThrow(_identifier);
22 |
23 | GXImageFormat Format = (GXImageFormat)stream.ReadUInt32(Endian.Big);
24 | ushort Width = stream.ReadUInt16(Endian.Big);
25 | ushort Height = stream.ReadUInt16(Endian.Big);
26 | byte unkflag = (byte)stream.ReadByte(); //Flag?
27 | _ = stream.ReadInt24(Endian.Big);
28 | uint ImgOffset = stream.ReadUInt32(Endian.Big);
29 | _ = stream.ReadUInt64(Endian.Big);
30 | ushort unkmip = stream.ReadUInt16(Endian.Big); //mips?
31 | _ = stream.ReadUInt16(Endian.Big);
32 | uint unknown = stream.ReadUInt32(Endian.Big); //202
33 |
34 | // we calculate the mips
35 | int mips = Format.GetMipmapsFromSize((int)(stream.Length - ImgOffset), Width, Height);
36 |
37 | // Palette are not supported?
38 | if (Format.IsPaletteFormat())
39 | {
40 | throw new PaletteException($"{nameof(GCT0)} does not support palette formats.");
41 | }
42 |
43 | stream.Seek(ImgOffset, SeekOrigin.Begin);
44 | Add(new TexEntry(stream, null, Format, GXPaletteFormat.IA8, 0, Width, Height, mips)
45 | {
46 | LODBias = 0,
47 | MagnificationFilter = GXFilterMode.Nearest,
48 | MinificationFilter = GXFilterMode.Nearest,
49 | WrapS = GXWrapMode.CLAMP,
50 | WrapT = GXWrapMode.CLAMP,
51 | EnableEdgeLOD = false,
52 | MinLOD = 0,
53 | MaxLOD = mips
54 | });
55 | }
56 |
57 | protected override void Write(Stream stream)
58 | {
59 | throw new NotImplementedException();
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Archives/Formats/CPK.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common.Node;
2 | using AuroraLib.Core.Interfaces;
3 | using System.Text;
4 |
5 | namespace AuroraLib.Archives.Formats
6 | {
7 | ///
8 | /// CRIWARE Compact Archive
9 | ///
10 | public sealed class CPK : ArchiveNode, IHasIdentifier
11 | {
12 | public override bool CanWrite => false;
13 |
14 | public IIdentifier Identifier => _identifier;
15 |
16 | private static readonly Identifier32 _identifier = new("CPK ");
17 |
18 | public readonly LibCPK.CPK CpkContent = new();
19 |
20 | public CPK()
21 | {
22 | }
23 |
24 | public CPK(string name) : base(name)
25 | {
26 | }
27 |
28 | public CPK(FileNode source) : base(source)
29 | {
30 | }
31 |
32 | public override bool IsMatch(Stream stream, ReadOnlySpan extension = default)
33 | => stream.Match(_identifier);
34 |
35 | protected override void Deserialize(Stream source)
36 | {
37 | CpkContent.ReadCPK(source, Encoding.UTF8);
38 |
39 | foreach (var entrie in CpkContent.fileTable)
40 | {
41 | if (entrie.FileType != LibCPK.FileTypeFlag.FILE)
42 | continue;
43 |
44 | DirectoryNode dir;
45 | if (String.IsNullOrWhiteSpace(entrie.DirName))
46 | {
47 | dir = this;
48 | }
49 | else
50 | {
51 | if (TryGet(entrie.DirName, out ObjectNode objectNode))
52 | {
53 | dir = (DirectoryNode)objectNode;
54 | }
55 | else
56 | {
57 | dir = new DirectoryNode(Path.GetFileName(entrie.DirName));
58 | AddPath(entrie.DirName, dir);
59 | }
60 | }
61 |
62 | // important files are available multiple times.
63 | FileNode file = new(entrie.FileName, new SubStream(source, UInt32.Parse(entrie.FileSize.ToString()), (long)entrie.FileOffset));
64 | if (!dir.TryAdd(file))
65 | {
66 | file.Dispose();
67 | }
68 | }
69 | }
70 |
71 | protected override void Serialize(Stream dest) => throw new NotImplementedException();
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Archives/Formats/PAC.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Common.Node;
3 | using AuroraLib.Core.Buffers;
4 |
5 | namespace AuroraLib.Archives.Formats
6 | {
7 | ///
8 | /// Sting Entertainment PAC Archive.
9 | ///
10 | public sealed class PAC : ArchiveNode
11 | {
12 | public override bool CanWrite => false;
13 |
14 | public PAC()
15 | {
16 | }
17 |
18 | public PAC(string name) : base(name)
19 | {
20 | }
21 |
22 | public PAC(FileNode source) : base(source)
23 | {
24 | }
25 |
26 | public override bool IsMatch(Stream stream, ReadOnlySpan extension = default)
27 | => extension.SequenceEqual(".PAC") && stream.Length > 52428800;
28 |
29 | protected override void Deserialize(Stream source)
30 | {
31 | //try to request an external file.
32 | string datname = Path.GetFileNameWithoutExtension(Name);
33 | if (TryGetRefFile(datname + ".PAH", out FileNode refFile))
34 | {
35 | using Stream streamPAH = refFile.Data;
36 | uint tabelEntrys = streamPAH.Read();
37 | uint tabelOffset = streamPAH.Read();
38 | uint tabelEnd = streamPAH.Read();
39 | // Unknown values from 0x7 to 0x70
40 | streamPAH.Seek(tabelOffset, SeekOrigin.Begin);
41 | using SpanBuffer entries = new((int)tabelEntrys);
42 | streamPAH.Read(entries.Span);
43 | foreach (var entry in entries)
44 | {
45 | streamPAH.Seek(entry.NameOffset, SeekOrigin.Begin);
46 | string name = streamPAH.ReadCString();
47 | FileNode file = new(name, new SubStream(source, entry.Size, entry.Offset));
48 | Add(file);
49 | }
50 | }
51 | else
52 | {
53 | throw new Exception($"{nameof(PAC)}: could not request the file {datname}.");
54 | }
55 | }
56 |
57 | protected override void Serialize(Stream dest) => throw new NotImplementedException();
58 |
59 | private struct PAHFileEntry
60 | {
61 | public uint Offset;
62 | public uint Size;
63 | public uint Null;
64 | public uint NameOffset;
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Compression/CompressionReflection.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Compression.Interfaces;
3 |
4 | namespace AuroraLib.Compression
5 | {
6 | public class CompressionReflection : FileAccessReflection
7 | {
8 | public CompressionReflection() : base()
9 | {
10 | }
11 |
12 | public bool TryToDecompress(Stream source, out List destinations, out Type type)
13 | {
14 | destinations = new();
15 | if (TryToDecompress(source, out Stream destination, out ICompressionDecoder decoder))
16 | {
17 | type = decoder.GetType();
18 | destinations.Add(destination);
19 | while (source.Position + 0x10 < source.Length)
20 | {
21 | while (source.ReadByte() == 0)
22 | { }
23 | source.Position--;
24 | if (source.Peek(s => decoder.IsMatch(s)))
25 | {
26 | destination = new MemoryPoolStream();
27 | decoder.Decompress(source, destination);
28 | destinations.Add(destination);
29 | }
30 | else
31 | {
32 | break;
33 | }
34 | }
35 | return true;
36 | }
37 | destinations = null;
38 | type = null;
39 | return false;
40 | }
41 |
42 | public bool TryToDecompress(Stream source, out Stream destination, out ICompressionDecoder type)
43 | {
44 | destination = new MemoryPoolStream();
45 |
46 | foreach (ICompressionDecoder decoder in Instances)
47 | {
48 | try
49 | {
50 | if (source.Peek(s => decoder.IsMatch(s)))
51 | {
52 | decoder.Decompress(source, destination);
53 | type = decoder;
54 | return true;
55 | }
56 | }
57 | catch (Exception t)
58 | {
59 | destination.SetLength(0);
60 | }
61 | }
62 |
63 | destination.Dispose();
64 | destination = null;
65 | type = null;
66 | return false;
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/TextureExtraction tool/Scans/Cutter.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Archives;
2 | using AuroraLib.Common.Node;
3 | using DolphinTextureExtraction.Scans.Helper;
4 | using DolphinTextureExtraction.Scans.Options;
5 | using DolphinTextureExtraction.Scans.Results;
6 |
7 | namespace DolphinTextureExtraction.Scans
8 | {
9 | public class Cutter : ScanBase
10 | {
11 | private readonly List Pattern;
12 |
13 | internal Cutter(string scanDirectory, string saveDirectory, ScanOptions options = null, string logDirectory = null) : base(scanDirectory, saveDirectory, options, logDirectory) { }
14 |
15 | internal Cutter(string scanDirectory, string saveDirectory, List pattern, ScanOptions options = null, string logDirectory = null) : base(scanDirectory, saveDirectory, options, logDirectory)
16 | => Pattern = pattern;
17 |
18 | public static ScanResults StartScan(string meindirectory, string savedirectory, List pattern, ScanOptions options, string logDirectory = null)
19 | => StartScan_Async(meindirectory, savedirectory, pattern, options, logDirectory).Result;
20 |
21 | public static async Task StartScan_Async(string meindirectory, string savedirectory, List pattern, ScanOptions options, string logDirectory = null)
22 | {
23 | Cutter Extractor = new(meindirectory, savedirectory, pattern, options, logDirectory);
24 | return await Extractor.StartScan_Async();
25 | }
26 | protected override void Scan(ScanObjekt so)
27 | {
28 | if (so.Deep != 0)
29 | {
30 | Save(so);
31 | }
32 | else
33 | {
34 | ArchiveNode archive;
35 | if (Pattern == null)
36 | archive = new DataCutter(so.File.Data);
37 | else
38 | archive = new DataCutter(so.File.Data, Pattern);
39 |
40 | if (archive.Count > 0)
41 | {
42 | if (archive.Count == 1)
43 | {
44 | foreach (var item in archive)
45 | {
46 | if (item.Value is FileNode file)
47 | Save(file.Data, so.File.GetFullPath(), so.Format);
48 | else
49 | Scan(archive, so.Deep + 1);
50 | }
51 | }
52 | }
53 | }
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Archives/Formats/PAKb.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common.Node;
2 | using AuroraLib.Core.Buffers;
3 | using AuroraLib.Core.Interfaces;
4 |
5 | namespace AuroraLib.Archives.Formats
6 | {
7 | ///
8 | /// Keen Games Dawn of Discovery Archive
9 | ///
10 | public sealed class PAKb : ArchiveNode, IHasIdentifier
11 | {
12 | public override bool CanWrite => false;
13 |
14 | public IIdentifier Identifier => _identifier;
15 |
16 | private static readonly Identifier32 _identifier = new("PAKb");
17 |
18 | public PAKb()
19 | {
20 | }
21 |
22 | public PAKb(string name) : base(name)
23 | {
24 | }
25 |
26 | public PAKb(FileNode source) : base(source)
27 | {
28 | }
29 |
30 | public override bool IsMatch(Stream stream, ReadOnlySpan extension = default)
31 | => stream.Match(_identifier);
32 |
33 | protected override void Deserialize(Stream source)
34 | {
35 | source.MatchThrow(_identifier);
36 |
37 | uint file_count = source.ReadUInt32(Endian.Big);
38 |
39 | using SpanBuffer file_data = new(file_count);
40 | source.Read(file_data, Endian.Big);
41 |
42 | uint names_start = file_data[(int)file_count - 1].Offset;
43 |
44 | for (int i = 0; i < file_count; i++)
45 | {
46 | source.Seek(names_start, SeekOrigin.Begin);
47 |
48 | uint expected_crc = file_data[i].Crc;
49 | uint crc = 0;
50 | string name = "";
51 | do
52 | {
53 | crc = source.ReadUInt32(Endian.Big);
54 | uint name_size = source.ReadUInt32(Endian.Big);
55 | if (name_size == 0)
56 | {
57 | crc = expected_crc;
58 | }
59 | name = source.ReadString((int)name_size);
60 | } while (expected_crc != crc);
61 |
62 | FileNode file = new(name, new SubStream(source, file_data[i].Size, file_data[i].Offset));
63 | Add(file);
64 | }
65 | }
66 |
67 | protected override void Serialize(Stream dest) => throw new NotImplementedException();
68 |
69 | private readonly struct FileData
70 | {
71 | public readonly uint Crc;
72 | public readonly uint Offset;
73 | public readonly uint Size;
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/lib/AuroraLip/DiscImage/Dolphin/GameHeader.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Core.Interfaces;
2 |
3 | namespace AuroraLib.DiscImage.Dolphin
4 | {
5 | public abstract class GameHeader : IBinaryObject
6 | {
7 | public const uint WiiMagicWord = 1562156707;
8 | public const uint GCMagicWord = 3258163005;
9 |
10 | public GameID GameID;
11 | public byte DiskID;
12 | public byte Version;
13 | public bool Streaming;
14 | public byte StreamBufSize; // 0 = default BufSize
15 |
16 | public string GameName { get; set; }
17 | public DiskTypes DiskType;
18 |
19 | protected GameHeader()
20 | { }
21 |
22 | public GameHeader(Stream source)
23 | => BinaryDeserialize(source);
24 |
25 | public virtual void BinaryDeserialize(Stream source)
26 | {
27 | GameID = source.Read();
28 | DiskID = source.ReadUInt8();
29 | Version = source.ReadUInt8();
30 | Streaming = source.ReadUInt8() == 1;
31 | StreamBufSize = source.ReadUInt8();
32 | source.Position += 14;
33 | uint magicWordWii = source.ReadUInt32(Endian.Big); // GC 0 Wii 1562156707
34 | uint magicWordGC = source.ReadUInt32(Endian.Big); // GC 3258163005 Wii 0
35 | if (magicWordWii == 0 && magicWordGC == GCMagicWord) DiskType = DiskTypes.GC;
36 | else if (magicWordWii == WiiMagicWord && magicWordGC == 0) DiskType = DiskTypes.Wii;
37 | else DiskType = DiskTypes.Invalid;
38 | ReadData(source);
39 | }
40 |
41 | public virtual void BinarySerialize(Stream dest)
42 | {
43 | dest.Write(GameID);
44 | dest.WriteByte(DiskID);
45 | dest.WriteByte(Version);
46 | dest.WriteByte((byte)(Streaming ? 1 : 0));
47 | dest.WriteByte(StreamBufSize);
48 | dest.Write(stackalloc byte[14]);
49 | if (DiskType == DiskTypes.Wii)
50 | {
51 | dest.Write(WiiMagicWord, Endian.Big);
52 | dest.Write(0);
53 | }
54 | else
55 | {
56 | dest.Write(0);
57 | dest.Write(GCMagicWord, Endian.Big);
58 | }
59 | WriteData(dest);
60 | }
61 |
62 | protected abstract void ReadData(Stream source);
63 | protected abstract void WriteData(Stream dest);
64 | }
65 |
66 | public enum DiskTypes
67 | {
68 | Invalid = 0,
69 | GC = 1,
70 | Wii = 2,
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/Formats/GTX1.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Core.Interfaces;
3 |
4 | namespace AuroraLib.Texture.Formats
5 | {
6 | public class GTX1 : JUTTexture, IHasIdentifier, IFileAccess
7 | {
8 | public virtual bool CanRead => true;
9 |
10 | public virtual bool CanWrite => false;
11 |
12 | public virtual IIdentifier Identifier => _identifier;
13 |
14 | private static readonly Identifier32 _identifier = new("GTX1");
15 |
16 | public bool IsMatch(Stream stream, ReadOnlySpan extension = default)
17 | => stream.Length > 0x10 && stream.At(4, s => s.Match(_identifier));
18 |
19 | protected override void Read(Stream stream)
20 | {
21 | Header header = stream.Read(Endian.Big);
22 |
23 | //hack to get mips i do not trust the header.mip value
24 | int mips = header.Format.GetMipmapsFromSize((int)header.Size, header.Width, header.Height) - 1;
25 |
26 | Add(new(stream, Span.Empty, header.Format, GXPaletteFormat.IA8, 0, header.Width, header.Height, mips)
27 | {
28 | LODBias = 0,
29 | MagnificationFilter = GXFilterMode.Nearest,
30 | MinificationFilter = GXFilterMode.Nearest,
31 | WrapS = GXWrapMode.CLAMP,
32 | WrapT = GXWrapMode.CLAMP,
33 | EnableEdgeLOD = false,
34 | MinLOD = 0,
35 | MaxLOD = mips
36 | });
37 | }
38 |
39 | protected override void Write(Stream stream) => throw new NotImplementedException();
40 |
41 | private struct Header
42 | {
43 | public uint Size;
44 | public Identifier32 Identifier; //GTX1
45 | public byte PahtID;
46 | public byte ImageID;
47 | public GXImageFormat Format;
48 | public byte Unk1;//255
49 | public ushort Width;
50 | public ushort Height;
51 |
52 | public uint Unk2;//0
53 | public byte Unk3;//0 80
54 | public byte data;
55 | public ushort Unk5; // 0 256
56 | public Identifier64 Name; //loobFrab
57 |
58 | public int Unk4 //1 2 3 11
59 | {
60 | get => (data >> 4);
61 | set => data = (byte)((data & 0x0F) | (value << 4));
62 | }
63 | public int Mips
64 | {
65 | get => (data & 0xF);
66 | set => data = (byte)((data & 0xF0) | value);
67 | }
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/lib/AuroraLip/DiscImage/Dolphin/BootBin.cs:
--------------------------------------------------------------------------------
1 | namespace AuroraLib.DiscImage.Dolphin
2 | {
3 | public class BootBin : GameHeader
4 | {
5 | public uint DebugMonitorOffset; //offset of debug monitor (dh.bin)?
6 | public uint DebugMonitorAddress; //addr(?) to load debug monitor?
7 |
8 | public uint DolOffset; //offset of main executable DOL (bootfile)
9 | public uint FSTableOffset; //offset of the FST ("fst.bin")
10 | public uint FSTableSize;
11 | public uint FSTableSizeMax; //maximum size of FST usually same as FSTSize
12 | public uint UserPosition;
13 | public uint UserLength;
14 | public uint Unknown;
15 |
16 | public BootBin(Stream source) : base(source)
17 | { }
18 |
19 | protected override void ReadData(Stream source)
20 | {
21 | GameName = source.ReadString(992);
22 | DebugMonitorOffset = source.ReadUInt32(Endian.Big);
23 | DebugMonitorAddress = source.ReadUInt32(Endian.Big);
24 | source.Skip(24);
25 | DolOffset = source.ReadUInt32(Endian.Big); //offset of main executable DOL (bootfile)
26 | FSTableOffset = source.ReadUInt32(Endian.Big); //offset of the FST ("fst.bin")
27 | FSTableSize = source.ReadUInt32(Endian.Big);
28 | FSTableSizeMax = source.ReadUInt32(Endian.Big); //maximum size of FST (usually same as FSTSize)*
29 | UserPosition = source.ReadUInt32(Endian.Big);
30 | UserLength = source.ReadUInt32(Endian.Big);
31 | Unknown = source.ReadUInt32(Endian.Big);
32 | source.Position += 4;
33 | if (DiskType == DiskTypes.Wii)
34 | {
35 | DolOffset <<= 2;
36 | FSTableOffset <<= 2;
37 | }
38 | }
39 |
40 | protected override void WriteData(Stream dest)
41 | {
42 | dest.WriteString(GameName, 992, 0);
43 | dest.Write(DebugMonitorOffset, Endian.Big);
44 | dest.Write(DebugMonitorAddress, Endian.Big);
45 | dest.Write(stackalloc byte[24]);
46 | dest.Write(DiskType == DiskTypes.GC ? DolOffset : DolOffset >> 2, Endian.Big);
47 | dest.Write(DiskType == DiskTypes.GC ? FSTableOffset : FSTableOffset >> 2, Endian.Big);
48 | dest.Write(FSTableSize, Endian.Big);
49 | dest.Write(FSTableSizeMax, Endian.Big);
50 | dest.Write(UserPosition, Endian.Big);
51 | dest.Write(UserLength, Endian.Big);
52 | dest.Write(Unknown, Endian.Big);
53 | dest.Write(0);
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Archives/Formats/RTDP.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Common.Node;
3 | using AuroraLib.Core.Interfaces;
4 |
5 | namespace AuroraLib.Archives.Formats
6 | {
7 | ///
8 | /// Imageepoch Arc Rise Archive
9 | ///
10 | public sealed class RTDP : ArchiveNode, IHasIdentifier
11 | {
12 | public override bool CanWrite => false;
13 |
14 | public IIdentifier Identifier => _identifier;
15 |
16 | private static readonly Identifier32 _identifier = new("RTDP");
17 |
18 | public RTDP()
19 | {
20 | }
21 |
22 | public RTDP(string name) : base(name)
23 | {
24 | }
25 |
26 | public RTDP(FileNode source) : base(source)
27 | {
28 | }
29 |
30 | public override bool IsMatch(Stream stream, ReadOnlySpan extension = default)
31 | => stream.Match(_identifier);
32 |
33 | protected override void Deserialize(Stream source)
34 | {
35 | source.MatchThrow(_identifier);
36 | int EOH = (int)source.ReadUInt32(Endian.Big);
37 | int NrEntries = (int)source.ReadUInt32(Endian.Big);
38 | int Size = (int)source.ReadUInt32(Endian.Big);
39 | source.Position = 0x20;
40 |
41 | List Entries = new(NrEntries);
42 | for (int i = 0; i < NrEntries; i++)
43 | {
44 | Entries.Add(new RTDPEntry(source));
45 | }
46 |
47 | foreach (var Entry in Entries)
48 | {
49 | SubStream subStream = new(source, Entry.DataSize, Entry.DataOffset + EOH);
50 | XORStream xORStream = new(subStream, 0x55);
51 | FileNode file = new(Entry.Name, xORStream);
52 | //If Duplicate...
53 | if (Contains(file))
54 | file.Name = Path.GetFileName(Entry.Name) + Entries.IndexOf(Entry) + Path.GetExtension(Entry.Name);
55 |
56 | Add(file);
57 | }
58 | }
59 |
60 | protected override void Serialize(Stream dest) => throw new NotImplementedException();
61 |
62 | private class RTDPEntry
63 | {
64 | public string Name { get; set; }
65 | public int DataSize { get; set; }
66 | public int DataOffset { get; set; }
67 |
68 | public RTDPEntry(Stream stream)
69 | {
70 | Name = stream.ReadString(32);
71 | DataSize = (int)stream.ReadUInt32(Endian.Big);
72 | DataOffset = (int)stream.ReadUInt32(Endian.Big);
73 | }
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Common/XORStream.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Core.Buffers;
2 |
3 | namespace AuroraLib.Common
4 | {
5 | public class XORStream : Stream
6 | {
7 | public readonly Stream Base;
8 | public readonly byte[] Key;
9 |
10 | public XORStream(Stream stream, byte key)
11 | {
12 | Base = stream;
13 | Key = new byte[] { key };
14 | }
15 |
16 | public XORStream(Stream stream, ReadOnlySpan key)
17 | {
18 | Base = stream;
19 | Key = new byte[key.Length * 2];
20 | for (int i = 0; i < Key.Length; i++)
21 | {
22 | Key[i] = key[i % key.Length];
23 | }
24 | }
25 |
26 | public override bool CanRead => Base.CanRead;
27 | public override bool CanSeek => Base.CanSeek;
28 | public override bool CanWrite => Base.CanWrite;
29 | public override long Length => Base.Length;
30 | public override long Position { get => Base.Position; set => Base.Position = value; }
31 | public override void Flush() => Base.Flush();
32 | public override long Seek(long offset, SeekOrigin origin) => Base.Seek(offset, origin);
33 | public override void SetLength(long value) => Base.SetLength(value);
34 | public override int Read(byte[] buffer, int offset, int count) => Read(buffer.AsSpan(offset, count));
35 | public override void Write(byte[] buffer, int offset, int count) => Write(buffer.AsSpan(offset, count));
36 |
37 | public override int Read(Span buffer)
38 | {
39 | int r = Base.Read(buffer);
40 | if (Key.Length == 1)
41 | {
42 | buffer.DataXor(Key[0]);
43 | }
44 | else
45 | {
46 | int offset = (int)(Base.Position % (Key.Length / 2));
47 | buffer.DataXor(Key.AsSpan(offset, (Key.Length / 2)));
48 | }
49 | return r;
50 | }
51 |
52 | public override void Write(ReadOnlySpan buffer)
53 | {
54 | using SpanBuffer rbuffer = new(buffer);
55 | if (Key.Length == 1)
56 | {
57 | rbuffer.Span.DataXor(Key[0]);
58 | }
59 | else
60 | {
61 | int offset = (int)(Base.Position % (Key.Length / 2));
62 | rbuffer.Span.DataXor(Key.AsSpan(offset, (Key.Length / 2)));
63 | }
64 | Base.Write(rbuffer);
65 | }
66 |
67 | protected override void Dispose(bool disposing)
68 | {
69 | Base.Dispose();
70 | base.Dispose(disposing);
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Archives/Formats/PAK_TM2.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Common.Node;
3 | using AuroraLib.Core.Buffers;
4 |
5 | namespace AuroraLib.Archives.Formats
6 | {
7 | ///
8 | /// Red Entertainment Tengai Makyō II Archive
9 | ///
10 | public sealed class PAK_TM2 : ArchiveNode
11 | {
12 | public override bool CanWrite => false;
13 |
14 | public PAK_TM2()
15 | {
16 | }
17 |
18 | public PAK_TM2(string name) : base(name)
19 | {
20 | }
21 |
22 | public PAK_TM2(FileNode source) : base(source)
23 | {
24 | }
25 |
26 | public override bool IsMatch(Stream stream, ReadOnlySpan extension = default)
27 | => Matcher(stream, extension);
28 |
29 | public static bool Matcher(Stream stream, ReadOnlySpan extension = default)
30 | {
31 | if ((extension.SequenceEqual(".pak") || extension.Length == 0 || extension.SequenceEqual(".cns")) && stream.Length > 0x20)
32 | {
33 | uint entryCount = stream.ReadUInt32(Endian.Big);
34 | if (entryCount != 0 && entryCount < 1024 && stream.Position + entryCount * 8 < stream.Length)
35 | {
36 | Entry[] entrys = stream.For((int)entryCount, s => s.Read(Endian.Big));
37 |
38 | for (int i = 0; i < entryCount - 1; i++)
39 | {
40 | if (entrys[i].Offset + entrys[i].Size > entrys[i + 1].Offset)
41 | {
42 | return false;
43 | }
44 | }
45 | return entrys.First().Offset >= stream.Position && entrys.Last().Offset + entrys.Last().Size == stream.Length;
46 | }
47 | }
48 | return false;
49 | }
50 |
51 | protected override void Deserialize(Stream source)
52 | {
53 | uint entryCount = source.ReadUInt32(Endian.Big);
54 | using SpanBuffer entries = new SpanBuffer(entryCount);
55 | source.Read(entries, Endian.Big);
56 |
57 | for (int i = 0; i < entries.Length; i++)
58 | {
59 | FileNode file = new($"Entry_{i}", new SubStream(source, entries[i].Size, entries[i].Offset));
60 | Add(file);
61 | }
62 | }
63 |
64 | protected override void Serialize(Stream dest) => throw new NotImplementedException();
65 |
66 | private readonly struct Entry
67 | {
68 | public readonly uint Offset;
69 | public readonly uint Size;
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Archives/Formats/TSET.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common.Node;
2 | using AuroraLib.Core.Interfaces;
3 | using static AuroraLib.Texture.Formats.TXTRCC;
4 |
5 | namespace AuroraLib.Archives.Formats
6 | {
7 | ///
8 | /// Square Enix FFCC data Archive
9 | ///
10 | public sealed class TSET : ArchiveNode, IHasIdentifier
11 | {
12 | public override bool CanWrite => false;
13 |
14 | public IIdentifier Identifier => _identifier;
15 |
16 | private static readonly Identifier32 _identifier = new("TSET");
17 | private static readonly Identifier32 _identifier2 = new("TEX ");
18 | private static readonly Identifier32 _identifier3 = new("OTM ");
19 |
20 | public TSET()
21 | {
22 | }
23 |
24 | public TSET(string name) : base(name)
25 | {
26 | }
27 |
28 | public TSET(FileNode source) : base(source)
29 | {
30 | }
31 |
32 | public override bool IsMatch(Stream stream, ReadOnlySpan extension = default)
33 | {
34 | CCPropertieNote root = stream.Read(Endian.Big);
35 |
36 | return (root.Identifier == _identifier || root.Identifier == _identifier2 || (root.Identifier == _identifier3 && stream.At(0x20, s => s.Match(_identifier)))) && root.ContentSize + 0x10 == stream.Length;
37 | }
38 |
39 | protected override void Deserialize(Stream source)
40 | {
41 | CCPropertieNote root = source.Read(Endian.Big);
42 | if (root.Identifier != _identifier)
43 | {
44 | source.Seek(0x20, SeekOrigin.Begin);
45 | root = source.Read(Endian.Big);
46 | }
47 |
48 | long contentSize = source.Position + root.ContentSize - 0x10;
49 | while (source.Position < contentSize)
50 | {
51 | long offset = source.Position;
52 | CCPropertieNote txtr = source.Read(Endian.Big);
53 | if (txtr.Identifier != 1381259348)
54 | {
55 | return;
56 | }
57 |
58 | CCPropertieNote propertie = source.Read(Endian.Big);
59 | string name = source.ReadString((int)propertie.ContentSize);
60 |
61 | FileNode file = new(name, new SubStream(source, txtr.ContentSize + 0x10, offset));
62 | if (Contains(file))
63 | file.Name += Count;
64 | Add(file);
65 | source.Seek(offset + txtr.ContentSize + 0x10, SeekOrigin.Begin);
66 | }
67 | }
68 |
69 | protected override void Serialize(Stream dest) => throw new NotImplementedException();
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Archives/Formats/ARC0.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Common.Node;
3 | using AuroraLib.Core.Interfaces;
4 |
5 | namespace AuroraLib.Archives.Formats
6 | {
7 | ///
8 | /// Brawl ARC0 Archive
9 | ///
10 | // ref https://github.com/soopercool101/BrawlCrate/blob/a0e5638c34bba0de783ece169d483ad7e7dcb016/BrawlLib/SSBB/ResourceNodes/Archives/ARCNode.cs
11 | public sealed class ARC0 : ArchiveNode, IHasIdentifier
12 | {
13 | public override bool CanWrite => false;
14 |
15 | public IIdentifier Identifier => _identifier;
16 |
17 | private static readonly Identifier32 _identifier = new((byte)'A', (byte)'R', (byte)'C', 0);
18 |
19 | public ARC0()
20 | {
21 | }
22 |
23 | public ARC0(string name) : base(name)
24 | {
25 | }
26 |
27 | public ARC0(FileNode source) : base(source)
28 | {
29 | }
30 |
31 | public override bool IsMatch(Stream stream, ReadOnlySpan extension = default)
32 | => stream.Match(_identifier) && stream.ReadByte() == 0;
33 |
34 | protected override void Deserialize(Stream source)
35 | {
36 | source.MatchThrow(_identifier);
37 |
38 | ushort version = source.ReadUInt16(Endian.Big); //257
39 | ushort files = source.ReadUInt16(Endian.Big);
40 | ulong unk = source.ReadUInt64(Endian.Big);
41 | string name = source.ReadString(48);
42 |
43 | for (int i = 0; i < files; i++)
44 | {
45 | EntryType type = (EntryType)source.ReadUInt16(Endian.Big);
46 | ushort index = source.ReadUInt16(Endian.Big);
47 | uint size = source.ReadUInt32(Endian.Big);
48 | byte groupIndex = (byte)source.ReadByte();
49 | byte pad = (byte)source.ReadByte();
50 | short redirectIndex = source.ReadInt16(Endian.Big);
51 |
52 | uint[] padding = new uint[5];
53 | for (int p = 0; p < 5; p++)
54 | padding[p] = source.ReadUInt32(Endian.Big);
55 | Add(new FileNode($"{type}_{i}.pcs", new SubStream(source, size)));
56 |
57 | source.Align(size, SeekOrigin.Current, 32);
58 | }
59 | }
60 |
61 | protected override void Serialize(Stream dest) => throw new NotImplementedException();
62 |
63 | public enum EntryType : short
64 | {
65 | None = 0x0,
66 | MiscData = 0x1,
67 | ModelData = 0x2,
68 | TextureData = 0x3,
69 | AnimationData = 0x4,
70 | SceneData = 0x5,
71 | Type6 = 0x6,
72 | GroupedArchive = 0x7,
73 | EffectData = 0x8
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/lib/Hack.io/README.md:
--------------------------------------------------------------------------------
1 | # Hack.io
2 | **A Collection of File In/Out libraries for various formats**
3 | Previously referred to as "Hackio.IO"
4 |
5 | ## What is it?
6 | The Hack.io libraries are easy-to-use, modular C# libraries that can be used in multiple projects. I made these with the intent of just using them so I wouldn't have to constantly repeat my code when doing projects.
7 | In the end, here they are, feel free to use them in your projects.
8 |
9 | ## Library Listing
10 |
11 | - **Hack.io**
12 | Hack.io is the base library used by all the other Hack.io libraries.
13 |
14 | - **Hack.io.BCK**
15 | Bone Animations for J3D Models (SMG/SMG2, SMS, Pikmin, etc.)
16 |
17 | - **Hack.io.BMD**
18 | Library for J3D Models (SMG/SMG2, SMS, Pikmin, etc.)
19 | Heavily based on SuperBMD, but only does Read/Write to/from BMD/BDL. (no model importing and no model exporting)
20 |
21 | - **Hack.io.BTK**
22 | Texture Position Animations for J3D Models (SMG/SMG2, SMS, Pikmin, etc.)
23 |
24 | - **Hack.io.BRK**
25 | Colour Register Animations for J3D Models (SMG/SMG2, SMS, Pikmin, etc.)
26 |
27 | - **Hack.io.BTI**
28 | Library for the BTI image format. Supports all image formats and mipmaps
29 |
30 | - **Hack.io.BTP**
31 | Frame Animations for J3D Models (SMG/SMG2, SMS, etc.)
32 | This would animate a material by swapping out texture indicies
33 |
34 | - **Hack.io.BVA**
35 | Mesh Visibility Animations for J3D Models (SMG/SMG2, etc.)
36 |
37 | - **Hack.io.BPK**
38 | Palette Animations for J3D Models (SMG/SMG2, etc.)
39 |
40 | - **Hack.io.BCSV**
41 | Comma Seperated Values (SMG/SMG2)
42 |
43 | - **Hack.io.RARC**
44 | Revolution (Wii) Archives. (SMG/SMG2, SMS)
45 | **THESE ARE NOT U8 FORMATTED ARCHIVES!**
46 |
47 | - **Hack.IO.YAZ0**
48 | Library for Compressing/Decompressing data to/from YAZ0. Works with pretty much anything
49 |
50 | - **Hack.IO.YAY0**
51 | Library for Compressing/Decompressing data to/from YAY0. Works with pretty much anything
52 |
53 | ## How to use
54 | Download the Libraries you want and then reference them in your program's Assembly References.
55 | Using statements will also be needed. The statements are identical to the library name.
56 | Example:
57 | ```using Hack.io.RARC;```
58 | For Library specific tutorials, please visit it's corresponding Wiki Page.
59 |
60 |
61 | # Credits
62 | - Super Hackio - Main Programmer/Maintainer
63 | - RenolY2 aka Yoshi2 - Code reference for Hack.io.BTK & Hack.io.BRK
64 | - NoClip.website - Code reference for Hack.io.BCK, Hack.io.BTP, Hack.io.BVA & Hack.io.BPK
65 | - tarsa129 - Code reference for Hack.io.BCK because NoClip wasn't enough
66 | - Old SMG Researchers - File formats for Hack.io.CANM, Hack.io.BCSV & Hack.io.RARC
67 | - Gericom - Quick YAZ0 Compression
68 | - Daniel-McCarthy - YAY0 Compression
69 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Archives/Formats/RKV2.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common.Node;
2 | using AuroraLib.Core.Interfaces;
3 |
4 | namespace AuroraLib.Archives.Formats
5 | {
6 | ///
7 | /// Krome Studios Star Wars Force Unleashed
8 | ///
9 | public sealed class RKV2 : ArchiveNode, IHasIdentifier
10 | {
11 | public override bool CanWrite => false;
12 |
13 | public IIdentifier Identifier => _identifier;
14 |
15 | private static readonly Identifier32 _identifier = new("RKV2");
16 |
17 | public RKV2()
18 | {
19 | }
20 |
21 | public RKV2(string name) : base(name)
22 | {
23 | }
24 |
25 | public RKV2(FileNode source) : base(source)
26 | {
27 | }
28 |
29 | public override bool IsMatch(Stream stream, ReadOnlySpan extension = default)
30 | => stream.Match(_identifier);
31 |
32 | protected override void Deserialize(Stream source)
33 | {
34 | source.MatchThrow(_identifier);
35 | uint FileCount = source.ReadUInt32(Endian.Little);
36 | uint NameSize = source.ReadUInt32(Endian.Little);
37 | uint FullName_Files = source.ReadUInt32(Endian.Little);
38 | uint Dummy = source.ReadUInt32(Endian.Little);
39 | uint Info_Offset = source.ReadUInt32(Endian.Little);
40 | uint Dummy2 = source.ReadUInt32(Endian.Little);
41 |
42 | uint NameOffset = FileCount * 20 + Info_Offset;
43 |
44 | uint FullName_Offset = FileCount * 16 + (NameOffset + NameSize);
45 |
46 | source.Seek(Info_Offset, SeekOrigin.Begin);
47 | for (int i = 0; i < FileCount; i++)
48 | {
49 | uint NameOffsetForFile = (uint)source.ReadUInt32(Endian.Little);
50 | uint DummyForFile = (uint)source.ReadUInt32(Endian.Little);
51 | uint SizeForFile = (uint)source.ReadUInt32(Endian.Little);
52 | uint OffsetForFile = (uint)source.ReadUInt32(Endian.Little);
53 | uint CRCForFile = (uint)source.ReadUInt32(Endian.Little);
54 | long FilePosition = source.Position;
55 |
56 | source.Seek(NameOffsetForFile + NameOffset, SeekOrigin.Begin);
57 | string Name = source.ReadCString();
58 |
59 | FileNode Sub = new(Name, new SubStream(source, SizeForFile, OffsetForFile));
60 | //If Duplicate...
61 | if (Contains(Name))
62 | Sub.Name += i;
63 | Add(Sub);
64 |
65 | // Read the file, move on to the next one
66 | source.Seek(FilePosition, SeekOrigin.Begin);
67 | }
68 | }
69 |
70 | protected override void Serialize(Stream dest) => throw new NotImplementedException();
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/Formats/text.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Core.Interfaces;
3 |
4 | namespace AuroraLib.Texture.Formats
5 | {
6 | public class text_AQ : JUTTexture, IHasIdentifier, IFileAccess
7 | {
8 | public virtual bool CanRead => true;
9 |
10 | public virtual bool CanWrite => false;
11 |
12 | public virtual IIdentifier Identifier => _identifier;
13 |
14 | private static readonly byte[] _bytes = new byte[] { 0x63, 0x68, 0x6E, 0x6B, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00, 0x77, 0x69, 0x69, 0x20, 0x74, 0x65, 0x78, 0x74 };
15 |
16 | private static readonly Identifier _identifier = new(_bytes);
17 |
18 | //public static readonly Identifier32 Platform = new(_identifierbyte.AsSpan().Slice(12, 4)); // Wii
19 | //public static readonly Identifier32 Type = new(_identifierbyte.AsSpan().Slice(16, 4)); // text
20 |
21 | public bool IsMatch(Stream stream, ReadOnlySpan extension = default)
22 | => Matcher(stream, extension);
23 |
24 | public static bool Matcher(Stream stream, ReadOnlySpan extension = default)
25 | => stream.Length > 0x40 && stream.Match(_identifier);
26 |
27 | protected override void Read(Stream stream)
28 | {
29 | stream.Seek(0x10, SeekOrigin.Current);
30 | Header header = stream.Read(Endian.Big);
31 |
32 | Add(new TexEntry(stream, null, header.Format, GXPaletteFormat.IA8, 0, (int)header.Width, (int)header.Height, (int)header.Images - 1)
33 | {
34 | LODBias = 0,
35 | MagnificationFilter = GXFilterMode.Nearest,
36 | MinificationFilter = GXFilterMode.Nearest,
37 | WrapS = GXWrapMode.CLAMP,
38 | WrapT = GXWrapMode.CLAMP,
39 | EnableEdgeLOD = false,
40 | MinLOD = 0,
41 | MaxLOD = header.Images - 1
42 | });
43 | }
44 |
45 | protected override void Write(Stream stream) => throw new NotImplementedException();
46 |
47 | private struct Header
48 | {
49 | public uint Magic; // "text" 1952807028
50 | public uint pad; // 0x0
51 | public uint HeaderPos; // 0x10
52 | public uint Size;
53 |
54 | private uint format;
55 | public uint Width;
56 | public uint Height;
57 | public uint Images;
58 |
59 | public uint Unk3; // 56
60 | public uint HeadeSize; // 64
61 | public uint Unk5; // 13421772
62 | public uint Unk6; // 3435973836
63 |
64 | public GXImageFormat Format
65 | {
66 | get => (GXImageFormat)format;
67 | set => format = (uint)value;
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Archives/Formats/FTEX.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common.Node;
2 | using AuroraLib.Core.Interfaces;
3 |
4 | namespace AuroraLib.Archives.Formats
5 | {
6 | ///
7 | /// Vanillaware Muramasa Texture Archive
8 | ///
9 | public sealed class FTEX : ArchiveNode, IHasIdentifier
10 | {
11 | public override bool CanWrite => false;
12 |
13 | public IIdentifier Identifier => _identifier;
14 |
15 | private static readonly Identifier32 _identifier = new("FTEX");
16 |
17 | public FTEX()
18 | {
19 | }
20 |
21 | public FTEX(string name) : base(name)
22 | {
23 | }
24 |
25 | public FTEX(FileNode source) : base(source)
26 | {
27 | }
28 |
29 | public override bool IsMatch(Stream stream, ReadOnlySpan extension = default)
30 | => stream.Match(_identifier);
31 |
32 | protected override void Deserialize(Stream source)
33 | {
34 | Header header = source.Read();
35 | source.Seek(0x10, SeekOrigin.Current);
36 | NameEntry[] names = source.For((int)header.Entrys, s => new NameEntry(s));
37 |
38 | source.Seek(header.Offset, SeekOrigin.Begin);
39 | for (int i = 0; i < header.Entrys; i++)
40 | {
41 | FTX0 Entry = source.Read();
42 | source.Seek(Entry.Offset - 0x10, SeekOrigin.Current);
43 | FileNode file = new(names[i].Name, new SubStream(source, Entry.Size));
44 | Add(file);
45 | source.Seek(Entry.Size, SeekOrigin.Current);
46 | }
47 | }
48 |
49 | protected override void Serialize(Stream dest) => throw new NotImplementedException();
50 |
51 | private struct Header
52 | {
53 | public uint Magic; // FTEX 1480938566
54 | public uint Size;
55 | public uint Offset;
56 | public uint Entrys;
57 |
58 | public readonly uint FullSize => Size + Offset + 0x10;
59 | }
60 |
61 | private struct NameEntry
62 | {
63 | public string Name;
64 | public Propertie Properties;
65 |
66 | public NameEntry(Stream stream)
67 | {
68 | Name = stream.ReadString(0x20);
69 | Properties = stream.Read();
70 | }
71 |
72 | public struct Propertie
73 | {
74 | public uint Padding;
75 | public uint unk1;
76 | public uint unk2;
77 | public uint unk3;
78 | }
79 | }
80 |
81 | private struct FTX0
82 | {
83 | public uint Magic; // FTX0 811095110
84 | public uint Size;
85 | public uint Offset;
86 | public uint Padding;
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/Enums/UImageFormats.cs:
--------------------------------------------------------------------------------
1 | namespace AuroraLib.Texture
2 | {
3 | public enum AImageFormats : uint
4 | {
5 | ///
6 | GXI4 = 0x00,
7 | ///
8 | GXI8 = 0x01,
9 | ///
10 | GXIA4 = 0x02,
11 | ///
12 | GXIA8 = 0x03,
13 | ///
14 | GXRGB565 = 0x04,
15 | ///
16 | GXRGB5A3 = 0x05,
17 | ///
18 | GXRGBA32 = 0x06,
19 | ///
20 | GXC4 = 0x08,
21 | ///
22 | GXC8 = 0x09,
23 | ///
24 | GXC14X2 = 0x0A,
25 | ///
26 | CMPR = 0x0E,
27 |
28 | ///
29 | /// 4 bit intensity values.
30 | ///
31 | I4 = 0xC0000000,
32 | ///
33 | /// 8 bit intensity values.
34 | ///
35 | I8 = 0xC0000001,
36 | ///
37 | /// 4 bit intensity values, along with a 8 bit alpha channel
38 | ///
39 | IA4 = 0xC0000002,
40 | ///
41 | /// 8 bit intensity values, along with a 8 bit alpha channel.
42 | ///
43 | IA8 = 0xC0000003,
44 | ///
45 | /// 16 bit color values without alpha. The alpha component is set to 0xff.
46 | ///
47 | RGB565 = 0xC0000004,
48 | ///
49 | /// Either 15 bit color values without alpha, or 12 bit color values with a 3 bit alpha channel.
50 | ///
51 | RGB5A3 = 0xC0000005,
52 | ///
53 | /// 24 bit depth true color, with an 8 bit alpha channel.
54 | ///
55 | RGBA32 = 0xC0000006,
56 | ///
57 | /// Is a 4 bit palette format. Supports up to 16 different colors.
58 | ///
59 | C4 = 0xC0000008,
60 | ///
61 | /// Is an 8 bit palette format. Supports up to 256 different colors.
62 | ///
63 | C8 = 0xC0000009,
64 | ///
65 | /// Is a 14 bit palette format. Supports up to 16384 different colors.
66 | ///
67 | C14X2 = 0xC000000A,
68 | ///
69 | /// Compressed image format.
70 | ///
71 | DXT1 = 0xC000000E,
72 |
73 | ///
74 | /// 24 bit depth true color, with an 8 bit alpha channel. The PS2 uses 128 as maximum alpha value.
75 | ///
76 | PS2RGBA32 = 0xC1000006,
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/Formats/PIM.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Texture.PixelFormats;
3 | using System.Runtime.InteropServices;
4 | using SixLabors.ImageSharp.PixelFormats;
5 |
6 | namespace AuroraLib.Texture
7 | {
8 | public class PIM : JUTTexture, IFileAccess
9 | {
10 | public bool CanRead => true;
11 |
12 | public bool CanWrite => false;
13 |
14 | public const string Extension = ".PIM";
15 |
16 | public bool IsMatch(Stream stream, ReadOnlySpan extension = default)
17 | => extension.SequenceEqual(Extension);
18 |
19 | protected override void Read(Stream stream)
20 | {
21 | PIMHeader header = stream.Read();
22 | stream.Seek(header.POffset, SeekOrigin.Begin);
23 | Span palette = stackalloc byte[header.Colors * 4];
24 | stream.Read(palette);
25 | stream.Seek(header.IOffset, SeekOrigin.Begin);
26 |
27 | //The game reduces the colors from RGBA32 to RGB5A3 in real time.
28 | Span paletteRGBA = MemoryMarshal.Cast(palette);
29 | Span paletteRGB5A3 = MemoryMarshal.Cast(palette);
30 | for (int c = 0; c < header.Colors; c++)
31 | {
32 | //PS2 Alpha channel must be normalized.
33 | paletteRGBA[c].A = (byte)Math.Min(paletteRGBA[c].A * 2, 255);
34 | paletteRGB5A3[c].FromRgba32(paletteRGBA[c]);
35 | paletteRGB5A3[c].PackedValue = BitConverterX.Swap(paletteRGB5A3[c].PackedValue);
36 | }
37 |
38 | AImageFormats format = header.BPP switch
39 | {
40 | 4 => AImageFormats.C4,
41 | 8 => AImageFormats.C8,
42 | 32 => AImageFormats.PS2RGBA32,
43 | _ => throw new NotImplementedException(),
44 | };
45 |
46 | TexEntry tex = new(stream, format, header.Width, header.Height)
47 | {
48 | LODBias = 0,
49 | MagnificationFilter = GXFilterMode.Nearest,
50 | MinificationFilter = GXFilterMode.Nearest,
51 | WrapS = GXWrapMode.CLAMP,
52 | WrapT = GXWrapMode.CLAMP,
53 | EnableEdgeLOD = false,
54 | MinLOD = 0,
55 | MaxLOD = 0,
56 | PaletteFormat = GXPaletteFormat.RGB5A3
57 | };
58 | tex.Palettes.Add(palette[..(header.Colors * 2)].ToArray());
59 | Add(tex);
60 | }
61 |
62 | protected override void Write(Stream stream) => throw new NotImplementedException();
63 |
64 | private struct PIMHeader
65 | {
66 | public ushort Width;
67 | public ushort Height;
68 | public ushort BPP;
69 | public ushort Colors;
70 | public uint POffset;
71 | public uint IOffset;
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/Formats/TXTR.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 |
3 | namespace AuroraLib.Texture.Formats
4 | {
5 | public class TXTR : JUTTexture, IFileAccess
6 | {
7 | public bool CanRead => true;
8 |
9 | public bool CanWrite => false;
10 |
11 | public const string Extension = ".txtr";
12 |
13 | public TXTR()
14 | { }
15 |
16 | public TXTR(Stream stream) : base(stream)
17 | {
18 | }
19 |
20 | public TXTR(string filepath) : base(filepath)
21 | {
22 | }
23 |
24 | public bool IsMatch(Stream stream, ReadOnlySpan extension = default)
25 | => extension.Contains(Extension, StringComparison.InvariantCultureIgnoreCase);
26 |
27 | protected override void Read(Stream stream)
28 | {
29 | TXTRImageFormat TXTRFormat = (TXTRImageFormat)stream.ReadUInt32(Endian.Big);
30 | GXImageFormat Format = (GXImageFormat)Enum.Parse(typeof(GXImageFormat), TXTRFormat.ToString());
31 | int ImageWidth = stream.ReadUInt16(Endian.Big);
32 | int ImageHeight = stream.ReadUInt16(Endian.Big);
33 | uint Images = stream.ReadUInt32(Endian.Big);
34 |
35 | Span palettedata = Span.Empty;
36 | int ColorsCount = 0;
37 | GXPaletteFormat PaletteFormat = GXPaletteFormat.IA8;
38 | if (Format.IsPaletteFormat())
39 | {
40 | PaletteFormat = (GXPaletteFormat)stream.ReadUInt32(Endian.Big);
41 | int CWidth = stream.ReadUInt16(Endian.Big);
42 | int CHeight = stream.ReadUInt16(Endian.Big);
43 | ColorsCount = CHeight * CWidth;
44 | palettedata = new byte[ColorsCount * 2];
45 | stream.Read(palettedata);
46 | }
47 |
48 | TexEntry current = new TexEntry(stream, palettedata, Format, PaletteFormat, ColorsCount, ImageWidth, ImageHeight, (int)Images - 1)
49 | {
50 | LODBias = 0,
51 | MagnificationFilter = GXFilterMode.Nearest,
52 | MinificationFilter = GXFilterMode.Nearest,
53 | WrapS = GXWrapMode.CLAMP,
54 | WrapT = GXWrapMode.CLAMP,
55 | EnableEdgeLOD = false,
56 | MinLOD = 0,
57 | MaxLOD = Images - 1
58 | };
59 | Add(current);
60 | }
61 |
62 | protected override void Write(Stream stream)
63 | {
64 | throw new NotImplementedException();
65 | }
66 |
67 | public enum TXTRImageFormat : uint
68 | {
69 | I4 = 0x00,
70 | I8 = 0x01,
71 | IA4 = 0x02,
72 | IA8 = 0x03,
73 | C4 = 0x04,
74 | C8 = 0x05,
75 | C14X2 = 0x06,
76 | RGB565 = 0x07,
77 | RGB5A3 = 0x08,
78 | RGBA32 = 0x09, //RGBA8?
79 | CMPR = 0x0A,
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/Interfaces/IGXTextureInfo.cs:
--------------------------------------------------------------------------------
1 | namespace AuroraLib.Texture.Interfaces
2 | {
3 | ///
4 | /// Defines the properties of a texture used by the GX API in the GameCube and Wii consoles.
5 | ///
6 | public interface IGXTextureInfo : IImageInfo
7 | {
8 | ///
9 | /// The image format of the texture.
10 | /// specifies how the data within the image is encoded.
11 | ///
12 | GXImageFormat Format { get; }
13 |
14 | ///
15 | /// The palette format of the texture.
16 | /// Only C4, C8, and C14X2 use palettes.
17 | ///
18 | GXPaletteFormat PaletteFormat { get; }
19 |
20 | ///
21 | /// The wrap mode for the S coordinate.
22 | /// Specifies how textures outside the vertical range [0..1] are treated for text coordinates.
23 | ///
24 | GXWrapMode WrapS { get; set; }
25 |
26 | ///
27 | /// The wrap mode for the T coordinate.
28 | /// Specifies how textures outside the horizontal range [0..1] are treated for text coordinates.
29 | ///
30 | GXWrapMode WrapT { get; set; }
31 |
32 | ///
33 | /// The magnification filter mode for the texture.
34 | /// specifies what type of filtering the file should use as magnification filter.
35 | ///
36 | GXFilterMode MagnificationFilter { get; set; }
37 |
38 | ///
39 | /// The minification filter mode for the texture.
40 | /// specifies what type of filtering the file should use as minification filter.
41 | ///
42 | GXFilterMode MinificationFilter { get; set; }
43 |
44 | ///
45 | /// The minimum level-of-detail for the texture.
46 | /// Exclude textures below a certain LOD level from being used.
47 | ///
48 | float MinLOD { get; set; }
49 |
50 | ///
51 | /// The maximum level-of-detail for the texture.
52 | /// Exclude textures above a certain LOD level from being used.
53 | /// A value larger than the actual textures should lead to culling.
54 | ///
55 | float MaxLOD { get; set; }
56 |
57 | ///
58 | /// The level-of-detail bias for the texture.
59 | /// A larger value leads to a larger camera distance before a lower LOD resolution is selected.
60 | ///
61 | float LODBias { get; set; }
62 |
63 | ///
64 | /// Indicating whether to enable edge level of detail (LOD) on the texture.
65 | /// When enabled, the LOD level is adjusted on the viewer distance to the texture's edges, resulting in smoother transitions.
66 | ///
67 | bool EnableEdgeLOD { get; set; }
68 |
69 | ///
70 | /// The number of mipmaps for the texture.
71 | ///
72 | int MipMaps { get; }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/Formats/PIL.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Texture.PixelFormats;
3 | using System.Runtime.InteropServices;
4 | using SixLabors.ImageSharp.PixelFormats;
5 |
6 | namespace AuroraLib.Texture.Formats
7 | {
8 | public class PIL : JUTTexture, IFileAccess
9 | {
10 | public bool CanRead => true;
11 |
12 | public bool CanWrite => false;
13 |
14 | public const string Extension = ".PIL";
15 |
16 | public bool IsMatch(Stream stream, ReadOnlySpan extension = default) => extension.SequenceEqual(Extension);
17 |
18 | protected override void Read(Stream stream)
19 | {
20 | uint images = stream.Read();
21 | stream.Seek(0x10, SeekOrigin.Begin);
22 | Span buffer = stackalloc byte[0x400];
23 | for (int i = 0; i < images; i++)
24 | {
25 | ushort width = stream.Read();
26 | ushort height = stream.Read();
27 | ushort BPP = stream.Read();
28 | ushort colors = stream.Read();
29 | string name = stream.ReadString(0x18);
30 | Span palette = buffer[..(colors * 4)];
31 | stream.Read(palette);
32 |
33 | //The game reduces the colors from RGBA32 to RGB5A3 in real time.
34 | Span paletteRGBA = MemoryMarshal.Cast(palette);
35 | Span paletteRGB5A3 = MemoryMarshal.Cast(palette);
36 | for (int c = 0; c < colors; c++)
37 | {
38 | //PS2 Alpha channel must be normalized
39 | paletteRGBA[c].A = (byte)Math.Min(paletteRGBA[c].A * 2, 255);
40 | paletteRGB5A3[c].FromRgba32(paletteRGBA[c]);
41 | paletteRGB5A3[c].PackedValue = BitConverterX.Swap(paletteRGB5A3[c].PackedValue);
42 | }
43 |
44 | AImageFormats format = BPP switch
45 | {
46 | 4 => AImageFormats.C4,
47 | 8 => AImageFormats.C8,
48 | 32 => AImageFormats.PS2RGBA32,
49 | _ => throw new NotImplementedException(),
50 | };
51 |
52 | TexEntry tex = new(stream, format, width, height)
53 | {
54 | LODBias = 0,
55 | MagnificationFilter = GXFilterMode.Nearest,
56 | MinificationFilter = GXFilterMode.Nearest,
57 | WrapS = GXWrapMode.CLAMP,
58 | WrapT = GXWrapMode.CLAMP,
59 | EnableEdgeLOD = false,
60 | MinLOD = 0,
61 | MaxLOD = 0,
62 | PaletteFormat = GXPaletteFormat.RGB5A3
63 | };
64 | tex.Palettes.Add(palette[..(colors * 2)].ToArray());
65 | Add(tex);
66 | }
67 | }
68 | protected override void Write(Stream stream) => throw new NotImplementedException();
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/lib/AuroraLip/Texture/Formats/TDL0.cs:
--------------------------------------------------------------------------------
1 | using AuroraLib.Common;
2 | using AuroraLib.Core.Buffers;
3 | using AuroraLib.Core.Interfaces;
4 |
5 | namespace AuroraLib.Texture.Formats
6 | {
7 | public class TDL0 : JUTTexture, IFileAccess, IHasIdentifier
8 | {
9 | public bool CanRead => true;
10 |
11 | public bool CanWrite => false;
12 |
13 | public virtual IIdentifier Identifier => Magic;
14 |
15 | public static readonly Identifier32 Magic = new("TDL0");
16 |
17 | public bool IsMatch(Stream stream, ReadOnlySpan extension = default)
18 | => stream.Length > 0x40 && stream.Match(Magic);
19 |
20 | protected override void Read(Stream stream)
21 | {
22 | Header header = stream.Read(Endian.Big);
23 | using SpanBuffer palette = new(header.PaletteSize * header.TextureCount);
24 | if (header.Format.IsPaletteFormat())
25 | stream.At(header.PaletteStart, s => s.Read(palette));
26 |
27 | for (int i = 0; i < header.TextureCount; i++)
28 | {
29 | TextureHeader texture = stream.Read(Endian.Big);
30 |
31 | stream.At(header.DataStart, s =>
32 | {
33 | TexEntry current = new(stream, palette.Slice(header.PaletteSize * i, header.PaletteSize), header.Format, GXPaletteFormat.RGB5A3, header.PaletteSize / 2, header.TotalWidth, header.TotalHeight, header.MipmapCount)
34 | {
35 | MinLOD = 0,
36 | MaxLOD = header.MipmapCount
37 | };
38 | Add(current);
39 | });
40 | }
41 | }
42 |
43 | protected override void Write(Stream stream) => throw new NotImplementedException();
44 |
45 | private struct Header
46 | {
47 | public readonly Identifier32 Magic;
48 | public readonly int unk;
49 | public readonly ushort TotalWidth;
50 | public readonly ushort TotalHeight;
51 | public readonly ushort TextureCount;
52 | public readonly ushort MipmapCount;
53 | private readonly byte format;
54 | public readonly byte unk02;
55 | public readonly ushort PaletteSize;
56 | public readonly uint DataStart;
57 | public readonly uint PaletteStart;
58 |
59 | public readonly GXImageFormat Format => format switch
60 | {
61 | 4 => GXImageFormat.C4,
62 | 5 => GXImageFormat.C8,
63 | 8 => GXImageFormat.RGB5A3,
64 | 10 => GXImageFormat.CMPR,
65 | _ => throw new NotImplementedException(),
66 | };
67 | }
68 |
69 | private struct TextureHeader
70 | {
71 | public readonly int ID;
72 | public readonly ushort Width;
73 | public readonly ushort Height;
74 | public readonly ushort OffsetWidth;
75 | public readonly ushort OffsetHeight;
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------