2009-09-04 Zoltan Varga <vargaz@gmail.com>
[mcs.git] / class / corlib / System.Resources / Win32Resources.cs
blobabd7eeb2d2ff44e9bd63596df1108e9974e2ccf6
1 //
2 // System.Resources/Win32Resources.cs
3 //
4 // Author:
5 // Zoltan Varga (vargaz@freemail.hu)
6 //
7 // (C) 2003 Ximian, Inc. http://www.ximian.com
8 //
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:
22 //
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 //
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.
35 using System;
36 using System.Collections;
37 using System.Globalization;
38 using System.IO;
39 using System.Text;
41 namespace System.Resources {
44 internal enum Win32ResourceType {
45 RT_CURSOR = 1,
46 RT_FONT = 8,
47 RT_BITMAP = 2,
48 RT_ICON = 3,
49 RT_MENU = 4,
50 RT_DIALOG = 5,
51 RT_STRING = 6,
52 RT_FONTDIR = 7,
53 RT_ACCELERATOR = 9,
54 RT_RCDATA = 10,
55 RT_MESSAGETABLE = 11,
56 RT_GROUP_CURSOR = 12,
57 RT_GROUP_ICON = 14,
58 RT_VERSION = 16,
59 RT_DLGINCLUDE = 17,
60 RT_PLUGPLAY = 19,
61 RT_VXD = 20,
62 RT_ANICURSOR = 21,
63 RT_ANIICON = 22,
64 RT_HTML = 23,
67 internal class NameOrId {
68 string name;
69 int id;
71 public NameOrId (string name) {
72 this.name = name;
75 public NameOrId (int id) {
76 this.id = id;
79 public bool IsName {
80 get {
81 return name != null;
85 public string Name {
86 get {
87 return name;
91 public int Id {
92 get {
93 return id;
97 public override string ToString () {
98 if (name != null)
99 return "Name(" + name + ")";
100 else
101 return "Id(" + id + ")";
105 internal abstract class Win32Resource {
107 NameOrId type;
108 NameOrId name;
109 int language;
111 internal Win32Resource (NameOrId type, NameOrId name, int language) {
112 this.type = type;
113 this.name = name;
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 {
124 get {
125 if (type.IsName)
126 return (Win32ResourceType)(-1);
127 else
128 return (Win32ResourceType)type.Id;
132 public NameOrId Name {
133 get {
134 return name;
138 public NameOrId Type {
139 get {
140 return type;
144 public int Language {
145 get {
146 return 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 {
162 byte[] data;
164 internal Win32EncodedResource (NameOrId type, NameOrId name, int language, byte[] data) : base (type, name, language) {
165 this.data = data;
168 public byte[] Data {
169 get {
170 return data;
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 {
184 ICONDIRENTRY icon;
186 public Win32IconResource (int id, int language, ICONDIRENTRY icon) : base (Win32ResourceType.RT_ICON, id, language) {
187 this.icon = icon;
190 public ICONDIRENTRY Icon {
191 get {
192 return 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) {
206 this.icons = icons;
209 public override void WriteTo (Stream s) {
210 using (BinaryWriter w = new BinaryWriter (s)) {
211 w.Write ((short)0);
212 w.Write ((short)1);
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);
221 w.Write ((byte)0);
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 = {
237 "Comments",
238 "CompanyName",
239 #if !NET_2_0
240 "FileDescription",
241 #endif
242 "FileVersion",
243 "InternalName",
244 #if !NET_2_0
245 "LegalCopyright",
246 #endif
247 "LegalTrademarks",
248 "OriginalFilename",
249 "ProductName",
250 "ProductVersion"
253 long signature;
254 int struct_version;
255 long file_version;
256 long product_version;
257 int file_flags_mask;
258 int file_flags;
259 int file_os;
260 int file_type;
261 int file_subtype;
262 long file_date;
264 int file_lang;
265 int file_codepage;
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
271 // resources
272 signature = 0xfeef04bd;
273 struct_version = 1 << 16; /* 1.0 */
274 file_flags_mask = 63;
275 file_flags = 0;
276 file_os = 4; /* VOS_WIN32 */
277 file_type = 2;
278 file_subtype = 0;
279 file_date = 0;
281 file_lang = compilercontext ? 0x00 : 0x7f;
282 file_codepage = 1200;
284 properties = new Hashtable ();
286 #if NET_2_0
287 string defaultvalue = compilercontext ? string.Empty : " ";
288 #else
289 string defaultvalue = " ";
290 #endif
292 // Well known properties
293 foreach (string s in WellKnownProperties)
294 // The value of properties can't be empty
295 properties [s] = defaultvalue;
297 #if NET_2_0
298 LegalCopyright = " ";
299 FileDescription = " ";
300 #endif
303 public string Version {
304 get {
305 return
306 "" + (file_version >> 48) +
307 "." + ((file_version >> 32) & 0xffff) +
308 "." + ((file_version >> 16) & 0xffff) +
309 "." + ((file_version >> 0) & 0xffff);
312 set {
313 #if NET_2_0
314 long[] ver = new long [4] { 0, 0, 0, 0 };
315 #else
316 long [] ver = new long [4] { 0, 0xffff, 0xffff, 0xffff };
317 #endif
318 if (value != null) {
319 string[] parts = value.Split ('.');
321 try {
322 for (int i = 0; i < parts.Length; ++i) {
323 if (i < ver.Length)
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] {
336 set {
337 properties [key] = value;
341 // Accessors for well known properties
343 public virtual string Comments {
344 get {
345 return (string)properties ["Comments"];
347 set {
348 properties ["Comments"] = value == String.Empty ? " " : value;
352 public virtual string CompanyName {
353 get {
354 return (string)properties ["CompanyName"];
356 set {
357 properties ["CompanyName"] = value == String.Empty ? " " : value;
361 public virtual string LegalCopyright {
362 get {
363 return (string)properties ["LegalCopyright"];
365 set {
366 properties ["LegalCopyright"] = value == String.Empty ? " " : value;
370 public virtual string LegalTrademarks {
371 get {
372 return (string)properties ["LegalTrademarks"];
374 set {
375 properties ["LegalTrademarks"] = value == String.Empty ? " " : value;
379 public virtual string OriginalFilename {
380 get {
381 return (string)properties ["OriginalFilename"];
383 set {
384 properties ["OriginalFilename"] = value == String.Empty ? " " : value;
388 public virtual string ProductName {
389 get {
390 return (string)properties ["ProductName"];
392 set {
393 properties ["ProductName"] = value == String.Empty ? " " : value;
397 public virtual string ProductVersion {
398 get {
399 return (string)properties ["ProductVersion"];
401 set {
402 if (value == null || value.Length == 0)
403 value = " ";
405 long [] ver = new long [4] { 0, 0, 0, 0 };
407 string [] parts = value.Split ('.');
409 try {
410 for (int i = 0; i < parts.Length; ++i) {
411 if (i < ver.Length)
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 {
423 get {
424 return (string)properties ["InternalName"];
426 set {
427 properties ["InternalName"] = value == String.Empty ? " " : value;
431 public virtual string FileDescription {
432 get {
433 return (string)properties ["FileDescription"];
435 set {
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 {
446 get {
447 return (string)properties ["FileVersion"];
449 set {
450 if (value == null || value.Length == 0)
451 value = " ";
453 long[] ver = new long [4] { 0, 0, 0, 0 };
454 string[] parts = value.Split ('.');
456 try {
457 for (int i = 0; i < parts.Length; ++i) {
458 if (i < ver.Length)
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)
473 w.Write ((short)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));
482 ms.Position = 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
493 // VS_VERSIONINFO
494 w.Write ((short)0);
495 w.Write ((short)0x34);
496 w.Write ((short)0);
497 w.Write ("VS_VERSION_INFO".ToCharArray ());
498 w.Write ((short)0);
500 emit_padding (w);
502 // VS_FIXEDFILEINFO
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));
518 emit_padding (w);
520 // VarFileInfo
521 long var_file_info_pos = ms.Position;
522 w.Write ((short)0);
523 w.Write ((short)0);
524 w.Write ((short)1);
525 w.Write ("VarFileInfo".ToCharArray ());
526 w.Write ((short)0);
528 if ((ms.Position % 4) != 0)
529 w.Write ((short)0);
531 // Var
532 long var_pos = ms.Position;
533 w.Write ((short)0);
534 w.Write ((short)4);
535 w.Write ((short)0);
536 w.Write ("Translation".ToCharArray ());
537 w.Write ((short)0);
539 if ((ms.Position % 4) != 0)
540 w.Write ((short)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);
549 // StringFileInfo
550 long string_file_info_pos = ms.Position;
551 w.Write ((short)0);
552 w.Write ((short)0);
553 w.Write ((short)1);
554 w.Write ("StringFileInfo".ToCharArray ());
556 emit_padding (w);
558 // StringTable
559 long string_table_pos = ms.Position;
560 w.Write ((short)0);
561 w.Write ((short)0);
562 w.Write ((short)1);
563 w.Write (String.Format ("{0:x4}{1:x4}", file_lang, file_codepage).ToCharArray ());
565 emit_padding (w);
567 // Strings
568 foreach (string key in properties.Keys) {
569 string value = (string)properties [key];
571 long string_pos = ms.Position;
572 w.Write ((short)0);
573 w.Write ((short)(value.ToCharArray ().Length + 1));
574 w.Write ((short)1);
575 w.Write (key.ToCharArray ());
576 w.Write ((short)0);
578 emit_padding (w);
580 w.Write (value.ToCharArray ());
581 w.Write ((short)0);
583 emit_padding (w);
585 patch_length (w, string_pos);
588 patch_length (w, string_table_pos);
590 patch_length (w, string_file_info_pos);
592 patch_length (w, 0);
597 internal class Win32ResFileReader {
599 Stream res_file;
601 public Win32ResFileReader (Stream s) {
602 res_file = s;
605 int read_int16 () {
606 int b1 = res_file.ReadByte ();
607 if (b1 == -1)
608 return -1;
610 int b2 = res_file.ReadByte ();
611 if (b2 == -1)
612 return -1;
614 return b1 | (b2 << 8);
617 int read_int32 () {
618 int w1 = read_int16 ();
619 if (w1 == -1)
620 return -1;
621 int w2 = read_int16 ();
622 if (w2 == -1)
623 return -1;
625 return w1 | (w2 << 16);
628 private void read_padding () {
629 while ((res_file.Position % 4) != 0)
630 read_int16 ();
633 NameOrId read_ordinal () {
634 int i = read_int16 ();
635 if ((i & 0xffff) != 0) {
636 int j = read_int16 ();
637 return new NameOrId (j);
639 else {
640 byte[] chars = new byte [16];
641 int pos = 0;
643 while (true) {
644 int j = read_int16 ();
645 if (j == 0)
646 break;
647 if (pos == chars.Length) {
648 byte[] new_chars = new byte [chars.Length * 2];
649 Array.Copy (chars, new_chars, chars.Length);
650 chars = new_chars;
652 chars [pos] = (byte)(j >> 8);
653 chars [pos + 1] = (byte)(j & 0xff);
654 pos += 2;
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.
669 while (true) {
671 read_padding ();
673 int data_size = read_int32 ();
675 if (data_size == -1)
676 /* EOF */
677 break;
679 //int header_size =
680 read_int32 ();
681 NameOrId type = read_ordinal ();
682 NameOrId name = read_ordinal ();
684 read_padding ();
686 //int data_version =
687 read_int32 ();
688 //int memory_flags =
689 read_int16 ();
690 int language_id = read_int16 ();
691 //int version =
692 read_int32 ();
693 //int characteristics =
694 read_int32 ();
696 if (data_size == 0)
697 /* Empty resource entry */
698 continue;
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));
706 return resources;
711 // This class represents one icon image in an .ico file
713 internal class ICONDIRENTRY {
715 #pragma warning disable 649
716 public byte bWidth;
717 public byte bHeight;
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
725 public byte[] image;
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 {
737 Stream iconFile;
739 public Win32IconFileReader (Stream s) {
740 iconFile = 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 ();
767 /* Read image */
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));
786 icons [i] = entry;
789 return icons;