fix typo
[mono.git] / mcs / monoresgen / monoresgen.cs
1 /*
2  * monoresgen: convert between the resource formats (.txt, .resources, .resx).
3  *
4  * Copyright (c) 2002 Ximian, Inc
5  *
6  * Author: Paolo Molaro (lupus@ximian.com)
7  */
8
9 /*
10  * TODO:
11  * * escape/unescape in the .txt reader/writer to be able to roundtrip values with newlines
12  *   (unlike the MS ResGen utility)
13  */
14
15 using System;
16 using System.IO;
17 using System.Collections;
18 using System.Resources;
19 using System.Reflection;
20
21 class ResGen {
22
23         static Assembly swf;
24         static Type resxr;
25         static Type resxw;
26
27         /*
28          * We load the ResX format stuff on demand, since the classes are in 
29          * System.Windows.Forms (!!!) and we can't depend on that assembly in mono, yet.
30          */
31         static void LoadResX () {
32                 if (swf != null)
33                         return;
34                 try {
35                         swf = Assembly.LoadWithPartialName ("System.Windows.Forms");
36                         resxr = swf.GetType ("System.Resources.ResXResourceReader");
37                         resxw = swf.GetType ("System.Resources.ResXResourceWriter");
38                 } catch (Exception e) {
39                         throw new Exception ("Cannot load support for ResX format: " + e.Message);
40                 }
41         }
42
43         static void Usage () {
44                 string Usage = @"Mono Resource Generator version 0.1
45 Usage:
46                 monoresgen source.ext [dest.ext]
47                 monoresgen /compile source.ext[,dest.resources] [...]
48
49 Convert a resource file from one format to another.
50 The currently supported formats are: '.txt' '.resources' '.resx' '.po'.
51 If the destination file is not specified, source.resources will be used.
52 The /compile option takes a list of .resX or .txt files to convert to
53 .resources files in one bulk operation, replacing .ext with .resources for
54 the output file name.
55 ";
56                 Console.WriteLine( Usage );
57         }
58         
59         static IResourceReader GetReader (Stream stream, string name) {
60                 string format = Path.GetExtension (name);
61                 switch (format.ToLower ()) {
62                 case ".po":
63                         return new PoResourceReader (stream);
64                 case ".txt":
65                 case ".text":
66                         return new TxtResourceReader (stream);
67                 case ".resources":
68                         return new ResourceReader (stream);
69                 case ".resx":
70                         LoadResX ();
71                         return (IResourceReader)Activator.CreateInstance (resxr, new object[] {stream});
72                 default:
73                         throw new Exception ("Unknown format in file " + name);
74                 }
75         }
76         
77         static IResourceWriter GetWriter (Stream stream, string name) {
78                 string format = Path.GetExtension (name);
79                 switch (format.ToLower ()) {
80                 case ".po":
81                         return new PoResourceWriter (stream);
82                 case ".txt":
83                 case ".text":
84                         return new TxtResourceWriter (stream);
85                 case ".resources":
86                         return new ResourceWriter (stream);
87                 case ".resx":
88                         LoadResX ();
89                         return (IResourceWriter)Activator.CreateInstance (resxw, new object[] {stream});
90                 default:
91                         throw new Exception ("Unknown format in file " + name);
92                 }
93         }
94         
95         static int CompileResourceFile(string sname, string dname ) {
96                 FileStream source, dest;
97                 IResourceReader reader;
98                 IResourceWriter writer;
99
100                 try {
101                         source = new FileStream (sname, FileMode.Open, FileAccess.Read);
102                         dest = new FileStream (dname, FileMode.OpenOrCreate, FileAccess.Write);
103
104                         reader = GetReader (source, sname);
105                         writer = GetWriter (dest, dname);
106
107                         int rescount = 0;
108                         foreach (DictionaryEntry e in reader) {
109                                 rescount++;
110                                 object val = e.Value;
111                                 if (val is string)
112                                         writer.AddResource ((string)e.Key, (string)e.Value);
113                                 else
114                                         writer.AddResource ((string)e.Key, e.Value);
115                         }
116                         Console.WriteLine( "Read in {0} resources from '{1}'", rescount, sname );
117
118                         reader.Close ();
119                         writer.Close ();
120                         Console.WriteLine("Writing resource file...  Done.");
121                 } catch (Exception e) {
122                         Console.WriteLine ("Error: {0}", e.Message);
123                         Exception inner = e.InnerException;
124                         if (inner != null)
125                                 Console.WriteLine ("Inner exception: {0}", inner.Message);
126                         return 1;
127                 }
128                 return 0;
129         }
130         
131         static int Main (string[] args) {
132                 string sname = "", dname = ""; 
133                 if ((int) args.Length < 1 || args[0] == "-h" || args[0] == "-?" || args[0] == "/h" || args[0] == "/?") {
134                           Usage();
135                           return 1;
136                 }               
137                 if (args[0] == "/compile" || args[0] == "-compile") {
138                         for ( int i=1; i< args.Length; i++ ) {                          
139                                 if ( args[i].IndexOf(",") != -1 ){
140                                         string[] pair =  args[i].Split(',');
141                                         sname = pair[0]; 
142                                         dname = pair[1];
143                                         if (dname == ""){
144                                                 Console.WriteLine(@"error: You must specify an input & outfile file name like this:");
145                                                 Console.WriteLine("inFile.txt,outFile.resources." );
146                                                 Console.WriteLine("You passed in '{0}'.", args[i] );
147                                                 return 1;
148                                         }
149                                 } else {
150                                         sname = args[i]; 
151                                         dname = Path.ChangeExtension (sname, "resources");
152                                 }
153                                 int ret = CompileResourceFile( sname, dname );
154                                 if (ret != 0 ) {
155                                         return ret;
156                                 }
157                         }
158                         return 0;
159                 
160                 }
161                 else if (args.Length == 1) {
162                         sname = args [0];
163                         dname = Path.ChangeExtension (sname, "resources");
164                 } else if (args.Length != 2) {
165                         Usage ();
166                         return 1;
167                 } else {
168                         sname = args [0];
169                         dname = args [1];                       
170                 }               
171                 return CompileResourceFile( sname, dname );
172         }
173 }
174
175 class TxtResourceWriter : IResourceWriter {
176         StreamWriter s;
177         
178         public TxtResourceWriter (Stream stream) {
179                 s = new StreamWriter (stream);
180         }
181         
182         public void AddResource (string name, byte[] value) {
183                 throw new Exception ("Binary data not valid in a text resource file");
184         }
185         
186         public void AddResource (string name, object value) {
187                 if (value is string) {
188                         AddResource (name, (string)value);
189                         return;
190                 }
191                 throw new Exception ("Objects not valid in a text resource file");
192         }
193         
194         /* FIXME: handle newlines */
195         public void AddResource (string name, string value) {
196                 s.WriteLine ("{0}={1}", name, value);
197         }
198         
199         public void Close () {
200                 s.Close ();
201         }
202         
203         public void Dispose () {}
204         
205         public void Generate () {}
206 }
207
208 class TxtResourceReader : IResourceReader {
209         Hashtable data;
210         Stream s;
211         
212         public TxtResourceReader (Stream stream) {
213                 data = new Hashtable ();
214                 s = stream;
215                 Load ();
216         }
217         
218         public virtual void Close () {
219         }
220         
221         public IDictionaryEnumerator GetEnumerator() {
222                 return data.GetEnumerator ();
223         }
224         
225         void Load () {
226                 StreamReader reader = new StreamReader (s);
227                 string line, key, val;
228                 int epos, line_num = 0;
229                 while ((line = reader.ReadLine ()) != null) {
230                         line_num++;
231                         line = line.Trim ();
232                         if (line.Length == 0 || line [0] == '#' ||
233                             line [0] == ';')
234                                 continue;
235                         epos = line.IndexOf ('=');
236                         if (epos < 0) 
237                                 throw new Exception ("Invalid format at line " + line_num);
238                         key = line.Substring (0, epos);
239                         val = line.Substring (epos + 1);
240                         key = key.Trim ();
241                         val = val.Trim ();
242                         if (key.Length == 0) 
243                                 throw new Exception ("Key is empty at line " + line_num);
244                         data.Add (key, val);
245                 }
246         }
247         
248         IEnumerator IEnumerable.GetEnumerator () {
249                 return ((IResourceReader) this).GetEnumerator();
250         }
251
252         void IDisposable.Dispose () {}
253 }
254
255 class PoResourceReader : IResourceReader {
256         Hashtable data;
257         Stream s;
258         int line_num;
259         
260         public PoResourceReader (Stream stream)
261         {
262                 data = new Hashtable ();
263                 s = stream;
264                 Load ();
265         }
266         
267         public virtual void Close ()
268         {
269                 s.Close ();
270         }
271         
272         public IDictionaryEnumerator GetEnumerator()
273         {
274                 return data.GetEnumerator ();
275         }
276         
277         string GetValue (string line)
278         {
279                 int begin = line.IndexOf ('"');
280                 if (begin == -1)
281                         throw new FormatException (String.Format ("No begin quote at line {0}: {1}", line_num, line));
282
283                 int end = line.LastIndexOf ('"');
284                 if (end == -1)
285                         throw new FormatException (String.Format ("No closing quote at line {0}: {1}", line_num, line));
286
287                 return line.Substring (begin + 1, end - begin - 1);
288         }
289         
290         void Load ()
291         {
292                 StreamReader reader = new StreamReader (s);
293                 string line, msgstr;
294                 string msgid = null;
295                 bool haveID = false;
296
297                 while ((line = reader.ReadLine ()) != null) {
298                         line_num++;
299                         line = line.Trim ();
300                         if (line.Length == 0 || line [0] == '#' ||
301                             line [0] == ';' || line [0] == '"')
302                                 continue;
303
304                         if (!haveID) {
305                                 msgid = GetValue (line);
306                                 haveID = true;
307                                 continue;
308                         }
309
310                         msgstr = GetValue (line);
311                         haveID = false;
312                         data.Add (msgid, msgstr);
313                 }
314         }
315         
316         IEnumerator IEnumerable.GetEnumerator ()
317         {
318                 return GetEnumerator();
319         }
320
321         void IDisposable.Dispose ()
322         {
323                 if (data != null)
324                         data = null;
325
326                 if (s != null) {
327                         s.Close ();
328                         s = null;
329                 }
330         }
331 }
332
333 class PoResourceWriter : IResourceWriter
334 {
335         TextWriter s;
336         
337         public PoResourceWriter (Stream stream)
338         {
339                 s = new StreamWriter (stream);
340         }
341         
342         public void AddResource (string name, byte [] value)
343         {
344                 throw new InvalidOperationException ("Binary data not valid in a po resource file");
345         }
346         
347         public void AddResource (string name, object value)
348         {
349                 if (value is string) {
350                         AddResource (name, (string) value);
351                         return;
352                 }
353                 throw new InvalidOperationException ("Objects not valid in a po resource file");
354         }
355         
356         public void AddResource (string name, string value)
357         {
358                 s.WriteLine ("msgid \"{0}\"", name);
359                 s.WriteLine ("msgstr \"{0}\"", value);
360                 s.WriteLine ();
361         }
362         
363         public void Close ()
364         {
365                 s.Close ();
366         }
367         
368         public void Dispose () { }
369         
370         public void Generate () {}
371 }