2 // System.Resources/Win32Resources.cs
5 // Zoltan Varga (vargaz@freemail.hu)
7 // (C) 2003 Ximian, Inc. http://www.ximian.com
9 // An incomplete set of classes for manipulating Win32 resources
13 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 using System.Collections;
37 using System.Globalization;
41 namespace System.Resources {
44 internal enum Win32ResourceType {
67 internal class NameOrId {
71 public NameOrId (string name) {
75 public NameOrId (int id) {
97 public override string ToString () {
99 return "Name(" + name + ")";
101 return "Id(" + id + ")";
105 internal abstract class Win32Resource {
111 internal Win32Resource (NameOrId type, NameOrId name, int language) {
114 this.language = language;
117 internal Win32Resource (Win32ResourceType type, int name, int language) {
118 this.type = new NameOrId ((int)type);
119 this.name = new NameOrId (name);
120 this.language = language;
123 public Win32ResourceType ResourceType {
126 return (Win32ResourceType)(-1);
128 return (Win32ResourceType)type.Id;
132 public NameOrId Name {
138 public NameOrId Type {
144 public int Language {
150 public abstract void WriteTo (Stream s);
152 public override string ToString () {
153 return "Win32Resource (Kind=" + ResourceType + ", Name=" + name + ")";
158 // This class represents a Win32 resource in encoded format
160 internal class Win32EncodedResource : Win32Resource {
164 internal Win32EncodedResource (NameOrId type, NameOrId name, int language, byte[] data) : base (type, name, language) {
174 public override void WriteTo (Stream s) {
175 s.Write (data, 0, data.Length);
180 // This class represents a Win32 ICON resource
182 internal class Win32IconResource : Win32Resource {
186 public Win32IconResource (int id, int language, ICONDIRENTRY icon) : base (Win32ResourceType.RT_ICON, id, language) {
190 public ICONDIRENTRY Icon {
196 public override void WriteTo (Stream s) {
197 s.Write (icon.image, 0, icon.image.Length);
201 internal class Win32GroupIconResource : Win32Resource {
203 Win32IconResource[] icons;
205 public Win32GroupIconResource (int id, int language, Win32IconResource[] icons) : base (Win32ResourceType.RT_GROUP_ICON, id, language) {
209 public override void WriteTo (Stream s) {
210 using (BinaryWriter w = new BinaryWriter (s)) {
213 w.Write ((short)icons.Length);
214 for (int i = 0; i < icons.Length; ++i) {
215 Win32IconResource icon = icons [i];
216 ICONDIRENTRY entry = icon.Icon;
218 w.Write (entry.bWidth);
219 w.Write (entry.bHeight);
220 w.Write (entry.bColorCount);
222 w.Write (entry.wPlanes);
223 w.Write (entry.wBitCount);
224 w.Write ((int)entry.image.Length);
225 w.Write ((short)icon.Name.Id);
232 // This class represents a Win32 VERSION resource
234 internal class Win32VersionResource : Win32Resource {
236 public string[] WellKnownProperties = {
256 long product_version;
267 Hashtable properties;
269 public Win32VersionResource (int id, int language, bool compilercontext) : base (Win32ResourceType.RT_VERSION, id, language) {
270 // Initialize non-public members to the usual values used in
272 signature = 0xfeef04bd;
273 struct_version = 1 << 16; /* 1.0 */
274 file_flags_mask = 63;
276 file_os = 4; /* VOS_WIN32 */
281 file_lang = compilercontext ? 0x00 : 0x7f;
282 file_codepage = 1200;
284 properties = new Hashtable ();
287 string defaultvalue = compilercontext ? string.Empty : " ";
289 string defaultvalue = " ";
292 // Well known properties
293 foreach (string s in WellKnownProperties)
294 // The value of properties can't be empty
295 properties [s] = defaultvalue;
298 LegalCopyright = " ";
299 FileDescription = " ";
303 public string Version {
306 "" + (file_version >> 48) +
307 "." + ((file_version >> 32) & 0xffff) +
308 "." + ((file_version >> 16) & 0xffff) +
309 "." + ((file_version >> 0) & 0xffff);
314 long[] ver = new long [4] { 0, 0, 0, 0 };
316 long [] ver = new long [4] { 0, 0xffff, 0xffff, 0xffff };
319 string[] parts = value.Split ('.');
322 for (int i = 0; i < parts.Length; ++i) {
324 ver [i] = Int32.Parse (parts [i]);
326 } catch (FormatException) {
330 file_version = (ver [0] << 48) | (ver [1] << 32) | (ver [2] << 16) + ver [3];
331 properties ["FileVersion"] = Version;
335 public virtual string this [string key] {
337 properties [key] = value;
341 // Accessors for well known properties
343 public virtual string Comments {
345 return (string)properties ["Comments"];
348 properties ["Comments"] = value == String.Empty ? " " : value;
352 public virtual string CompanyName {
354 return (string)properties ["CompanyName"];
357 properties ["CompanyName"] = value == String.Empty ? " " : value;
361 public virtual string LegalCopyright {
363 return (string)properties ["LegalCopyright"];
366 properties ["LegalCopyright"] = value == String.Empty ? " " : value;
370 public virtual string LegalTrademarks {
372 return (string)properties ["LegalTrademarks"];
375 properties ["LegalTrademarks"] = value == String.Empty ? " " : value;
379 public virtual string OriginalFilename {
381 return (string)properties ["OriginalFilename"];
384 properties ["OriginalFilename"] = value == String.Empty ? " " : value;
388 public virtual string ProductName {
390 return (string)properties ["ProductName"];
393 properties ["ProductName"] = value == String.Empty ? " " : value;
397 public virtual string ProductVersion {
399 return (string)properties ["ProductVersion"];
402 if (value == null || value.Length == 0)
405 long [] ver = new long [4] { 0, 0, 0, 0 };
407 string [] parts = value.Split ('.');
410 for (int i = 0; i < parts.Length; ++i) {
412 ver [i] = Int32.Parse (parts [i]);
414 } catch (FormatException) {
417 properties ["ProductVersion"] = value;
418 product_version = (ver [0] << 48) | (ver [1] << 32) | (ver [2] << 16) + ver [3];
422 public virtual string InternalName {
424 return (string)properties ["InternalName"];
427 properties ["InternalName"] = value == String.Empty ? " " : value;
431 public virtual string FileDescription {
433 return (string)properties ["FileDescription"];
436 properties ["FileDescription"] = value == String.Empty ? " " : value;
440 public virtual int FileLanguage {
441 get { return file_lang; }
442 set { file_lang = value; }
445 public virtual string FileVersion {
447 return (string)properties ["FileVersion"];
450 if (value == null || value.Length == 0)
453 long[] ver = new long [4] { 0, 0, 0, 0 };
454 string[] parts = value.Split ('.');
457 for (int i = 0; i < parts.Length; ++i) {
459 ver [i] = Int32.Parse (parts [i]);
461 } catch (FormatException) {
464 properties ["FileVersion"] = value;
465 file_version = (ver [0] << 48) | (ver [1] << 32) | (ver [2] << 16) + ver [3];
469 private void emit_padding (BinaryWriter w) {
470 Stream ms = w.BaseStream;
472 if ((ms.Position % 4) != 0)
476 private void patch_length (BinaryWriter w, long len_pos) {
477 Stream ms = w.BaseStream;
479 long pos = ms.Position;
480 ms.Position = len_pos;
481 w.Write ((short)(pos - len_pos));
485 public override void WriteTo (Stream ms)
487 using (BinaryWriter w = new BinaryWriter (ms, Encoding.Unicode)) {
489 // See the documentation for the VS_VERSIONINFO structure and
490 // its children on MSDN
495 w.Write ((short)0x34);
497 w.Write ("VS_VERSION_INFO".ToCharArray ());
503 w.Write ((uint)signature);
504 w.Write ((int)struct_version);
505 w.Write ((int)(file_version >> 32));
506 w.Write ((int)((file_version & 0xffffffff)));
508 w.Write ((int)(product_version >> 32));
509 w.Write ((int)(product_version & 0xffffffff));
510 w.Write ((int)file_flags_mask);
511 w.Write ((int)file_flags);
512 w.Write ((int)file_os);
513 w.Write ((int)file_type);
514 w.Write ((int)file_subtype);
515 w.Write ((int)(file_date >> 32));
516 w.Write ((int)(file_date & 0xffffffff));
521 long var_file_info_pos = ms.Position;
525 w.Write ("VarFileInfo".ToCharArray ());
528 if ((ms.Position % 4) != 0)
532 long var_pos = ms.Position;
536 w.Write ("Translation".ToCharArray ());
539 if ((ms.Position % 4) != 0)
542 w.Write ((short)file_lang);
543 w.Write ((short)file_codepage);
545 patch_length (w, var_pos);
547 patch_length (w, var_file_info_pos);
550 long string_file_info_pos = ms.Position;
554 w.Write ("StringFileInfo".ToCharArray ());
559 long string_table_pos = ms.Position;
563 w.Write (String.Format ("{0:x4}{1:x4}", file_lang, file_codepage).ToCharArray ());
568 foreach (string key in properties.Keys) {
569 string value = (string)properties [key];
571 long string_pos = ms.Position;
573 w.Write ((short)(value.ToCharArray ().Length + 1));
575 w.Write (key.ToCharArray ());
580 w.Write (value.ToCharArray ());
585 patch_length (w, string_pos);
588 patch_length (w, string_table_pos);
590 patch_length (w, string_file_info_pos);
597 internal class Win32ResFileReader {
601 public Win32ResFileReader (Stream s) {
606 int b1 = res_file.ReadByte ();
610 int b2 = res_file.ReadByte ();
614 return b1 | (b2 << 8);
618 int w1 = read_int16 ();
621 int w2 = read_int16 ();
625 return w1 | (w2 << 16);
628 private void read_padding () {
629 while ((res_file.Position % 4) != 0)
633 NameOrId read_ordinal () {
634 int i = read_int16 ();
635 if ((i & 0xffff) != 0) {
636 int j = read_int16 ();
637 return new NameOrId (j);
640 byte[] chars = new byte [16];
644 int j = read_int16 ();
647 if (pos == chars.Length) {
648 byte[] new_chars = new byte [chars.Length * 2];
649 Array.Copy (chars, new_chars, chars.Length);
652 chars [pos] = (byte)(j >> 8);
653 chars [pos + 1] = (byte)(j & 0xff);
657 return new NameOrId (new String (Encoding.Unicode.GetChars (chars, 0, pos)));
661 public ICollection ReadResources () {
662 ArrayList resources = new ArrayList ();
665 * We can't use a BinaryReader since we have to keep track of the
666 * stream position for padding.
673 int data_size = read_int32 ();
681 NameOrId type = read_ordinal ();
682 NameOrId name = read_ordinal ();
690 int language_id = read_int16 ();
693 //int characteristics =
697 /* Empty resource entry */
700 byte[] data = new byte [data_size];
701 res_file.Read (data, 0, data_size);
703 resources.Add (new Win32EncodedResource (type, name, language_id, data));
711 // This class represents one icon image in an .ico file
713 internal class ICONDIRENTRY {
715 #pragma warning disable 649
718 public byte bColorCount;
719 public byte bReserved;
720 public Int16 wPlanes;
721 public Int16 wBitCount;
722 public Int32 dwBytesInRes;
723 public Int32 dwImageOffset;
724 #pragma warning restore 649
727 public override string ToString () {
728 return "ICONDIRENTRY (" + bWidth + "x" + bHeight + " " + wBitCount + " bpp)";
733 // This class represents a Reader for Win32 .ico files
735 internal class Win32IconFileReader {
739 public Win32IconFileReader (Stream s) {
743 public ICONDIRENTRY[] ReadIcons () {
744 ICONDIRENTRY[] icons = null;
746 using (BinaryReader r = new BinaryReader (iconFile)) {
747 int idReserved = r.ReadInt16 ();
748 int idType = r.ReadInt16 ();
749 if ((idReserved != 0) || (idType != 1))
750 throw new Exception ("Invalid .ico file format");
751 long nitems = r.ReadInt16 ();
753 icons = new ICONDIRENTRY [nitems];
755 for (int i = 0; i < nitems; ++i) {
756 ICONDIRENTRY entry = new ICONDIRENTRY ();
758 entry.bWidth = r.ReadByte ();
759 entry.bHeight = r.ReadByte ();
760 entry.bColorCount = r.ReadByte ();
761 entry.bReserved = r.ReadByte ();
762 entry.wPlanes = r.ReadInt16 ();
763 entry.wBitCount = r.ReadInt16 ();
764 int dwBytesInRes = r.ReadInt32 ();
765 int dwImageOffset = r.ReadInt32 ();
768 entry.image = new byte [dwBytesInRes];
770 long pos = iconFile.Position;
771 iconFile.Position = dwImageOffset;
772 iconFile.Read (entry.image, 0, dwBytesInRes);
773 iconFile.Position = pos;
776 * The wPlanes and wBitCount members in the ICONDIRENTRY
777 * structure can be 0, so we set them from the BITMAPINFOHEADER
778 * structure that follows
781 if (entry.wPlanes == 0)
782 entry.wPlanes = (short)(entry.image [12] | (entry.image [13] << 8));
783 if (entry.wBitCount == 0)
784 entry.wBitCount = (short)(entry.image [14] | (entry.image [15] << 8));