diff --git a/exeinfogui.XamMac/exeinfogui.XamMac.csproj b/exeinfogui.XamMac/exeinfogui.XamMac.csproj index 3eb2af0..8e66985 100644 --- a/exeinfogui.XamMac/exeinfogui.XamMac.csproj +++ b/exeinfogui.XamMac/exeinfogui.XamMac.csproj @@ -9,6 +9,7 @@ v2.0 Xamarin.Mac Resources + 0.2 false diff --git a/iconviewer/iconviewer.Desktop/Info.plist b/iconviewer/iconviewer.Desktop/Info.plist new file mode 100644 index 0000000..8d03c79 --- /dev/null +++ b/iconviewer/iconviewer.Desktop/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleName + iconviewer + CFBundleIdentifier + com.example.iconviewer + CFBundleShortVersionString + 1.0 + LSMinimumSystemVersion + 10.7 + CFBundleDevelopmentRegion + en + NSHumanReadableCopyright + + CFBundleIconFile + MacIcon.icns + + diff --git a/iconviewer/iconviewer.Desktop/MacIcon.icns b/iconviewer/iconviewer.Desktop/MacIcon.icns new file mode 100644 index 0000000..8f385bb Binary files /dev/null and b/iconviewer/iconviewer.Desktop/MacIcon.icns differ diff --git a/iconviewer/iconviewer.Desktop/Program.cs b/iconviewer/iconviewer.Desktop/Program.cs new file mode 100644 index 0000000..f8e1c81 --- /dev/null +++ b/iconviewer/iconviewer.Desktop/Program.cs @@ -0,0 +1,15 @@ +using System; +using Eto.Forms; +using Eto.Drawing; + +namespace iconviewer.Desktop +{ + class Program + { + [STAThread] + static void Main(string[] args) + { + new Application(Eto.Platform.Detect).Run(new MainForm()); + } + } +} \ No newline at end of file diff --git a/iconviewer/iconviewer.Desktop/iconviewer.Desktop.csproj b/iconviewer/iconviewer.Desktop/iconviewer.Desktop.csproj new file mode 100644 index 0000000..43d70f2 --- /dev/null +++ b/iconviewer/iconviewer.Desktop/iconviewer.Desktop.csproj @@ -0,0 +1,17 @@ + + + + WinExe + net461 + + + + + + + + + + + + diff --git a/iconviewer/iconviewer/MainForm.xeto b/iconviewer/iconviewer/MainForm.xeto new file mode 100644 index 0000000..e8b1a0a --- /dev/null +++ b/iconviewer/iconviewer/MainForm.xeto @@ -0,0 +1,31 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/iconviewer/iconviewer/MainForm.xeto.cs b/iconviewer/iconviewer/MainForm.xeto.cs new file mode 100644 index 0000000..ff8954c --- /dev/null +++ b/iconviewer/iconviewer/MainForm.xeto.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Linq; +using Eto.Forms; +using Eto.Drawing; +using Eto.Serialization.Xaml; +using Bitmap = libexeinfo.Os2.Bitmap; + +namespace iconviewer +{ + public class MainForm : Form + { + ImageView imgIcon; + TextBox txtPath; + + public MainForm() + { + XamlReader.Load(this); + } + + protected void OnBtnPathClick(object sender, EventArgs e) + { + OpenFileDialog dlgOpenFileDialog = new OpenFileDialog {MultiSelect = false}; + dlgOpenFileDialog.Filters.Add(new FileFilter {Extensions = new[] {".ico"}}); + DialogResult result = dlgOpenFileDialog.ShowDialog(this); + + if(result != DialogResult.Ok) + { + txtPath.Text = ""; + imgIcon.Image = null; + return; + } + + txtPath.Text = dlgOpenFileDialog.FileName; + FileStream fstream = new FileStream(dlgOpenFileDialog.FileName, FileMode.Open); + byte[] data = new byte[fstream.Length]; + fstream.Read(data, 0, data.Length); + fstream.Dispose(); + + Bitmap.DecodedBitmap[] icons = libexeinfo.Os2.Bitmap.DecodeBitmap(data); + imgIcon.Image = new Eto.Drawing.Bitmap((int)icons[0].Width, (int)icons[0].Height, PixelFormat.Format32bppRgba, + icons[0].Pixels); + } + + protected void HandleAbout(object sender, EventArgs e) + { + new AboutDialog().ShowDialog(this); + } + + protected void HandleQuit(object sender, EventArgs e) + { + Application.Instance.Quit(); + } + } +} diff --git a/iconviewer/iconviewer/iconviewer.csproj b/iconviewer/iconviewer/iconviewer.csproj new file mode 100644 index 0000000..b931614 --- /dev/null +++ b/iconviewer/iconviewer/iconviewer.csproj @@ -0,0 +1,24 @@ + + + netstandard2.0 + iconviewer + 1.0 + iconviewer + Copyright © 2018 + Description of iconviewer + 0.2 + + + false + + + false + + + + + + + + + \ No newline at end of file diff --git a/libexeinfo.sln b/libexeinfo.sln index c0343ad..8149280 100644 --- a/libexeinfo.sln +++ b/libexeinfo.sln @@ -11,6 +11,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "exeinfogui.Desktop", "exein EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "exeinfogui.XamMac", "exeinfogui.XamMac\exeinfogui.XamMac.csproj", "{E2DC1857-A942-419B-849E-58AC8BBB94CD}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iconviewer", "iconviewer\iconviewer\iconviewer.csproj", "{D6282B50-9A8D-44C5-8674-43BED27B5B53}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iconviewer.Desktop", "iconviewer\iconviewer.Desktop\iconviewer.Desktop.csproj", "{3206160A-B6AB-4B90-AC29-888C7E64A2CE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x86 = Debug|x86 @@ -37,6 +41,14 @@ Global {E2DC1857-A942-419B-849E-58AC8BBB94CD}.Debug|x86.Build.0 = Debug|Any CPU {E2DC1857-A942-419B-849E-58AC8BBB94CD}.Release|x86.ActiveCfg = Release|Any CPU {E2DC1857-A942-419B-849E-58AC8BBB94CD}.Release|x86.Build.0 = Release|Any CPU + {D6282B50-9A8D-44C5-8674-43BED27B5B53}.Debug|x86.ActiveCfg = Debug|Any CPU + {D6282B50-9A8D-44C5-8674-43BED27B5B53}.Debug|x86.Build.0 = Debug|Any CPU + {D6282B50-9A8D-44C5-8674-43BED27B5B53}.Release|x86.ActiveCfg = Release|Any CPU + {D6282B50-9A8D-44C5-8674-43BED27B5B53}.Release|x86.Build.0 = Release|Any CPU + {3206160A-B6AB-4B90-AC29-888C7E64A2CE}.Debug|x86.ActiveCfg = Debug|Any CPU + {3206160A-B6AB-4B90-AC29-888C7E64A2CE}.Debug|x86.Build.0 = Debug|Any CPU + {3206160A-B6AB-4B90-AC29-888C7E64A2CE}.Release|x86.ActiveCfg = Release|Any CPU + {3206160A-B6AB-4B90-AC29-888C7E64A2CE}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution version = 0.2 diff --git a/libexeinfo/Os2/Bitmap.cs b/libexeinfo/Os2/Bitmap.cs new file mode 100644 index 0000000..ee77247 --- /dev/null +++ b/libexeinfo/Os2/Bitmap.cs @@ -0,0 +1,268 @@ +// +// Accelerator.cs +// +// Author: +// Natalia Portillo +// +// Copyright (c) 2017 Copyright © Claunia.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; + +namespace libexeinfo.Os2 +{ + public class Bitmap + { + /// + /// 'IC', OS/2 only, icon + /// + public const ushort TYPE_ICON = 0x4349; + /// + /// 'BM', OS/2 and Windows, bitmap + /// + public const ushort TYPE_BITMAP = 0x4D42; + /// + /// 'PT', OS/2 only, cursor + /// + public const ushort TYPE_POINTER = 0x5450; + /// + /// 'CI', OS/2 only, color icon + /// + public const ushort TYPE_COLOR_ICON = 0x4943; + /// + /// 'CP', OS/2 only, color cursor + /// + public const ushort TYPE_COLOR_POINTER = 0x5043; + /// + /// 'BA', OS/2 only, bitmap array + /// + public const ushort TYPE_BITMAP_ARRAY = 0x4142; + + /// + /// This will decode a bitmap array, or if data is not an array, return an array with the single bitmap element + /// + /// Data + /// Array of , one per bitmap, null if the bitmap could not be decoded + public static DecodedBitmap[] DecodeBitmap(byte[] data) + { + long pos = 0; + BitmapArrayHeader bitmapArrayHeader; + BitmapInfoHeader bitmapFileHeader; + byte[] buffer = new byte[Marshal.SizeOf(typeof(BitmapInfoHeader))]; + + Array.Copy(data, pos, buffer, 0, buffer.Length); + bitmapArrayHeader = BigEndianMarshal.ByteArrayToStructureLittleEndian(buffer); + bitmapFileHeader = BigEndianMarshal.ByteArrayToStructureLittleEndian(buffer); + + List headers = new List(); + List palettes = new List(); + List datas = new List(); + + do + { + Array.Copy(data, pos, buffer, 0, buffer.Length); + bitmapArrayHeader = BigEndianMarshal.ByteArrayToStructureLittleEndian(buffer); + long remaining; + + if(bitmapArrayHeader.Type == TYPE_BITMAP_ARRAY) + { + remaining = bitmapArrayHeader.Size - Marshal.SizeOf(typeof(BitmapArrayHeader)); + pos += Marshal.SizeOf(typeof(BitmapArrayHeader)); + } + else + { + remaining = 1; + pos = 0; + } + + while(remaining > 0) + { + buffer = new byte[Marshal.SizeOf(typeof(BitmapInfoHeader))]; + Array.Copy(data, pos, buffer, 0, buffer.Length); + bitmapFileHeader = BigEndianMarshal.ByteArrayToStructureLittleEndian(buffer); + + // Stop at unknown header + if(bitmapFileHeader.Size != Marshal.SizeOf(typeof(BitmapInfoHeader))) break; + + // Multiplanes not supported + if(bitmapFileHeader.Planes != 1) break; + + // TODO: Non paletted? + pos += bitmapFileHeader.Size; + RGB[] palette = new RGB[1 << bitmapFileHeader.BitsPerPlane]; + buffer = new byte[Marshal.SizeOf(typeof(RGB))]; + for(int i = 0; i < palette.Length; i++) + { + Array.Copy(data, pos, buffer, 0, buffer.Length); + pos += buffer.Length; + palette[i] = BigEndianMarshal.ByteArrayToStructureLittleEndian(buffer); + } + + headers.Add(bitmapFileHeader); + palettes.Add(palette); + remaining -= bitmapFileHeader.Fix; + // rgb[1]; + remaining -= 1; + + buffer = new byte[bitmapFileHeader.X * bitmapFileHeader.Y * bitmapFileHeader.BitsPerPlane / 8]; + Array.Copy(data, bitmapFileHeader.Offset, buffer, 0, buffer.Length); + datas.Add(buffer); + } + + pos = bitmapArrayHeader.Next; + } + while(bitmapArrayHeader.Next != 0); + + DecodedBitmap[] bitmaps = new DecodedBitmap[datas.Count]; + + for(int b = 0; b < bitmaps.Length; b++) bitmaps[b] = DecodeBitmap(headers[b], palettes[b], datas[b]); + + return bitmaps; + } + + static DecodedBitmap DecodeBitmap(BitmapInfoHeader header, IList palette, byte[] data) + { + DecodedBitmap bitmap = new DecodedBitmap + { + BitsPerPixel = header.BitsPerPlane, + Height = header.Y, + Width = header.X, + XHotspot = header.XHotspot, + YHostpot = header.YHostpot, + Pixels = new int[header.X * header.Y] + }; + + switch(header.Type) + { + case TYPE_ICON: + bitmap.Type = "Icon"; + break; + case TYPE_BITMAP: + bitmap.Type = "Bitmap"; + break; + case TYPE_POINTER: + bitmap.Type = "Pointer"; + break; + case TYPE_COLOR_ICON: + bitmap.Type = "Color Icon"; + break; + case TYPE_COLOR_POINTER: + bitmap.Type = "Color Pointer"; + break; + default: return null; + } + + const int VISIBLE = -16777216; + int[] argbPalette = new int[palette.Count]; + + for(int c = 0; c < palette.Count; c++) + argbPalette[c] = (palette[c].Red << 16) + (palette[c].Green << 8) + palette[c].Blue; + + long pos = 0; + + for(int y = 0; y < bitmap.Height; y++) + { + int x = 0; + while(x < bitmap.Width) + { + for(int k = (int)(8 - bitmap.BitsPerPixel); k >= 0; k -= (int)bitmap.BitsPerPixel) + { + bitmap.Pixels[y * bitmap.Width + x] = + argbPalette[(data[pos] >> k) & ((1 << (int)bitmap.BitsPerPixel) - 1)]; + x++; + } + + pos++; + } + + pos += pos % 2; + } + + // First image, then mask + if(header.Type == TYPE_ICON || header.Type == TYPE_POINTER) + { + int[] icon = new int[bitmap.Width * bitmap.Height / 2]; + int[] mask = new int[bitmap.Width * bitmap.Height / 2]; + Array.Copy(bitmap.Pixels, 0, icon, 0, icon.Length); + Array.Copy(bitmap.Pixels, icon.Length, mask, 0, mask.Length); + + bitmap.Pixels = new int[bitmap.Width * bitmap.Height / 2]; + bitmap.Height /= 2; + for(int px = 0; px < bitmap.Pixels.Length; px++) + bitmap.Pixels[px] = icon[px] + (mask[px] == argbPalette[0] ? VISIBLE : 0); + } + + // OS/2 coordinate 0,0 is lower,left, so need to reverse first all pixels then by line + int[] pixels = bitmap.Pixels.Reverse().ToArray(); + for(int y = 0; y < bitmap.Height; y++) + for(int x = 0; x < bitmap.Width; x++) + bitmap.Pixels[y * bitmap.Width + (bitmap.Width - x - 1)] = pixels[y * bitmap.Width + x]; + + return bitmap; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct BitmapArrayHeader + { + public ushort Type; + public uint Size; + public uint Next; + public ushort XDisplay; + public ushort YDisplay; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct BitmapInfoHeader + { + public ushort Type; + public uint Size; + public short XHotspot; + public short YHostpot; + public uint Offset; + public uint Fix; + public ushort X; + public ushort Y; + public ushort Planes; + public ushort BitsPerPlane; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct RGB + { + public byte Blue; + public byte Green; + public byte Red; + } + + public class DecodedBitmap + { + public uint BitsPerPixel; + public uint Height; + public int[] Pixels; + public string Type; + public uint Width; + public short XHotspot; + public short YHostpot; + } + } +} \ No newline at end of file diff --git a/libexeinfo/libexeinfo.csproj b/libexeinfo/libexeinfo.csproj index 69655d5..8400588 100644 --- a/libexeinfo/libexeinfo.csproj +++ b/libexeinfo/libexeinfo.csproj @@ -58,6 +58,7 @@ +