// Duncan Mak duncan@ximian.com
// Gonzalo Paniagua Javier gonzalo@ximian.com
// Peter Bartok pbartok@novell.com
-// Gary Barnett
-//
+// Gary Barnett gary.barnett.mono@gmail.com
+// includes code by Mike Krüger and Lluis Sanchez
using System.ComponentModel;
using System.IO;
void InitWriter ()
{
if (filename != null)
- stream = File.OpenWrite (filename);
+ stream = File.Open (filename, FileMode.Create);
if (textwriter == null)
textwriter = new StreamWriter (stream, Encoding.UTF8);
writer.WriteEndElement ();
}
- void WriteBytes (string name, Type type, byte [] value)
+ void WriteBytes (string name, Type type, byte [] value, string comment)
{
- WriteBytes (name, type, value, 0, value.Length);
+ WriteBytes (name, type, value, 0, value.Length, comment);
}
void WriteString (string name, string value)
if (writer == null)
InitWriter ();
- WriteBytes (name, value.GetType (), value);
+ WriteBytes (name, value.GetType (), value, null);
}
public void AddResource (string name, object value)
return;
}
- if (value is byte[]) {
- AddResource (name, (byte[]) value);
- return;
- }
-
if (name == null)
throw new ArgumentNullException ("name");
if (writer == null)
InitWriter ();
+ if (value is byte[]) {
+ WriteBytes (name, value.GetType (), (byte []) value, comment);
+ return;
+ }
+
if (value == null) {
// nulls written as ResXNullRef
- WriteString (name, "", typeof (ResXNullRef), comment); //FIXME: ive included comment here
+ WriteString (name, "", typeof (ResXNullRef), comment);
return;
}
- // FIXME: why no comments for any of the below? are there other code paths without comments?
+
TypeConverter converter = TypeDescriptor.GetConverter (value);
+ if (value is ResXFileRef) {
+ ResXFileRef fileRef = ProcessFileRefBasePath ((ResXFileRef) value);
+ string str = (string) converter.ConvertToInvariantString (fileRef);
+ WriteString (name, str, value.GetType (), comment);
+ return;
+ }
+
if (converter != null && converter.CanConvertTo (typeof (string)) && converter.CanConvertFrom (typeof (string))) {
string str = (string) converter.ConvertToInvariantString (value);
- WriteString (name, str, value.GetType ());
+ WriteString (name, str, value.GetType (), comment);
return;
}
if (converter != null && converter.CanConvertTo (typeof (byte[])) && converter.CanConvertFrom (typeof (byte[]))) {
byte[] b = (byte[]) converter.ConvertTo (value, typeof (byte[]));
- WriteBytes (name, value.GetType (), b);
+ WriteBytes (name, value.GetType (), b, comment);
return;
}
if (node.IsWritable)
WriteWritableNode (node);
- else if (node.FileRef != null)
+ else if (node.FileRef != null)
AddResource (node.Name, node.FileRef, node.Comment);
else
AddResource (node.Name, node.GetValue ((AssemblyName []) null), node.Comment);
}
+ ResXFileRef ProcessFileRefBasePath (ResXFileRef fileRef)
+ {
+ if (String.IsNullOrEmpty (BasePath))
+ return fileRef;
+
+ string newPath = AbsoluteToRelativePath (BasePath, fileRef.FileName);
+ return new ResXFileRef (newPath, fileRef.TypeName, fileRef.TextFileEncoding);
+ }
+
+ static bool IsSeparator (char ch)
+ {
+ return ch == Path.DirectorySeparatorChar || ch == Path.AltDirectorySeparatorChar || ch == Path.VolumeSeparatorChar;
+ }
+ //adapted from MonoDevelop.Core
+ unsafe static string AbsoluteToRelativePath (string baseDirectoryPath, string absPath)
+ {
+ if (string.IsNullOrEmpty (baseDirectoryPath))
+ return absPath;
+
+ baseDirectoryPath = baseDirectoryPath.TrimEnd (Path.DirectorySeparatorChar);
+
+ fixed (char* bPtr = baseDirectoryPath, aPtr = absPath) {
+ var bEnd = bPtr + baseDirectoryPath.Length;
+ var aEnd = aPtr + absPath.Length;
+ char* lastStartA = aEnd;
+ char* lastStartB = bEnd;
+
+ int indx = 0;
+ // search common base path
+ var a = aPtr;
+ var b = bPtr;
+ while (a < aEnd) {
+ if (*a != *b)
+ break;
+ if (IsSeparator (*a)) {
+ indx++;
+ lastStartA = a + 1;
+ lastStartB = b;
+ }
+ a++;
+ b++;
+ if (b >= bEnd) {
+ if (a >= aEnd || IsSeparator (*a)) {
+ indx++;
+ lastStartA = a + 1;
+ lastStartB = b;
+ }
+ break;
+ }
+ }
+ if (indx == 0)
+ return absPath;
+
+ if (lastStartA >= aEnd)
+ return ".";
+
+ // handle case a: some/path b: some/path/deeper...
+ if (a >= aEnd) {
+ if (IsSeparator (*b)) {
+ lastStartA = a + 1;
+ lastStartB = b;
+ }
+ }
+
+ // look how many levels to go up into the base path
+ int goUpCount = 0;
+ while (lastStartB < bEnd) {
+ if (IsSeparator (*lastStartB))
+ goUpCount++;
+ lastStartB++;
+ }
+ var size = goUpCount * 2 + goUpCount + aEnd - lastStartA;
+ var result = new char [size];
+ fixed (char* rPtr = result) {
+ // go paths up
+ var r = rPtr;
+ for (int i = 0; i < goUpCount; i++) {
+ *(r++) = '.';
+ *(r++) = '.';
+ *(r++) = Path.DirectorySeparatorChar;
+ }
+ // copy the remaining absulute path
+ while (lastStartA < aEnd)
+ *(r++) = *(lastStartA++);
+ }
+ return new string (result);
+ }
+ }
+
// avoids instantiating objects
void WriteWritableNode (ResXDataNode node)
{
writer.WriteStartElement ("data");
writer.WriteAttributeString ("name", node.Name);
- if (!(node.type == null || node.type.Equals (String.Empty)))
- writer.WriteAttributeString ("type", node.type);
- if (!(node.mime_type == null || node.mime_type.Equals (String.Empty)))
- writer.WriteAttributeString ("mimetype", node.mime_type);
+ if (!(node.Type == null || node.Type.Equals (String.Empty)))
+ writer.WriteAttributeString ("type", node.Type);
+ if (!(node.MimeType == null || node.MimeType.Equals (String.Empty)))
+ writer.WriteAttributeString ("mimetype", node.MimeType);
writer.WriteStartElement ("value");
- writer.WriteString (node.dataString);
+ writer.WriteString (node.DataString);
writer.WriteEndElement ();
if (!(node.Comment == null || node.Comment.Equals (String.Empty))) {
writer.WriteStartElement ("comment");