//
// System.Resources/Win32Resources.cs
//
// Author:
// Zoltan Varga (vargaz@freemail.hu)
//
// (C) 2003 Ximian, Inc. http://www.ximian.com
//
// An incomplete set of classes for manipulating Win32 resources
//
//
// Copyright (C) 2004 Novell, Inc (http://www.novell.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;
using System.Globalization;
using System.IO;
using System.Text;
namespace System.Resources{
internal enum Win32ResourceType {
RT_CURSOR = 1,
RT_FONT = 8,
RT_BITMAP = 2,
RT_ICON = 3,
RT_MENU = 4,
RT_DIALOG = 5,
RT_STRING = 6,
RT_FONTDIR = 7,
RT_ACCELERATOR = 9,
RT_RCDATA = 10,
RT_MESSAGETABLE = 11,
RT_GROUP_CURSOR = 12,
RT_GROUP_ICON = 14,
RT_VERSION = 16,
RT_DLGINCLUDE = 17,
RT_PLUGPLAY = 19,
RT_VXD = 20,
RT_ANICURSOR = 21,
RT_ANIICON = 22,
RT_HTML = 23,
}
internal class NameOrId {
string name;
int id;
public NameOrId (string name) {
this.name = name;
}
public NameOrId (int id) {
this.id = id;
}
public bool IsName {
get {
return name != null;
}
}
public string Name {
get {
return name;
}
}
public int Id {
get {
return id;
}
}
public override string ToString () {
if (name != null)
return "Name(" + name + ")";
else
return "Id(" + id + ")";
}
}
internal abstract class Win32Resource {
NameOrId type;
NameOrId name;
int language;
internal Win32Resource (NameOrId type, NameOrId name, int language) {
this.type = type;
this.name = name;
this.language = language;
}
internal Win32Resource (Win32ResourceType type, int name, int language) {
this.type = new NameOrId ((int)type);
this.name = new NameOrId (name);
this.language = language;
}
public Win32ResourceType ResourceType {
get {
if (type.IsName)
return (Win32ResourceType)(-1);
else
return (Win32ResourceType)type.Id;
}
}
public NameOrId Name {
get {
return name;
}
}
public NameOrId Type {
get {
return type;
}
}
public int Language {
get {
return language;
}
}
public abstract void WriteTo (Stream s);
public override string ToString () {
return "Win32Resource (Kind=" + ResourceType + ", Name=" + name + ")";
}
}
//
// This class represents a Win32 resource in encoded format
//
internal class Win32EncodedResource : Win32Resource {
byte[] data;
internal Win32EncodedResource (NameOrId type, NameOrId name, int language, byte[] data) : base (type, name, language) {
this.data = data;
}
public byte[] Data {
get {
return data;
}
}
public override void WriteTo (Stream s) {
s.Write (data, 0, data.Length);
}
}
//
// This class represents a Win32 ICON resource
//
internal class Win32IconResource : Win32Resource {
ICONDIRENTRY icon;
public Win32IconResource (int id, int language, ICONDIRENTRY icon) : base (Win32ResourceType.RT_ICON, id, language) {
this.icon = icon;
}
public ICONDIRENTRY Icon {
get {
return icon;
}
}
public override void WriteTo (Stream s) {
s.Write (icon.image, 0, icon.image.Length);
}
}
internal class Win32GroupIconResource : Win32Resource {
Win32IconResource[] icons;
public Win32GroupIconResource (int id, int language, Win32IconResource[] icons) : base (Win32ResourceType.RT_GROUP_ICON, id, language) {
this.icons = icons;
}
public override void WriteTo (Stream s) {
using (BinaryWriter w = new BinaryWriter (s)) {
w.Write ((short)0);
w.Write ((short)1);
w.Write ((short)icons.Length);
for (int i = 0; i < icons.Length; ++i) {
Win32IconResource icon = icons [i];
ICONDIRENTRY entry = icon.Icon;
w.Write (entry.bWidth);
w.Write (entry.bHeight);
w.Write (entry.bColorCount);
w.Write ((byte)0);
w.Write (entry.wPlanes);
w.Write (entry.wBitCount);
w.Write ((int)entry.image.Length);
w.Write ((short)icon.Name.Id);
}
}
}
}
//
// This class represents a Win32 VERSION resource
//
internal class Win32VersionResource : Win32Resource {
public string[] WellKnownProperties = {
"Comments",
"CompanyName",
"FileVersion",
"InternalName",
"LegalTrademarks",
"OriginalFilename",
"ProductName",
"ProductVersion"
};
long signature;
int struct_version;
long file_version;
long product_version;
int file_flags_mask;
int file_flags;
int file_os;
int file_type;
int file_subtype;
long file_date;
int file_lang;
int file_codepage;
Hashtable properties;
public Win32VersionResource (int id, int language, bool compilercontext) : base (Win32ResourceType.RT_VERSION, id, language) {
// Initialize non-public members to the usual values used in
// resources
signature = 0xfeef04bd;
struct_version = 1 << 16; /* 1.0 */
file_flags_mask = 63;
file_flags = 0;
file_os = 4; /* VOS_WIN32 */
file_type = 2;
file_subtype = 0;
file_date = 0;
file_lang = compilercontext ? 0x00 : 0x7f;
file_codepage = 1200;
properties = new Hashtable ();
string defaultvalue = compilercontext ? string.Empty : " ";
// Well known properties
foreach (string s in WellKnownProperties)
// The value of properties can't be empty
properties [s] = defaultvalue;
LegalCopyright = " ";
FileDescription = " ";
}
public string Version {
get {
return
"" + (file_version >> 48) +
"." + ((file_version >> 32) & 0xffff) +
"." + ((file_version >> 16) & 0xffff) +
"." + ((file_version >> 0) & 0xffff);
}
set {
long[] ver = new long [4] { 0, 0, 0, 0 };
if (value != null) {
string[] parts = value.Split ('.');
try {
for (int i = 0; i < parts.Length; ++i) {
if (i < ver.Length)
ver [i] = Int32.Parse (parts [i]);
}
} catch (FormatException) {
}
}
file_version = (ver [0] << 48) | (ver [1] << 32) | (ver [2] << 16) + ver [3];
properties ["FileVersion"] = Version;
}
}
public virtual string this [string key] {
set {
properties [key] = value;
}
}
// Accessors for well known properties
public virtual string Comments {
get {
return (string)properties ["Comments"];
}
set {
properties ["Comments"] = value == String.Empty ? " " : value;
}
}
public virtual string CompanyName {
get {
return (string)properties ["CompanyName"];
}
set {
properties ["CompanyName"] = value == String.Empty ? " " : value;
}
}
public virtual string LegalCopyright {
get {
return (string)properties ["LegalCopyright"];
}
set {
properties ["LegalCopyright"] = value == String.Empty ? " " : value;
}
}
public virtual string LegalTrademarks {
get {
return (string)properties ["LegalTrademarks"];
}
set {
properties ["LegalTrademarks"] = value == String.Empty ? " " : value;
}
}
public virtual string OriginalFilename {
get {
return (string)properties ["OriginalFilename"];
}
set {
properties ["OriginalFilename"] = value == String.Empty ? " " : value;
}
}
public virtual string ProductName {
get {
return (string)properties ["ProductName"];
}
set {
properties ["ProductName"] = value == String.Empty ? " " : value;
}
}
public virtual string ProductVersion {
get {
return (string)properties ["ProductVersion"];
}
set {
if (value == null || value.Length == 0)
value = " ";
long [] ver = new long [4] { 0, 0, 0, 0 };
string [] parts = value.Split ('.');
try {
for (int i = 0; i < parts.Length; ++i) {
if (i < ver.Length)
ver [i] = Int32.Parse (parts [i]);
}
} catch (FormatException) {
}
properties ["ProductVersion"] = value;
product_version = (ver [0] << 48) | (ver [1] << 32) | (ver [2] << 16) + ver [3];
}
}
public virtual string InternalName {
get {
return (string)properties ["InternalName"];
}
set {
properties ["InternalName"] = value == String.Empty ? " " : value;
}
}
public virtual string FileDescription {
get {
return (string)properties ["FileDescription"];
}
set {
properties ["FileDescription"] = value == String.Empty ? " " : value;
}
}
public virtual int FileLanguage {
get { return file_lang; }
set { file_lang = value; }
}
public virtual string FileVersion {
get {
return (string)properties ["FileVersion"];
}
set {
if (value == null || value.Length == 0)
value = " ";
long[] ver = new long [4] { 0, 0, 0, 0 };
string[] parts = value.Split ('.');
try {
for (int i = 0; i < parts.Length; ++i) {
if (i < ver.Length)
ver [i] = Int32.Parse (parts [i]);
}
} catch (FormatException) {
}
properties ["FileVersion"] = value;
file_version = (ver [0] << 48) | (ver [1] << 32) | (ver [2] << 16) + ver [3];
}
}
private void emit_padding (BinaryWriter w) {
Stream ms = w.BaseStream;
if ((ms.Position % 4) != 0)
w.Write ((short)0);
}
private void patch_length (BinaryWriter w, long len_pos) {
Stream ms = w.BaseStream;
long pos = ms.Position;
ms.Position = len_pos;
w.Write ((short)(pos - len_pos));
ms.Position = pos;
}
public override void WriteTo (Stream ms)
{
using (BinaryWriter w = new BinaryWriter (ms, Encoding.Unicode)) {
//
// See the documentation for the VS_VERSIONINFO structure and
// its children on MSDN
//
// VS_VERSIONINFO
w.Write ((short)0);
w.Write ((short)0x34);
w.Write ((short)0);
w.Write ("VS_VERSION_INFO".ToCharArray ());
w.Write ((short)0);
emit_padding (w);
// VS_FIXEDFILEINFO
w.Write ((uint)signature);
w.Write ((int)struct_version);
w.Write ((int)(file_version >> 32));
w.Write ((int)((file_version & 0xffffffff)));
w.Write ((int)(product_version >> 32));
w.Write ((int)(product_version & 0xffffffff));
w.Write ((int)file_flags_mask);
w.Write ((int)file_flags);
w.Write ((int)file_os);
w.Write ((int)file_type);
w.Write ((int)file_subtype);
w.Write ((int)(file_date >> 32));
w.Write ((int)(file_date & 0xffffffff));
emit_padding (w);
// VarFileInfo
long var_file_info_pos = ms.Position;
w.Write ((short)0);
w.Write ((short)0);
w.Write ((short)1);
w.Write ("VarFileInfo".ToCharArray ());
w.Write ((short)0);
if ((ms.Position % 4) != 0)
w.Write ((short)0);
// Var
long var_pos = ms.Position;
w.Write ((short)0);
w.Write ((short)4);
w.Write ((short)0);
w.Write ("Translation".ToCharArray ());
w.Write ((short)0);
if ((ms.Position % 4) != 0)
w.Write ((short)0);
w.Write ((short)file_lang);
w.Write ((short)file_codepage);
patch_length (w, var_pos);
patch_length (w, var_file_info_pos);
// StringFileInfo
long string_file_info_pos = ms.Position;
w.Write ((short)0);
w.Write ((short)0);
w.Write ((short)1);
w.Write ("StringFileInfo".ToCharArray ());
emit_padding (w);
// StringTable
long string_table_pos = ms.Position;
w.Write ((short)0);
w.Write ((short)0);
w.Write ((short)1);
w.Write (String.Format ("{0:x4}{1:x4}", file_lang, file_codepage).ToCharArray ());
emit_padding (w);
// Strings
foreach (string key in properties.Keys) {
string value = (string)properties [key];
long string_pos = ms.Position;
w.Write ((short)0);
w.Write ((short)(value.ToCharArray ().Length + 1));
w.Write ((short)1);
w.Write (key.ToCharArray ());
w.Write ((short)0);
emit_padding (w);
w.Write (value.ToCharArray ());
w.Write ((short)0);
emit_padding (w);
patch_length (w, string_pos);
}
patch_length (w, string_table_pos);
patch_length (w, string_file_info_pos);
patch_length (w, 0);
}
}
}
internal class Win32ResFileReader {
Stream res_file;
public Win32ResFileReader (Stream s) {
res_file = s;
}
int read_int16 () {
int b1 = res_file.ReadByte ();
if (b1 == -1)
return -1;
int b2 = res_file.ReadByte ();
if (b2 == -1)
return -1;
return b1 | (b2 << 8);
}
int read_int32 () {
int w1 = read_int16 ();
if (w1 == -1)
return -1;
int w2 = read_int16 ();
if (w2 == -1)
return -1;
return w1 | (w2 << 16);
}
private bool read_padding () {
while ((res_file.Position % 4) != 0){
if (read_int16 () == -1)
return false;
}
return true;
}
NameOrId read_ordinal () {
int i = read_int16 ();
if ((i & 0xffff) != 0) {
int j = read_int16 ();
return new NameOrId (j);
}
else {
byte[] chars = new byte [16];
int pos = 0;
while (true) {
int j = read_int16 ();
if (j == 0)
break;
if (pos == chars.Length) {
byte[] new_chars = new byte [chars.Length * 2];
Array.Copy (chars, new_chars, chars.Length);
chars = new_chars;
}
chars [pos] = (byte)(j >> 8);
chars [pos + 1] = (byte)(j & 0xff);
pos += 2;
}
return new NameOrId (new String (Encoding.Unicode.GetChars (chars, 0, pos)));
}
}
public ICollection ReadResources () {
ArrayList resources = new ArrayList ();
/*
* We can't use a BinaryReader since we have to keep track of the
* stream position for padding.
*/
while (true) {
if (!read_padding ())
break;
int data_size = read_int32 ();
if (data_size == -1)
/* EOF */
break;
//int header_size =
read_int32 ();
NameOrId type = read_ordinal ();
NameOrId name = read_ordinal ();
if (!read_padding ())
break;
//int data_version =
read_int32 ();
//int memory_flags =
read_int16 ();
int language_id = read_int16 ();
//int version =
read_int32 ();
//int characteristics =
read_int32 ();
if (data_size == 0)
/* Empty resource entry */
continue;
byte[] data = new byte [data_size];
if (res_file.Read (data, 0, data_size) != data_size)
break;
resources.Add (new Win32EncodedResource (type, name, language_id, data));
}
return resources;
}
}
//
// This class represents one icon image in an .ico file
//
internal class ICONDIRENTRY {
#pragma warning disable 649
public byte bWidth;
public byte bHeight;
public byte bColorCount;
public byte bReserved;
public Int16 wPlanes;
public Int16 wBitCount;
public Int32 dwBytesInRes;
public Int32 dwImageOffset;
#pragma warning restore 649
public byte[] image;
public override string ToString () {
return "ICONDIRENTRY (" + bWidth + "x" + bHeight + " " + wBitCount + " bpp)";
}
}
//
// This class represents a Reader for Win32 .ico files
//
internal class Win32IconFileReader {
Stream iconFile;
public Win32IconFileReader (Stream s) {
iconFile = s;
}
public ICONDIRENTRY[] ReadIcons () {
ICONDIRENTRY[] icons = null;
using (BinaryReader r = new BinaryReader (iconFile)) {
int idReserved = r.ReadInt16 ();
int idType = r.ReadInt16 ();
if ((idReserved != 0) || (idType != 1))
throw new Exception ("Invalid .ico file format");
long nitems = r.ReadInt16 ();
icons = new ICONDIRENTRY [nitems];
for (int i = 0; i < nitems; ++i) {
ICONDIRENTRY entry = new ICONDIRENTRY ();
entry.bWidth = r.ReadByte ();
entry.bHeight = r.ReadByte ();
entry.bColorCount = r.ReadByte ();
entry.bReserved = r.ReadByte ();
entry.wPlanes = r.ReadInt16 ();
entry.wBitCount = r.ReadInt16 ();
int dwBytesInRes = r.ReadInt32 ();
int dwImageOffset = r.ReadInt32 ();
/* Read image */
entry.image = new byte [dwBytesInRes];
long pos = iconFile.Position;
iconFile.Position = dwImageOffset;
iconFile.Read (entry.image, 0, dwBytesInRes);
iconFile.Position = pos;
/*
* The wPlanes and wBitCount members in the ICONDIRENTRY
* structure can be 0, so we set them from the BITMAPINFOHEADER
* structure that follows
*/
if (entry.wPlanes == 0)
entry.wPlanes = (short)(entry.image [12] | (entry.image [13] << 8));
if (entry.wBitCount == 0)
entry.wBitCount = (short)(entry.image [14] | (entry.image [15] << 8));
icons [i] = entry;
}
return icons;
}
}
}
}
|