commit 27dc2ec95311edbc98cb6dbc79b94d57ffb1815e Author: Admiral H. Curtiss Date: Fri May 16 16:02:27 2014 +0200 First version, converts files and displays some info. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2967fea --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +bin +obj +*.user diff --git a/MysteryGiftConvert.csproj b/MysteryGiftConvert.csproj new file mode 100644 index 0000000..20fd693 --- /dev/null +++ b/MysteryGiftConvert.csproj @@ -0,0 +1,58 @@ + + + + Debug + x86 + 8.0.30703 + 2.0 + {824EB93B-B6CE-4DA6-831B-006EBBA5A8A4} + Exe + Properties + MysteryGiftConvert + MysteryGiftConvert + v4.0 + Client + 512 + + + x86 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..a3e1563 --- /dev/null +++ b/Program.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; + +namespace MysteryGiftConvert { + class Program { + static void Main( string[] args ) { + if ( args.Length < 1 ) { + Console.WriteLine( "Usage: MysteryGiftConvert infile.pcd [outfile.myg]" ); + return; + } + + string inFilename = args[0]; + var file = File.ReadAllBytes( inFilename ); + + if ( file.Length != 856 ) { + Console.WriteLine( "Input is not a Generation 4 pcd file!" ); + return; + } + + // display some info about the wonder card + ushort cardId = BitConverter.ToUInt16( file, 0x150 ); + Console.WriteLine( "Card ID: " + cardId ); + + string outFilename = args.Length >= 2 ? args[1] : cardId + ".myg"; + + ushort gameBitmask = BitConverter.ToUInt16( file, 0x14C ); + Console.Write( "This Mystery Gift is valid for:" ); + if ( ( gameBitmask & 0x0400 ) == 0x0400 ) { Console.Write( " Diamond" ); } + if ( ( gameBitmask & 0x0800 ) == 0x0800 ) { Console.Write( " Pearl" ); } + if ( ( gameBitmask & 0x1000 ) == 0x1000 ) { Console.Write( " Platinum" ); } + if ( ( gameBitmask & 0x0080 ) == 0x0080 ) { Console.Write( " HeartGold" ); } + if ( ( gameBitmask & 0x0100 ) == 0x0100 ) { Console.Write( " SoulSilver" ); } + Console.WriteLine(); + + // to convert a pcd into a wifi-distributable wonder card file, copy the short description and "header" data from 0x104 to 0x154 to the start of the file + var outStream = new FileStream( outFilename, FileMode.Create ); + + outStream.Write( file, 0x104, 0x50 ); + outStream.Write( file, 0, file.Length ); + + outStream.Close(); + + Console.WriteLine( "Converted " + Path.GetFileName( inFilename ) + " to " + Path.GetFileName( outFilename ) + "!" ); + } + } +} diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..e51382d --- /dev/null +++ b/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle( "MysteryGiftConvert" )] +[assembly: AssemblyDescription( "" )] +[assembly: AssemblyConfiguration( "" )] +[assembly: AssemblyCompany( "" )] +[assembly: AssemblyProduct( "MysteryGiftConvert" )] +[assembly: AssemblyCopyright( "Copyright © 2014" )] +[assembly: AssemblyTrademark( "" )] +[assembly: AssemblyCulture( "" )] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible( false )] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid( "f1c84fe0-b62d-4ef9-830a-d662b80a33ef" )] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion( "1.0.0.0" )] +[assembly: AssemblyFileVersion( "1.0.0.0" )] diff --git a/Util.cs b/Util.cs new file mode 100644 index 0000000..0bd45ac --- /dev/null +++ b/Util.cs @@ -0,0 +1,188 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; + +namespace MysteryGiftConvert { + public static class Util { + + #region SwapEndian + public static Int16 SwapEndian( this Int16 x ) { + return (Int16)SwapEndian( (UInt16)x ); + } + public static UInt16 SwapEndian( this UInt16 x ) { + return x = (UInt16) + ( ( x << 8 ) | + ( x >> 8 ) ); + } + + public static Int32 SwapEndian( this Int32 x ) { + return (Int32)SwapEndian( (UInt32)x ); + } + public static UInt32 SwapEndian( this UInt32 x ) { + return x = ( x << 24 ) | + ( ( x << 8 ) & 0x00FF0000 ) | + ( ( x >> 8 ) & 0x0000FF00 ) | + ( x >> 24 ); + } + + public static Int64 SwapEndian( this Int64 x ) { + return (Int64)SwapEndian( (UInt64)x ); + } + public static UInt64 SwapEndian( this UInt64 x ) { + return x = ( x << 56 ) | + ( ( x << 40 ) & 0x00FF000000000000 ) | + ( ( x << 24 ) & 0x0000FF0000000000 ) | + ( ( x << 8 ) & 0x000000FF00000000 ) | + ( ( x >> 8 ) & 0x00000000FF000000 ) | + ( ( x >> 24 ) & 0x0000000000FF0000 ) | + ( ( x >> 40 ) & 0x000000000000FF00 ) | + ( x >> 56 ); + } + #endregion + + #region NumberUtils + public static uint ToUInt24( byte[] File, int Pointer ) { + byte b1 = File[Pointer]; + byte b2 = File[Pointer + 1]; + byte b3 = File[Pointer + 2]; + + return (uint)( b3 << 16 | b2 << 8 | b1 ); + } + + public static byte[] GetBytesForUInt24( uint Number ) { + byte[] b = new byte[3]; + b[0] = (byte)( Number & 0xFF ); + b[1] = (byte)( ( Number >> 8 ) & 0xFF ); + b[2] = (byte)( ( Number >> 16 ) & 0xFF ); + return b; + } + + /// + /// converts a 32-bit int that's actually a byte representation of a float + /// to an actual float for use in calculations or whatever + /// + public static float UIntToFloat( uint integer ) { + byte[] b = BitConverter.GetBytes( integer ); + float f = BitConverter.ToSingle( b, 0 ); + return f; + } + + public static int Align( int Number, int Alignment ) { + return (int)Align( (uint)Number, (uint)Alignment ); + } + public static uint Align( uint Number, uint Alignment ) { + uint diff = Number % Alignment; + if ( diff == 0 ) { + return Number; + } else { + return ( Number + ( Alignment - diff ) ); + } + } + #endregion + + public static void CopyByteArrayPart( IList from, int locationFrom, IList to, int locationTo, int count ) { + for ( int i = 0; i < count; i++ ) { + to[locationTo + i] = from[locationFrom + i]; + } + } + + public static void CopyStream( System.IO.Stream input, System.IO.Stream output, int count ) { + byte[] buffer = new byte[4096]; + int read; + + int bytesLeft = count; + while ( ( read = input.Read( buffer, 0, Math.Min( buffer.Length, bytesLeft ) ) ) > 0 ) { + output.Write( buffer, 0, read ); + bytesLeft -= read; + if ( bytesLeft <= 0 ) return; + } + } + + public static void FillNull( IList Array, int Location, int Count ) { + for ( int i = 0; i < Count; ++i ) { + Array[Location + i] = 0x00; + } + } + + public static bool IsByteArrayPartEqual( IList Array1, int Location1, IList Array2, int Location2, int count ) { + for ( int i = 0; i < count; ++i ) { + if ( Array1[i + Location1] != Array2[i + Location2] ) { + return false; + } + } + return true; + } + + public static uint ReadUInt32( this Stream s ) { + int b1 = s.ReadByte(); + int b2 = s.ReadByte(); + int b3 = s.ReadByte(); + int b4 = s.ReadByte(); + + return (uint)( b4 << 24 | b3 << 16 | b2 << 8 | b1 ); + } + public static uint PeekUInt32( this Stream s ) { + long pos = s.Position; + uint retval = s.ReadUInt32(); + s.Position = pos; + return retval; + } + public static uint ReadUInt24( this Stream s ) { + int b1 = s.ReadByte(); + int b2 = s.ReadByte(); + int b3 = s.ReadByte(); + + return (uint)( b3 << 16 | b2 << 8 | b1 ); + } + public static uint PeekUInt24( this Stream s ) { + long pos = s.Position; + uint retval = s.ReadUInt24(); + s.Position = pos; + return retval; + } + public static ushort ReadUInt16( this Stream s ) { + int b1 = s.ReadByte(); + int b2 = s.ReadByte(); + + return (ushort)( b2 << 8 | b1 ); + } + public static ushort PeekUInt16( this Stream s ) { + long pos = s.Position; + ushort retval = s.ReadUInt16(); + s.Position = pos; + return retval; + } + public static string ReadAsciiNullterm( this Stream s ) { + StringBuilder sb = new StringBuilder(); + int b = s.ReadByte(); + while ( b != 0 && b != -1 ) { + sb.Append( (char)( b ) ); + b = s.ReadByte(); + } + return sb.ToString(); + } + public static string ReadAscii( this Stream s, int count ) { + StringBuilder sb = new StringBuilder( count ); + int b; + for ( int i = 0; i < count; ++i ) { + b = s.ReadByte(); + sb.Append( (char)( b ) ); + } + return sb.ToString(); + } + public static string ReadUTF16Nullterm( this Stream s ) { + StringBuilder sb = new StringBuilder(); + byte[] b = new byte[2]; + int b0 = s.ReadByte(); + int b1 = s.ReadByte(); + while ( !( b0 == 0 && b1 == 0 ) && b1 != -1 ) { + b[0] = (byte)b0; b[1] = (byte)b1; + sb.Append( Encoding.Unicode.GetString( b, 0, 2 ) ); + b0 = s.ReadByte(); b1 = s.ReadByte(); + } + return sb.ToString(); + } + } +}