updating to the latest module.
[mono.git] / mcs / class / Managed.Windows.Forms / System.Resources / ResXResourceReader.cs
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 // 
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 // 
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 //
20 // Copyright (c) 2004 Novell, Inc.
21 //
22 // Authors:
23 //      Duncan Mak      duncan@ximian.com
24 //      Nick Drochak    ndrochak@gol.com
25 //      Paolo Molaro    lupus@ximian.com
26 //
27
28 // NOT COMPLETE
29
30 using System.Collections;
31 using System.Resources;
32 using System.IO;
33 using System.Xml;
34 using System.ComponentModel;
35 using System.Globalization;
36 using System.Runtime.Serialization.Formatters.Binary;
37
38 namespace System.Resources
39 {
40         public class ResXResourceReader : IResourceReader, IDisposable
41         {
42                 Stream stream;
43                 XmlTextReader reader;
44                 Hashtable hasht;
45
46                 // Constructors
47                 public ResXResourceReader (Stream stream)
48                 {
49                         if (stream == null)
50                                 throw new ArgumentNullException ("Value cannot be null.");
51                         
52                         if (!stream.CanRead)
53                                 throw new ArgumentException ("Stream was not readable.");
54
55                         this.stream = stream;
56                         basic_setup ();
57                 }
58                 
59                 public ResXResourceReader (string fileName)
60                 {
61                         stream = File.OpenRead (fileName);
62                         basic_setup ();
63                 }
64
65                 void basic_setup () {
66                         reader = new XmlTextReader (stream);
67                         hasht = new Hashtable ();
68
69                         if (!IsStreamValid()){
70                                 throw new ArgumentException("Stream is not a valid .resx file!  It was possibly truncated.");
71                         }
72                         load_data ();
73                 }
74                 
75                 static string get_attr (XmlTextReader reader, string name) {
76                         if (!reader.HasAttributes)
77                                 return null;
78                         for (int i = 0; i < reader.AttributeCount; i++) {
79                                 reader.MoveToAttribute (i);
80                                 if (String.Compare (reader.Name, name, true) == 0) {
81                                         string v = reader.Value;
82                                         reader.MoveToElement ();
83                                         return v;
84                                 }
85                         }
86                         reader.MoveToElement ();
87                         return null;
88                 }
89
90                 static string get_value (XmlTextReader reader, string name) {
91                         bool gotelement = false;
92                         while (reader.Read ()) {
93                                 if (reader.NodeType == XmlNodeType.Element && String.Compare (reader.Name, name, true) == 0) {
94                                         gotelement = true;
95                                         break;
96                                 }
97                         }
98                         if (!gotelement)
99                                 return null;
100                         while (reader.Read ()) {
101                                 if (reader.NodeType == XmlNodeType.Text || reader.NodeType == XmlNodeType.CDATA) {
102                                         string v = reader.Value;
103                                         return v;
104                                 }
105                                 else if (reader.NodeType == XmlNodeType.EndElement && reader.Value == string.Empty)
106                                 {
107                                         string v = reader.Value;
108                                         return v;
109                                 }
110                         }
111                         return null;
112                 }
113
114                 private bool IsStreamValid() {
115                         bool gotroot = false;
116                         bool gotmime = false;
117                         
118                         while (reader.Read ()) {
119                                 if (reader.NodeType == XmlNodeType.Element && String.Compare (reader.Name, "root", true) == 0) {
120                                         gotroot = true;
121                                         break;
122                                 }
123                         }
124                         if (!gotroot)
125                                 return false;
126                         while (reader.Read ()) {
127                                 if (reader.NodeType == XmlNodeType.Element && String.Compare (reader.Name, "resheader", true) == 0) {
128                                         string v = get_attr (reader, "name");
129                                         if (v != null && String.Compare (v, "resmimetype", true) == 0) {
130                                                 v = get_value (reader, "value");
131                                                 if (String.Compare (v, "text/microsoft-resx", true) == 0) {
132                                                         gotmime = true;
133                                                         break;
134                                                 }
135                                         }
136                                 } else if (reader.NodeType == XmlNodeType.Element && String.Compare (reader.Name, "data", true) == 0) {
137                                         /* resheader apparently can appear anywhere, so we collect
138                                          * the data even if we haven't validated yet.
139                                          */
140                                         string n = get_attr (reader, "name");
141                                         if (n != null) {
142                                                 string v = get_value (reader, "value");
143                                                 hasht [n] = v;
144                                         }
145                                 }
146                         }
147                         return gotmime;
148                 }
149
150                 private void load_data ()
151                 {
152                         while (reader.Read ()) {
153                                 if (reader.NodeType == XmlNodeType.Element && String.Compare (reader.Name, "data", true) == 0) {
154                                         string n = get_attr (reader, "name");
155                                         string t = get_attr (reader, "type");
156                                         string mt = get_attr (reader, "mimetype");
157
158                                         Type tt = t == null ? null : Type.GetType (t);
159
160                                         if (t != null && tt == null) {
161                                                 throw new SystemException ("The type `" + t +"' could not be resolved");
162                                         }
163                                         if (tt == typeof (ResXNullRef)) {
164                                                 hasht [n] = null;
165                                                 continue;
166                                         }
167                                         if (n != null) {
168                                                 object v = null;
169                                                 string val = get_value (reader, "value");
170                                                 if (mt != null && tt != null) {
171                                                         TypeConverter c = TypeDescriptor.GetConverter (tt);
172                                                         v = c.ConvertFrom (Convert.FromBase64String (val));
173                                                 } else if (tt != null) {
174                                                         TypeConverter c = TypeDescriptor.GetConverter (tt);
175                                                         v = c.ConvertFromString (val);
176                                                 } else if (mt != null) {
177                                                         byte [] data = Convert.FromBase64String (val);
178                                                         BinaryFormatter f = new BinaryFormatter ();
179                                                         using (MemoryStream s = new MemoryStream (data)) {
180                                                                 v = f.Deserialize (s);
181                                                         }
182                                                 } else {
183                                                         v = val;
184                                                 }
185                                                 hasht [n] = v;
186                                         }
187                                 }
188                         }
189                 }
190
191                 public void Close ()
192                 {
193                         stream.Close ();
194                         stream = null;
195                 }
196                 
197                 public IDictionaryEnumerator GetEnumerator () {
198                         if (null == stream){
199                                 throw new InvalidOperationException("ResourceReader is closed.");
200                         }
201                         else {
202                                 return hasht.GetEnumerator ();
203                         }
204                 }
205                 
206                 IEnumerator IEnumerable.GetEnumerator ()
207                 {
208                         return ((IResourceReader) this).GetEnumerator();
209                 }
210                 
211                 [MonoTODO]
212                 void IDisposable.Dispose ()
213                 {
214                         // FIXME: is this all we need to do?
215                         Close();
216                 }
217                 
218         }  // public sealed class ResXResourceReader
219 } // namespace System.Resources