2010-04-07 Jb Evain <jbevain@novell.com>
[mcs.git] / class / corlib / System.Resources / Win32Resources.cs
blobad58ce8823fc9092687e547878d7a6eaffed78f3
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 "FileVersion",
240 "InternalName",
241 "LegalTrademarks",
242 "OriginalFilename",
243 "ProductName",
244 "ProductVersion"
247 long signature;
248 int struct_version;
249 long file_version;
250 long product_version;
251 int file_flags_mask;
252 int file_flags;
253 int file_os;
254 int file_type;
255 int file_subtype;
256 long file_date;
258 int file_lang;
259 int file_codepage;
261 Hashtable properties;
263 public Win32VersionResource (int id, int language, bool compilercontext) : base (Win32ResourceType.RT_VERSION, id, language) {
264 // Initialize non-public members to the usual values used in
265 // resources
266 signature = 0xfeef04bd;
267 struct_version = 1 << 16; /* 1.0 */
268 file_flags_mask = 63;
269 file_flags = 0;
270 file_os = 4; /* VOS_WIN32 */
271 file_type = 2;
272 file_subtype = 0;
273 file_date = 0;
275 file_lang = compilercontext ? 0x00 : 0x7f;
276 file_codepage = 1200;
278 properties = new Hashtable ();
280 string defaultvalue = compilercontext ? string.Empty : " ";
282 // Well known properties
283 foreach (string s in WellKnownProperties)
284 // The value of properties can't be empty
285 properties [s] = defaultvalue;
287 LegalCopyright = " ";
288 FileDescription = " ";
291 public string Version {
292 get {
293 return
294 "" + (file_version >> 48) +
295 "." + ((file_version >> 32) & 0xffff) +
296 "." + ((file_version >> 16) & 0xffff) +
297 "." + ((file_version >> 0) & 0xffff);
300 set {
301 long[] ver = new long [4] { 0, 0, 0, 0 };
302 if (value != null) {
303 string[] parts = value.Split ('.');
305 try {
306 for (int i = 0; i < parts.Length; ++i) {
307 if (i < ver.Length)
308 ver [i] = Int32.Parse (parts [i]);
310 } catch (FormatException) {
314 file_version = (ver [0] << 48) | (ver [1] << 32) | (ver [2] << 16) + ver [3];
315 properties ["FileVersion"] = Version;
319 public virtual string this [string key] {
320 set {
321 properties [key] = value;
325 // Accessors for well known properties
327 public virtual string Comments {
328 get {
329 return (string)properties ["Comments"];
331 set {
332 properties ["Comments"] = value == String.Empty ? " " : value;
336 public virtual string CompanyName {
337 get {
338 return (string)properties ["CompanyName"];
340 set {
341 properties ["CompanyName"] = value == String.Empty ? " " : value;
345 public virtual string LegalCopyright {
346 get {
347 return (string)properties ["LegalCopyright"];
349 set {
350 properties ["LegalCopyright"] = value == String.Empty ? " " : value;
354 public virtual string LegalTrademarks {
355 get {
356 return (string)properties ["LegalTrademarks"];
358 set {
359 properties ["LegalTrademarks"] = value == String.Empty ? " " : value;
363 public virtual string OriginalFilename {
364 get {
365 return (string)properties ["OriginalFilename"];
367 set {
368 properties ["OriginalFilename"] = value == String.Empty ? " " : value;
372 public virtual string ProductName {
373 get {
374 return (string)properties ["ProductName"];
376 set {
377 properties ["ProductName"] = value == String.Empty ? " " : value;
381 public virtual string ProductVersion {
382 get {
383 return (string)properties ["ProductVersion"];
385 set {
386 if (value == null || value.Length == 0)
387 value = " ";
389 long [] ver = new long [4] { 0, 0, 0, 0 };
391 string [] parts = value.Split ('.');
393 try {
394 for (int i = 0; i < parts.Length; ++i) {
395 if (i < ver.Length)
396 ver [i] = Int32.Parse (parts [i]);
398 } catch (FormatException) {
401 properties ["ProductVersion"] = value;
402 product_version = (ver [0] << 48) | (ver [1] << 32) | (ver [2] << 16) + ver [3];
406 public virtual string InternalName {
407 get {
408 return (string)properties ["InternalName"];
410 set {
411 properties ["InternalName"] = value == String.Empty ? " " : value;
415 public virtual string FileDescription {
416 get {
417 return (string)properties ["FileDescription"];
419 set {
420 properties ["FileDescription"] = value == String.Empty ? " " : value;
424 public virtual int FileLanguage {
425 get { return file_lang; }
426 set { file_lang = value; }
429 public virtual string FileVersion {
430 get {
431 return (string)properties ["FileVersion"];
433 set {
434 if (value == null || value.Length == 0)
435 value = " ";
437 long[] ver = new long [4] { 0, 0, 0, 0 };
438 string[] parts = value.Split ('.');
440 try {
441 for (int i = 0; i < parts.Length; ++i) {
442 if (i < ver.Length)
443 ver [i] = Int32.Parse (parts [i]);
445 } catch (FormatException) {
448 properties ["FileVersion"] = value;
449 file_version = (ver [0] << 48) | (ver [1] << 32) | (ver [2] << 16) + ver [3];
453 private void emit_padding (BinaryWriter w) {
454 Stream ms = w.BaseStream;
456 if ((ms.Position % 4) != 0)
457 w.Write ((short)0);
460 private void patch_length (BinaryWriter w, long len_pos) {
461 Stream ms = w.BaseStream;
463 long pos = ms.Position;
464 ms.Position = len_pos;
465 w.Write ((short)(pos - len_pos));
466 ms.Position = pos;
469 public override void WriteTo (Stream ms)
471 using (BinaryWriter w = new BinaryWriter (ms, Encoding.Unicode)) {
473 // See the documentation for the VS_VERSIONINFO structure and
474 // its children on MSDN
477 // VS_VERSIONINFO
478 w.Write ((short)0);
479 w.Write ((short)0x34);
480 w.Write ((short)0);
481 w.Write ("VS_VERSION_INFO".ToCharArray ());
482 w.Write ((short)0);
484 emit_padding (w);
486 // VS_FIXEDFILEINFO
487 w.Write ((uint)signature);
488 w.Write ((int)struct_version);
489 w.Write ((int)(file_version >> 32));
490 w.Write ((int)((file_version & 0xffffffff)));
492 w.Write ((int)(product_version >> 32));
493 w.Write ((int)(product_version & 0xffffffff));
494 w.Write ((int)file_flags_mask);
495 w.Write ((int)file_flags);
496 w.Write ((int)file_os);
497 w.Write ((int)file_type);
498 w.Write ((int)file_subtype);
499 w.Write ((int)(file_date >> 32));
500 w.Write ((int)(file_date & 0xffffffff));
502 emit_padding (w);
504 // VarFileInfo
505 long var_file_info_pos = ms.Position;
506 w.Write ((short)0);
507 w.Write ((short)0);
508 w.Write ((short)1);
509 w.Write ("VarFileInfo".ToCharArray ());
510 w.Write ((short)0);
512 if ((ms.Position % 4) != 0)
513 w.Write ((short)0);
515 // Var
516 long var_pos = ms.Position;
517 w.Write ((short)0);
518 w.Write ((short)4);
519 w.Write ((short)0);
520 w.Write ("Translation".ToCharArray ());
521 w.Write ((short)0);
523 if ((ms.Position % 4) != 0)
524 w.Write ((short)0);
526 w.Write ((short)file_lang);
527 w.Write ((short)file_codepage);
529 patch_length (w, var_pos);
531 patch_length (w, var_file_info_pos);
533 // StringFileInfo
534 long string_file_info_pos = ms.Position;
535 w.Write ((short)0);
536 w.Write ((short)0);
537 w.Write ((short)1);
538 w.Write ("StringFileInfo".ToCharArray ());
540 emit_padding (w);
542 // StringTable
543 long string_table_pos = ms.Position;
544 w.Write ((short)0);
545 w.Write ((short)0);
546 w.Write ((short)1);
547 w.Write (String.Format ("{0:x4}{1:x4}", file_lang, file_codepage).ToCharArray ());
549 emit_padding (w);
551 // Strings
552 foreach (string key in properties.Keys) {
553 string value = (string)properties [key];
555 long string_pos = ms.Position;
556 w.Write ((short)0);
557 w.Write ((short)(value.ToCharArray ().Length + 1));
558 w.Write ((short)1);
559 w.Write (key.ToCharArray ());
560 w.Write ((short)0);
562 emit_padding (w);
564 w.Write (value.ToCharArray ());
565 w.Write ((short)0);
567 emit_padding (w);
569 patch_length (w, string_pos);
572 patch_length (w, string_table_pos);
574 patch_length (w, string_file_info_pos);
576 patch_length (w, 0);
581 internal class Win32ResFileReader {
583 Stream res_file;
585 public Win32ResFileReader (Stream s) {
586 res_file = s;
589 int read_int16 () {
590 int b1 = res_file.ReadByte ();
591 if (b1 == -1)
592 return -1;
594 int b2 = res_file.ReadByte ();
595 if (b2 == -1)
596 return -1;
598 return b1 | (b2 << 8);
601 int read_int32 () {
602 int w1 = read_int16 ();
603 if (w1 == -1)
604 return -1;
605 int w2 = read_int16 ();
606 if (w2 == -1)
607 return -1;
609 return w1 | (w2 << 16);
612 private bool read_padding () {
613 while ((res_file.Position % 4) != 0){
614 if (read_int16 () == -1)
615 return false;
617 return true;
620 NameOrId read_ordinal () {
621 int i = read_int16 ();
622 if ((i & 0xffff) != 0) {
623 int j = read_int16 ();
624 return new NameOrId (j);
626 else {
627 byte[] chars = new byte [16];
628 int pos = 0;
630 while (true) {
631 int j = read_int16 ();
632 if (j == 0)
633 break;
634 if (pos == chars.Length) {
635 byte[] new_chars = new byte [chars.Length * 2];
636 Array.Copy (chars, new_chars, chars.Length);
637 chars = new_chars;
639 chars [pos] = (byte)(j >> 8);
640 chars [pos + 1] = (byte)(j & 0xff);
641 pos += 2;
644 return new NameOrId (new String (Encoding.Unicode.GetChars (chars, 0, pos)));
648 public ICollection ReadResources () {
649 ArrayList resources = new ArrayList ();
652 * We can't use a BinaryReader since we have to keep track of the
653 * stream position for padding.
656 while (true) {
658 if (!read_padding ())
659 break;
661 int data_size = read_int32 ();
663 if (data_size == -1)
664 /* EOF */
665 break;
667 //int header_size =
668 read_int32 ();
669 NameOrId type = read_ordinal ();
670 NameOrId name = read_ordinal ();
672 if (!read_padding ())
673 break;
675 //int data_version =
676 read_int32 ();
677 //int memory_flags =
678 read_int16 ();
679 int language_id = read_int16 ();
680 //int version =
681 read_int32 ();
682 //int characteristics =
683 read_int32 ();
685 if (data_size == 0)
686 /* Empty resource entry */
687 continue;
689 byte[] data = new byte [data_size];
690 if (res_file.Read (data, 0, data_size) != data_size)
691 break;
693 resources.Add (new Win32EncodedResource (type, name, language_id, data));
696 return resources;
701 // This class represents one icon image in an .ico file
703 internal class ICONDIRENTRY {
705 #pragma warning disable 649
706 public byte bWidth;
707 public byte bHeight;
708 public byte bColorCount;
709 public byte bReserved;
710 public Int16 wPlanes;
711 public Int16 wBitCount;
712 public Int32 dwBytesInRes;
713 public Int32 dwImageOffset;
714 #pragma warning restore 649
715 public byte[] image;
717 public override string ToString () {
718 return "ICONDIRENTRY (" + bWidth + "x" + bHeight + " " + wBitCount + " bpp)";
723 // This class represents a Reader for Win32 .ico files
725 internal class Win32IconFileReader {
727 Stream iconFile;
729 public Win32IconFileReader (Stream s) {
730 iconFile = s;
733 public ICONDIRENTRY[] ReadIcons () {
734 ICONDIRENTRY[] icons = null;
736 using (BinaryReader r = new BinaryReader (iconFile)) {
737 int idReserved = r.ReadInt16 ();
738 int idType = r.ReadInt16 ();
739 if ((idReserved != 0) || (idType != 1))
740 throw new Exception ("Invalid .ico file format");
741 long nitems = r.ReadInt16 ();
743 icons = new ICONDIRENTRY [nitems];
745 for (int i = 0; i < nitems; ++i) {
746 ICONDIRENTRY entry = new ICONDIRENTRY ();
748 entry.bWidth = r.ReadByte ();
749 entry.bHeight = r.ReadByte ();
750 entry.bColorCount = r.ReadByte ();
751 entry.bReserved = r.ReadByte ();
752 entry.wPlanes = r.ReadInt16 ();
753 entry.wBitCount = r.ReadInt16 ();
754 int dwBytesInRes = r.ReadInt32 ();
755 int dwImageOffset = r.ReadInt32 ();
757 /* Read image */
758 entry.image = new byte [dwBytesInRes];
760 long pos = iconFile.Position;
761 iconFile.Position = dwImageOffset;
762 iconFile.Read (entry.image, 0, dwBytesInRes);
763 iconFile.Position = pos;
766 * The wPlanes and wBitCount members in the ICONDIRENTRY
767 * structure can be 0, so we set them from the BITMAPINFOHEADER
768 * structure that follows
771 if (entry.wPlanes == 0)
772 entry.wPlanes = (short)(entry.image [12] | (entry.image [13] << 8));
773 if (entry.wBitCount == 0)
774 entry.wBitCount = (short)(entry.image [14] | (entry.image [15] << 8));
776 icons [i] = entry;
779 return icons;