From e64f4425d5c468ee8faa41f14c1eb563bef1880b Mon Sep 17 00:00:00 2001 From: Kurt Date: Tue, 7 Jul 2015 21:24:58 -0700 Subject: [PATCH] Add SMDH (Icon) class --- pk3DS/3DS/SMDH.cs | 188 +++++++++++++++++++++++++++++++++++++++++++++ pk3DS/pk3DS.csproj | 1 + 2 files changed, 189 insertions(+) create mode 100644 pk3DS/3DS/SMDH.cs diff --git a/pk3DS/3DS/SMDH.cs b/pk3DS/3DS/SMDH.cs new file mode 100644 index 0000000..f933596 --- /dev/null +++ b/pk3DS/3DS/SMDH.cs @@ -0,0 +1,188 @@ +using System; +using System.Drawing; +using System.IO; +using System.Text; + +namespace CTR +{ + // System Menu Data Header + class SMDH + { + public uint Magic; + public ushort Version; + public ushort Reserved2; + public ApplicationInfo[] AppInfo = new ApplicationInfo[16]; + public ApplicationSettings AppSettings; + public ulong Reserved8; + public SmallIcon SmallIcon; + public LargeIcon LargeIcon; + + public SMDH(byte[] data) + { + Read(new BinaryReader(new MemoryStream(data))); + } + public SMDH(string path) + { + Read(new BinaryReader(File.OpenRead(path))); + } + public void Read(BinaryReader br) + { + // Check to see if the first 4 bytes (magic) is valid. + if (br.BaseStream.Length != 0x36C0 || (Magic = br.ReadUInt32()) != 0x48444D53) + return; // Abort + + Version = br.ReadUInt16(); + Reserved2 = br.ReadUInt16(); + + for (int i = 0; i < 16; i++) + AppInfo[i] = new ApplicationInfo(br); + + AppSettings = new ApplicationSettings(br); + Reserved8 = br.ReadUInt64(); + SmallIcon = new SmallIcon(br); + LargeIcon = new LargeIcon(br); + } + public byte[] Write() + { + using (var ms = new MemoryStream()) + using (var bw = new BinaryWriter(ms)) + { + bw.Write(Magic); + bw.Write(Version); + bw.Write(Reserved2); + for (int i = 0; i < 16; i++) AppInfo[i].Write(bw); + AppSettings.Write(bw); + bw.Write(Reserved8); + SmallIcon.Write(bw); + LargeIcon.Write(bw); + return ms.ToArray(); + } + } + } + + // Thanks to Gericom for EveryFileExplorer's SMDH.cs as a basis for the object code (and AppSettings enumeration) + class ApplicationInfo + { + public String ShortDescription; //0x80 + public String LongDescription; //0x100 + public String Publisher; //0x80 + public ApplicationInfo(BinaryReader br) + { + ShortDescription = Encoding.Unicode.GetString(br.ReadBytes(0x80)).TrimEnd('\0'); + LongDescription = Encoding.Unicode.GetString(br.ReadBytes(0x100)).TrimEnd('\0'); + Publisher = Encoding.Unicode.GetString(br.ReadBytes(0x80)).TrimEnd('\0'); + } + public void Write(BinaryWriter bw) + { + bw.Write(Encoding.Unicode.GetBytes(ShortDescription.PadRight(64, '\0'))); + bw.Write(Encoding.Unicode.GetBytes(LongDescription.PadRight(64, '\0'))); + bw.Write(Encoding.Unicode.GetBytes(Publisher.PadRight(64, '\0'))); + } + } + + class ApplicationSettings + { + public byte[] GameRatings; //0x10 + public RegionLockoutFlags RegionLockout; + public UInt32 MatchMakerID; + public UInt64 MatchMakerBITID; + public AppSettingsFlags Flags; + public UInt16 EULAVersion; + public UInt16 Reserved; + public Single AnimationDefaultFrame; + public UInt32 StreetPassID; + + public enum RegionLockoutFlags : uint + { + Japan = 0x01, + NorthAmerica = 0x02, + Europe = 0x04, + Australia = 0x08, + China = 0x10, + Korea = 0x20, + Taiwan = 0x40 + } + public enum AppSettingsFlags : uint + { + Visible = 1, + AutoBoot = 2, + Allow3D = 4, + ReqAcceptEULA = 8, + AutoSaveOnExit = 16, + UsesExtendedBanner = 32, + ReqRegionGameRating = 64, + UsesSaveData = 128, + RecordUsage = 256, + DisableSDSaveBackup = 512 + } + public ApplicationSettings(BinaryReader br) + { + GameRatings = br.ReadBytes(0x10); + RegionLockout = (RegionLockoutFlags)br.ReadUInt32(); + MatchMakerID = br.ReadUInt32(); + MatchMakerBITID = br.ReadUInt64(); + Flags = (AppSettingsFlags)br.ReadUInt32(); + EULAVersion = br.ReadUInt16(); + Reserved = br.ReadUInt16(); + AnimationDefaultFrame = br.ReadSingle(); + StreetPassID = br.ReadUInt32(); + } + public void Write(BinaryWriter bw) + { + bw.Write(GameRatings, 0, 0x10); + bw.Write((uint)RegionLockout); + bw.Write(MatchMakerID); + bw.Write(MatchMakerBITID); + bw.Write((uint)Flags); + bw.Write(EULAVersion); + bw.Write(Reserved); + bw.Write(AnimationDefaultFrame); + bw.Write(StreetPassID); + } + } + + class SmallIcon // 24x24 + { + public Bitmap Icon; + public byte[] Bytes; + public SmallIcon(BinaryReader br) + { + Bytes = br.ReadBytes(0x480); + Icon = BCLIM.getIMG(24, 24, Bytes, 0x5); + } + public void Write(BinaryWriter bw) + { + bw.Write(Bytes); + } + public bool ChangeIcon(Bitmap img) + { + if (img.Width != Icon.Width || img.Height != Icon.Height) return false; + Icon = img; + Bytes = BCLIM.getPixelData(Icon, 0x5); + return true; + } + } + + class LargeIcon // 48x48 + { + public Bitmap Icon; + public byte[] Bytes; + public LargeIcon(BinaryReader br) + { + Bytes = br.ReadBytes(0x2000); + Icon = BCLIM.getIMG(48, 48, Bytes, 0x5); + } + public void Write(BinaryWriter bw) + { + bw.Write(Bytes); + Bytes = BCLIM.getPixelData(Icon, 0x5); + } + public bool ChangeIcon(Bitmap img) + { + if (img.Width != Icon.Width || img.Height != Icon.Height) return false; + Icon = img; + Bytes = BCLIM.getPixelData(Icon, 0x5); + return true; + } + } +} diff --git a/pk3DS/pk3DS.csproj b/pk3DS/pk3DS.csproj index c732edb..2d1b3b6 100644 --- a/pk3DS/pk3DS.csproj +++ b/pk3DS/pk3DS.csproj @@ -54,6 +54,7 @@ +