diff --git a/ImageDecode/Format40.cs b/ImageDecode/Format40.cs index 3e6d6736f9..71f022a210 100644 --- a/ImageDecode/Format40.cs +++ b/ImageDecode/Format40.cs @@ -22,18 +22,6 @@ namespace ImageDecode return inp + ( ReadByte( input ) << 8 ); } - //static void ReplicatePrevious( byte[] dest, int destIndex, int srcIndex, int count ) - //{ - // for( int i = 0 ; i < Math.Min( count, destIndex - srcIndex ) ; i++ ) - // dest[ destIndex + i ] = dest[ srcIndex + i ]; - - // if( srcIndex + count <= destIndex ) - // return; - - // for( int i = destIndex + destIndex - srcIndex ; i < destIndex + count ; i++ ) - // dest[ i ] = dest[ destIndex - 1 ]; - //} - public static int DecodeInto( MemoryStream input, byte[] dest ) { int destIndex = 0; diff --git a/ImageDecode/ImageDecode.csproj b/ImageDecode/ImageDecode.csproj index f297956fa4..4d0cf29896 100644 --- a/ImageDecode/ImageDecode.csproj +++ b/ImageDecode/ImageDecode.csproj @@ -5,7 +5,7 @@ 8.0.50727 2.0 {39352FD2-28B0-4DF5-97C7-499CE1AECCB9} - Exe + Library Properties ImageDecode ImageDecode @@ -40,7 +40,6 @@ - diff --git a/ImageDecode/Program.cs b/ImageDecode/Program.cs deleted file mode 100644 index 50ad4ba1d2..0000000000 --- a/ImageDecode/Program.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.IO; -using System.Drawing; - -namespace ImageDecode -{ - public static class Program - { - [STAThread] - public static void Main() - { - ShpReader.Read( File.OpenRead( "stek.shp" ) ); - } - } -} diff --git a/ImageDecode/ShpReader.cs b/ImageDecode/ShpReader.cs index dbe651d95b..46db699288 100644 --- a/ImageDecode/ShpReader.cs +++ b/ImageDecode/ShpReader.cs @@ -10,8 +10,11 @@ namespace ImageDecode { public uint Offset; public Format Format; + public uint RefOffset; public Format RefFormat; + public ImageHeader RefImage; + public byte[] Image; public ImageHeader( BinaryReader reader ) @@ -32,53 +35,125 @@ namespace ImageDecode Format80 = 0x80, } - public static class ShpReader + public class ShpReader : IEnumerable { - public static IEnumerable Read( Stream stream ) + public readonly int ImageCount; + public readonly ushort Width; + public readonly ushort Height; + + private readonly List headers = new List(); + + int recurseDepth = 0; + + public ShpReader( Stream stream ) { BinaryReader reader = new BinaryReader( stream ); - ushort numImages = reader.ReadUInt16(); + ImageCount = reader.ReadUInt16(); reader.ReadUInt16(); reader.ReadUInt16(); - ushort width = reader.ReadUInt16(); - ushort height = reader.ReadUInt16(); + Width = reader.ReadUInt16(); + Height = reader.ReadUInt16(); reader.ReadUInt32(); - List headers = new List(); - for( int i = 0 ; i < numImages ; i++ ) + for( int i = 0 ; i < ImageCount ; i++ ) headers.Add( new ImageHeader( reader ) ); new ImageHeader( reader ); // end-of-file header new ImageHeader( reader ); // all-zeroes header + Dictionary offsets = new Dictionary(); foreach( ImageHeader h in headers ) - { - reader.BaseStream.Position = h.Offset; - switch( h.Format ) - { - case Format.Format20: - //throw new NotImplementedException(); - break; - case Format.Format40: - //throw new NotImplementedException(); - break; - case Format.Format80: - { - byte[] compressedBytes = reader.ReadBytes( (int)( reader.BaseStream.Length - reader.BaseStream.Position ) ); - MemoryStream ms = new MemoryStream( compressedBytes ); - byte[] imageBytes = new byte[ width * height ]; - Format80.DecodeInto( ms, imageBytes ); - h.Image = imageBytes; - break; - } - default: - throw new InvalidDataException(); - } + offsets.Add( h.Offset, h ); - if( h.Image != null ) - yield return h.Image; + for( int i = 0 ; i < ImageCount ; i++ ) + { + ImageHeader h = headers[ i ]; + if( h.Format == Format.Format20 ) + h.RefImage = headers[ i - 1 ]; + + else if( h.Format == Format.Format40 ) + { + if( !offsets.TryGetValue( h.RefOffset, out h.RefImage ) ) + throw new InvalidDataException( string.Format( "Reference doesnt point to image data {0}->{1}", h.Offset, h.RefOffset ) ); + } } + + foreach( ImageHeader h in headers ) + Decompress( stream, h ); + } + + public ImageHeader this[ int index ] + { + get { return headers[ index ]; } + } + + void Decompress( Stream stream, ImageHeader h ) + { + if( recurseDepth > ImageCount ) + throw new InvalidDataException( "Format20/40 headers contain infinite loop" ); + + switch( h.Format ) + { + case Format.Format20: + case Format.Format40: + { + if( h.RefImage.Image == null ) + { + ++recurseDepth; + Decompress( stream, h.RefImage ); + --recurseDepth; + } + + h.Image = CopyImageData( h.RefImage.Image ); + + MemoryStream ms = ReadCompressedData( stream, h ); + Format40.DecodeInto( ms, h.Image ); + break; + } + case Format.Format80: + { + MemoryStream ms = ReadCompressedData( stream, h ); + byte[] imageBytes = new byte[ Width * Height ]; + Format80.DecodeInto( ms, imageBytes ); + h.Image = imageBytes; + break; + } + default: + throw new InvalidDataException(); + } + } + + private static MemoryStream ReadCompressedData( Stream stream, ImageHeader h ) + { + stream.Position = h.Offset; + // Actually, far too big. There's no length field with the correct length though :( + int compressedLength = (int)( stream.Length - stream.Position ); + + byte[] compressedBytes = new byte[ compressedLength ]; + stream.Read( compressedBytes, 0, compressedLength ); + + MemoryStream ms = new MemoryStream( compressedBytes ); + return ms; + } + + private byte[] CopyImageData( byte[] baseImage ) + { + byte[] imageData = new byte[ Width * Height ]; + for( int i = 0 ; i < Width * Height ; i++ ) + imageData[ i ] = baseImage[ i ]; + + return imageData; + } + + public IEnumerator GetEnumerator() + { + return headers.GetEnumerator(); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return GetEnumerator(); } } } diff --git a/OpenRa.sln b/OpenRa.sln index e2659cf82e..bbe10aaa7a 100644 --- a/OpenRa.sln +++ b/OpenRa.sln @@ -1,12 +1,14 @@  Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual Studio 2005 +# Visual C# Express 2005 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MixBrowser", "MixBrowser\MixBrowser.csproj", "{E183D00B-FD2C-4001-8336-DF345DE281DA}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MixDecrypt", "MixDecrypt\MixDecrypt.vcproj", "{6F5D4280-3D23-41FF-AE2A-511B5553E377}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageDecode", "ImageDecode\ImageDecode.csproj", "{39352FD2-28B0-4DF5-97C7-499CE1AECCB9}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShpViewer", "ShpViewer\ShpViewer.csproj", "{4303FE72-B07F-4EBB-8CD2-5F33E44801B3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -47,6 +49,16 @@ Global {39352FD2-28B0-4DF5-97C7-499CE1AECCB9}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {39352FD2-28B0-4DF5-97C7-499CE1AECCB9}.Release|Mixed Platforms.Build.0 = Release|Any CPU {39352FD2-28B0-4DF5-97C7-499CE1AECCB9}.Release|Win32.ActiveCfg = Release|Any CPU + {4303FE72-B07F-4EBB-8CD2-5F33E44801B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4303FE72-B07F-4EBB-8CD2-5F33E44801B3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4303FE72-B07F-4EBB-8CD2-5F33E44801B3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {4303FE72-B07F-4EBB-8CD2-5F33E44801B3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {4303FE72-B07F-4EBB-8CD2-5F33E44801B3}.Debug|Win32.ActiveCfg = Debug|Any CPU + {4303FE72-B07F-4EBB-8CD2-5F33E44801B3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4303FE72-B07F-4EBB-8CD2-5F33E44801B3}.Release|Any CPU.Build.0 = Release|Any CPU + {4303FE72-B07F-4EBB-8CD2-5F33E44801B3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {4303FE72-B07F-4EBB-8CD2-5F33E44801B3}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {4303FE72-B07F-4EBB-8CD2-5F33E44801B3}.Release|Win32.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/ShpViewer/Program.cs b/ShpViewer/Program.cs new file mode 100644 index 0000000000..f18dc2c1f9 --- /dev/null +++ b/ShpViewer/Program.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Windows.Forms; +using System.IO; + +namespace ShpViewer +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault( false ); + + try + { + OpenFileDialog ofd = new OpenFileDialog(); + ofd.Filter = "SHP Files|*.shp"; + if( ofd.ShowDialog() == DialogResult.OK ) + Application.Run( new ShpViewForm( ofd.FileName ) ); + } + catch( Exception e ) + { + MessageBox.Show( e.ToString() ); + } + } + } +} \ No newline at end of file diff --git a/ShpViewer/Properties/AssemblyInfo.cs b/ShpViewer/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..b69d4a9b40 --- /dev/null +++ b/ShpViewer/Properties/AssemblyInfo.cs @@ -0,0 +1,33 @@ +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( "ShpViewer" )] +[assembly: AssemblyDescription( "" )] +[assembly: AssemblyConfiguration( "" )] +[assembly: AssemblyCompany( "" )] +[assembly: AssemblyProduct( "ShpViewer" )] +[assembly: AssemblyCopyright( "Copyright © 2007" )] +[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( "69816600-0431-4ad8-b648-47f5ac2d545c" )] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion( "1.0.0.0" )] +[assembly: AssemblyFileVersion( "1.0.0.0" )] diff --git a/ShpViewer/Properties/Resources.Designer.cs b/ShpViewer/Properties/Resources.Designer.cs new file mode 100644 index 0000000000..40bbc98e45 --- /dev/null +++ b/ShpViewer/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:2.0.50727.1318 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace ShpViewer.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute( "System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0" )] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute( "Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode" )] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute( global::System.ComponentModel.EditorBrowsableState.Advanced )] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if( ( resourceMan == null ) ) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager( "ShpViewer.Properties.Resources", typeof( Resources ).Assembly ); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute( global::System.ComponentModel.EditorBrowsableState.Advanced )] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/ShpViewer/Properties/Resources.resx b/ShpViewer/Properties/Resources.resx new file mode 100644 index 0000000000..ffecec851a --- /dev/null +++ b/ShpViewer/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/ShpViewer/Properties/Settings.Designer.cs b/ShpViewer/Properties/Settings.Designer.cs new file mode 100644 index 0000000000..08f469110c --- /dev/null +++ b/ShpViewer/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:2.0.50727.1318 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace ShpViewer.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute( "Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "8.0.0.0" )] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ( (Settings)( global::System.Configuration.ApplicationSettingsBase.Synchronized( new Settings() ) ) ); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/ShpViewer/Properties/Settings.settings b/ShpViewer/Properties/Settings.settings new file mode 100644 index 0000000000..abf36c5d3d --- /dev/null +++ b/ShpViewer/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/ShpViewer/ShpViewForm.Designer.cs b/ShpViewer/ShpViewForm.Designer.cs new file mode 100644 index 0000000000..b7c79d6e04 --- /dev/null +++ b/ShpViewer/ShpViewForm.Designer.cs @@ -0,0 +1,39 @@ +namespace ShpViewer +{ + partial class ShpViewForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose( bool disposing ) + { + if( disposing && ( components != null ) ) + { + components.Dispose(); + } + base.Dispose( disposing ); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Text = "Form1"; + } + + #endregion + } +} + diff --git a/ShpViewer/ShpViewForm.cs b/ShpViewer/ShpViewForm.cs new file mode 100644 index 0000000000..8c52754d70 --- /dev/null +++ b/ShpViewer/ShpViewForm.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Text; +using System.Windows.Forms; +using ImageDecode; +using System.IO; + +namespace ShpViewer +{ + public partial class ShpViewForm : Form + { + ShpReader shpReader; + List bitmaps = new List(); + + public ShpViewForm( string filename ) + { + shpReader = new ShpReader( File.OpenRead( filename ) ); + + foreach( ImageHeader h in shpReader ) + { + byte[] imageBytes = h.Image; + + Bitmap bitmap = new System.Drawing.Bitmap( shpReader.Width, shpReader.Height ); + for( int x = 0 ; x < shpReader.Width ; x++ ) + for( int y = 0 ; y < shpReader.Height ; y++ ) + bitmap.SetPixel( x, y, Color.FromArgb( imageBytes[ x + shpReader.Width * y ], 0, 0 ) ); + bitmaps.Add( bitmap ); + } + + InitializeComponent(); + } + + protected override void OnPaint( PaintEventArgs e ) + { + base.OnPaint( e ); + + int y = 10; + foreach( Bitmap b in bitmaps ) + { + e.Graphics.DrawImage( b, 10, y ); + y += 10 + b.Height; + } + } + } +} \ No newline at end of file diff --git a/ShpViewer/ShpViewer.csproj b/ShpViewer/ShpViewer.csproj new file mode 100644 index 0000000000..7287f38e41 --- /dev/null +++ b/ShpViewer/ShpViewer.csproj @@ -0,0 +1,82 @@ + + + Debug + AnyCPU + 8.0.50727 + 2.0 + {4303FE72-B07F-4EBB-8CD2-5F33E44801B3} + WinExe + Properties + ShpViewer + ShpViewer + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + + + + + + + + + + Form + + + ShpViewForm.cs + + + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + {39352FD2-28B0-4DF5-97C7-499CE1AECCB9} + ImageDecode + + + + + \ No newline at end of file