2 * monoresgen: convert between the resource formats (.txt, .resources, .resx).
4 * Copyright (c) 2002 Ximian, Inc
6 * Author: Paolo Molaro (lupus@ximian.com)
11 * * escape/unescape in the .txt reader/writer to be able to roundtrip values with newlines
12 * (unlike the MS ResGen utility)
17 using System.Collections;
18 using System.Resources;
19 using System.Reflection;
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.
31 static void LoadResX () {
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);
43 static void Usage () {
44 string Usage = @"Mono Resource Generator version 0.1
46 monoresgen source.ext [dest.ext]
47 monoresgen /compile source.ext[,dest.resources] [...]
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
56 Console.WriteLine( Usage );
59 static IResourceReader GetReader (Stream stream, string name) {
60 string format = Path.GetExtension (name);
61 switch (format.ToLower ()) {
63 return new PoResourceReader (stream);
66 return new TxtResourceReader (stream);
68 return new ResourceReader (stream);
71 return (IResourceReader)Activator.CreateInstance (resxr, new object[] {stream});
73 throw new Exception ("Unknown format in file " + name);
77 static IResourceWriter GetWriter (Stream stream, string name) {
78 string format = Path.GetExtension (name);
79 switch (format.ToLower ()) {
81 return new PoResourceWriter (stream);
84 return new TxtResourceWriter (stream);
86 return new ResourceWriter (stream);
89 return (IResourceWriter)Activator.CreateInstance (resxw, new object[] {stream});
91 throw new Exception ("Unknown format in file " + name);
95 static int CompileResourceFile(string sname, string dname ) {
96 FileStream source, dest;
97 IResourceReader reader;
98 IResourceWriter writer;
101 source = new FileStream (sname, FileMode.Open, FileAccess.Read);
102 dest = new FileStream (dname, FileMode.OpenOrCreate, FileAccess.Write);
104 reader = GetReader (source, sname);
105 writer = GetWriter (dest, dname);
108 foreach (DictionaryEntry e in reader) {
110 object val = e.Value;
112 writer.AddResource ((string)e.Key, (string)e.Value);
114 writer.AddResource ((string)e.Key, e.Value);
116 Console.WriteLine( "Read in {0} resources from '{1}'", rescount, sname );
120 Console.WriteLine("Writing resource file... Done.");
121 } catch (Exception e) {
122 Console.WriteLine ("Error: {0}", e.Message);
123 Exception inner = e.InnerException;
125 Console.WriteLine ("Inner exception: {0}", inner.Message);
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] == "/?") {
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(',');
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] );
151 dname = Path.ChangeExtension (sname, "resources");
153 int ret = CompileResourceFile( sname, dname );
161 else if (args.Length == 1) {
163 dname = Path.ChangeExtension (sname, "resources");
164 } else if (args.Length != 2) {
171 return CompileResourceFile( sname, dname );
175 class TxtResourceWriter : IResourceWriter {
178 public TxtResourceWriter (Stream stream) {
179 s = new StreamWriter (stream);
182 public void AddResource (string name, byte[] value) {
183 throw new Exception ("Binary data not valid in a text resource file");
186 public void AddResource (string name, object value) {
187 if (value is string) {
188 AddResource (name, (string)value);
191 throw new Exception ("Objects not valid in a text resource file");
194 /* FIXME: handle newlines */
195 public void AddResource (string name, string value) {
196 s.WriteLine ("{0}={1}", name, value);
199 public void Close () {
203 public void Dispose () {}
205 public void Generate () {}
208 class TxtResourceReader : IResourceReader {
212 public TxtResourceReader (Stream stream) {
213 data = new Hashtable ();
218 public virtual void Close () {
221 public IDictionaryEnumerator GetEnumerator() {
222 return data.GetEnumerator ();
226 StreamReader reader = new StreamReader (s);
227 string line, key, val;
228 int epos, line_num = 0;
229 while ((line = reader.ReadLine ()) != null) {
232 if (line.Length == 0 || line [0] == '#' ||
235 epos = line.IndexOf ('=');
237 throw new Exception ("Invalid format at line " + line_num);
238 key = line.Substring (0, epos);
239 val = line.Substring (epos + 1);
243 throw new Exception ("Key is empty at line " + line_num);
248 IEnumerator IEnumerable.GetEnumerator () {
249 return ((IResourceReader) this).GetEnumerator();
252 void IDisposable.Dispose () {}
255 class PoResourceReader : IResourceReader {
260 public PoResourceReader (Stream stream)
262 data = new Hashtable ();
267 public virtual void Close ()
272 public IDictionaryEnumerator GetEnumerator()
274 return data.GetEnumerator ();
277 string GetValue (string line)
279 int begin = line.IndexOf ('"');
281 throw new FormatException (String.Format ("No begin quote at line {0}: {1}", line_num, line));
283 int end = line.LastIndexOf ('"');
285 throw new FormatException (String.Format ("No closing quote at line {0}: {1}", line_num, line));
287 return line.Substring (begin + 1, end - begin - 1);
292 StreamReader reader = new StreamReader (s);
297 while ((line = reader.ReadLine ()) != null) {
300 if (line.Length == 0 || line [0] == '#' ||
301 line [0] == ';' || line [0] == '"')
305 msgid = GetValue (line);
310 msgstr = GetValue (line);
312 data.Add (msgid, msgstr);
316 IEnumerator IEnumerable.GetEnumerator ()
318 return GetEnumerator();
321 void IDisposable.Dispose ()
333 class PoResourceWriter : IResourceWriter
337 public PoResourceWriter (Stream stream)
339 s = new StreamWriter (stream);
342 public void AddResource (string name, byte [] value)
344 throw new InvalidOperationException ("Binary data not valid in a po resource file");
347 public void AddResource (string name, object value)
349 if (value is string) {
350 AddResource (name, (string) value);
353 throw new InvalidOperationException ("Objects not valid in a po resource file");
356 public void AddResource (string name, string value)
358 s.WriteLine ("msgid \"{0}\"", name);
359 s.WriteLine ("msgstr \"{0}\"", value);
368 public void Dispose () { }
370 public void Generate () {}