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;
40 namespace System.Resources {
43 internal enum Win32ResourceType {
66 internal class NameOrId {
70 public NameOrId (string name) {
74 public NameOrId (int id) {
96 public override string ToString () {
98 return "Name(" + name + ")";
100 return "Id(" + id + ")";
104 internal abstract class Win32Resource {
110 internal Win32Resource (NameOrId type, NameOrId name, int language) {
113 this.language = language;
116 internal Win32Resource (Win32ResourceType type, int name, int language) {
117 this.type = new NameOrId ((int)type);
118 this.name = new NameOrId (name);
119 this.language = language;
122 public Win32ResourceType ResourceType {
125 return (Win32ResourceType)(-1);
127 return (Win32ResourceType)type.Id;
131 public NameOrId Name {
137 public NameOrId Type {
143 public int Language {
149 public abstract void WriteTo (Stream s);
151 public override string ToString () {
152 return "Win32Resource (Kind=" + ResourceType + ", Name=" + name + ")";
157 // This class represents a Win32 resource in encoded format
159 internal class Win32EncodedResource : Win32Resource {
163 internal Win32EncodedResource (NameOrId type, NameOrId name, int language, byte[] data) : base (type, name, language) {
173 public override void WriteTo (Stream s) {
174 s.Write (data, 0, data.Length);
179 // This class represents a Win32 ICON resource
181 internal class Win32IconResource : Win32Resource {
185 public Win32IconResource (int id, int language, ICONDIRENTRY icon) : base (Win32ResourceType.RT_ICON, id, language) {
189 public ICONDIRENTRY Icon {
195 public override void WriteTo (Stream s) {
196 s.Write (icon.image, 0, icon.image.Length);
200 internal class Win32GroupIconResource : Win32Resource {
202 Win32IconResource[] icons;
204 public Win32GroupIconResource (int id, int language, Win32IconResource[] icons) : base (Win32ResourceType.RT_GROUP_ICON, id, language) {
208 public override void WriteTo (Stream s) {
209 using (BinaryWriter w = new BinaryWriter (s)) {
212 w.Write ((short)icons.Length);
213 for (int i = 0; i < icons.Length; ++i) {
214 Win32IconResource icon = icons [i];
215 ICONDIRENTRY entry = icon.Icon;
217 w.Write (entry.bWidth);
218 w.Write (entry.bHeight);
219 w.Write (entry.bColorCount);
221 w.Write (entry.wPlanes);
222 w.Write (entry.wBitCount);
223 w.Write ((int)entry.image.Length);
224 w.Write ((short)icon.Name.Id);
231 // This class represents a Win32 VERSION resource
233 internal class Win32VersionResource : Win32Resource {
235 public string[] WellKnownProperties = {
251 long product_version;
262 Hashtable properties;
264 public Win32VersionResource (int id, int language) : base (Win32ResourceType.RT_VERSION, id, language) {
265 // Initialize non-public members to the usual values used in
267 signature = 0xfeef04bd;
268 struct_version = 1 << 16; /* 1.0 */
269 file_flags_mask = 63;
271 file_os = 4; /* VOS_WIN32 */
277 file_codepage = 1200;
279 properties = new Hashtable ();
281 // Well known properties
282 foreach (string s in WellKnownProperties)
283 // The value of properties can't be empty
284 properties [s] = " ";
287 public string FileVersion {
290 "" + (file_version >> 48) +
291 "." + ((file_version >> 32) & 0xffff) +
292 "." + ((file_version >> 16) & 0xffff) +
293 "." + ((file_version >> 0) & 0xffff);
297 long[] ver = new long [4] { 0, 0, 0, 0 };
299 string[] parts = value.Split ('.');
301 for (int i = 0; i < parts.Length; ++i) {
304 ver [i] = Int32.Parse (parts [i]);
306 catch (FormatException) {
311 file_version = (ver [0] << 48) | (ver [1] << 32) | (ver [2] << 16) + ver [3];
315 public virtual string this [string key] {
317 properties [key] = value;
321 // Accessors for well known properties
323 public virtual string Comments {
325 return (string)properties ["Comments"];
328 properties ["Comments"] = value == String.Empty ? " " : value;
332 public virtual string CompanyName {
334 return (string)properties ["CompanyName"];
337 properties ["CompanyName"] = value == String.Empty ? " " : value;
341 public virtual string LegalCopyright {
343 return (string)properties ["LegalCopyright"];
346 properties ["LegalCopyright"] = value == String.Empty ? " " : value;
350 public virtual string LegalTrademarks {
352 return (string)properties ["LegalTrademarks"];
355 properties ["LegalTrademarks"] = value == String.Empty ? " " : value;
359 public virtual string OriginalFilename {
361 return (string)properties ["OriginalFilename"];
364 properties ["OriginalFilename"] = value == String.Empty ? " " : value;
368 public virtual string ProductName {
370 return (string)properties ["ProductName"];
373 properties ["ProductName"] = value == String.Empty ? " " : value;
377 public virtual string ProductVersion {
379 return (string)properties ["ProductVersion"];
382 properties ["ProductVersion"] = value == String.Empty ? " " : value;
386 public virtual string InternalName {
388 return (string)properties ["InternalName"];
391 properties ["InternalName"] = value == String.Empty ? " " : value;
395 public virtual string FileDescription {
397 return (string)properties ["FileDescription"];
400 properties ["FileDescription"] = value == String.Empty ? " " : value;
404 public virtual int FileLanguage {
413 private void emit_padding (BinaryWriter w) {
414 Stream ms = w.BaseStream;
416 if ((ms.Position % 4) != 0)
420 private void patch_length (BinaryWriter w, long len_pos) {
421 Stream ms = w.BaseStream;
423 long pos = ms.Position;
424 ms.Position = len_pos;
425 w.Write ((short)(pos - len_pos));
429 public override void WriteTo (Stream ms)
431 using (BinaryWriter w = new BinaryWriter (ms, Encoding.Unicode)) {
433 // See the documentation for the VS_VERSIONINFO structure and
434 // its children on MSDN
439 w.Write ((short)0x34);
441 w.Write ("VS_VERSION_INFO".ToCharArray ());
447 w.Write ((uint)signature);
448 w.Write ((int)struct_version);
449 w.Write ((int)(file_version >> 32));
450 w.Write ((int)((file_version & 0xffffffff)));
452 w.Write ((int)(product_version >> 32));
453 w.Write ((int)(product_version & 0xffffffff));
454 w.Write ((int)file_flags_mask);
455 w.Write ((int)file_flags);
456 w.Write ((int)file_os);
457 w.Write ((int)file_type);
458 w.Write ((int)file_subtype);
459 w.Write ((int)(file_date >> 32));
460 w.Write ((int)(file_date & 0xffffffff));
465 long var_file_info_pos = ms.Position;
469 w.Write ("VarFileInfo".ToCharArray ());
472 if ((ms.Position % 4) != 0)
476 long var_pos = ms.Position;
480 w.Write ("Translation".ToCharArray ());
483 if ((ms.Position % 4) != 0)
486 w.Write ((short)file_lang);
487 w.Write ((short)file_codepage);
489 patch_length (w, var_pos);
491 patch_length (w, var_file_info_pos);
494 long string_file_info_pos = ms.Position;
498 w.Write ("StringFileInfo".ToCharArray ());
503 long string_table_pos = ms.Position;
507 w.Write (String.Format ("{0:x4}{1:x4}", file_lang, file_codepage).ToCharArray ());
512 foreach (string key in properties.Keys) {
513 string value = (string)properties [key];
515 long string_pos = ms.Position;
517 w.Write ((short)(value.ToCharArray ().Length + 1));
519 w.Write (key.ToCharArray ());
524 w.Write (value.ToCharArray ());
529 patch_length (w, string_pos);
532 patch_length (w, string_table_pos);
534 patch_length (w, string_file_info_pos);
541 internal class Win32ResFileReader {
545 public Win32ResFileReader (Stream s) {
550 int b1 = res_file.ReadByte ();
551 int b2 = res_file.ReadByte ();
553 if ((b1 == -1) || (b2 == -1))
556 return b1 | (b2 << 8);
560 int w1 = read_int16 ();
561 int w2 = read_int16 ();
563 if ((w1 == -1) || (w2 == -1))
565 return w1 | (w2 << 16);
568 private void read_padding () {
569 while ((res_file.Position % 4) != 0)
573 NameOrId read_ordinal () {
574 int i = read_int16 ();
575 if ((i & 0xffff) != 0) {
576 int j = read_int16 ();
577 return new NameOrId (j);
580 byte[] chars = new byte [16];
584 int j = read_int16 ();
587 if (pos == chars.Length) {
588 byte[] new_chars = new byte [chars.Length * 2];
589 Array.Copy (chars, new_chars, chars.Length);
592 chars [pos] = (byte)(j >> 8);
593 chars [pos + 1] = (byte)(j & 0xff);
597 return new NameOrId (new String (Encoding.Unicode.GetChars (chars, 0, pos)));
601 public ICollection ReadResources () {
602 ArrayList resources = new ArrayList ();
605 * We can't use a BinaryReader since we have to keep track of the
606 * stream position for padding.
613 int data_size = read_int32 ();
621 NameOrId type = read_ordinal ();
622 NameOrId name = read_ordinal ();
630 int language_id = read_int16 ();
633 //int characteristics =
637 /* Empty resource entry */
640 byte[] data = new byte [data_size];
641 res_file.Read (data, 0, data_size);
643 resources.Add (new Win32EncodedResource (type, name, language_id, data));
651 // This class represents one icon image in an .ico file
653 internal class ICONDIRENTRY {
657 public byte bColorCount;
658 public byte bReserved;
659 public Int16 wPlanes;
660 public Int16 wBitCount;
661 public Int32 dwBytesInRes;
662 public Int32 dwImageOffset;
666 public override string ToString () {
667 return "ICONDIRENTRY (" + bWidth + "x" + bHeight + " " + wBitCount + " bpp)";
672 // This class represents a Reader for Win32 .ico files
674 internal class Win32IconFileReader {
678 public Win32IconFileReader (Stream s) {
682 public ICONDIRENTRY[] ReadIcons () {
683 ICONDIRENTRY[] icons = null;
685 using (BinaryReader r = new BinaryReader (iconFile)) {
686 int idReserved = r.ReadInt16 ();
687 int idType = r.ReadInt16 ();
688 if ((idReserved != 0) || (idType != 1))
689 throw new Exception ("Invalid .ico file format");
690 long nitems = r.ReadInt16 ();
692 icons = new ICONDIRENTRY [nitems];
694 for (int i = 0; i < nitems; ++i) {
695 ICONDIRENTRY entry = new ICONDIRENTRY ();
697 entry.bWidth = r.ReadByte ();
698 entry.bHeight = r.ReadByte ();
699 entry.bColorCount = r.ReadByte ();
700 entry.bReserved = r.ReadByte ();
701 entry.wPlanes = r.ReadInt16 ();
702 entry.wBitCount = r.ReadInt16 ();
703 int dwBytesInRes = r.ReadInt32 ();
704 int dwImageOffset = r.ReadInt32 ();
707 entry.image = new byte [dwBytesInRes];
709 long pos = iconFile.Position;
710 iconFile.Position = dwImageOffset;
711 iconFile.Read (entry.image, 0, dwBytesInRes);
712 iconFile.Position = pos;
715 * The wPlanes and wBitCount members in the ICONDIRENTRY
716 * structure can be 0, so we set them from the BITMAPINFOHEADER
717 * structure that follows
720 if (entry.wPlanes == 0)
721 entry.wPlanes = (short)(entry.image [12] | (entry.image [13] << 8));
722 if (entry.wBitCount == 0)
723 entry.wBitCount = (short)(entry.image [14] | (entry.image [15] << 8));