using System;
using System.Drawing;
using System.Collections;
using System.Resources;
using System.Windows.Forms;
using System.IO;
using System.Xml;
using System.Globalization;
namespace resxtract
{
///
/// A command line utility to extract binary resources from xml resource (resx) files and
/// write them to separate correctly named files.
///
/// An attempt is made to reconstruct an object according to the Type definition
/// in the xml. Some types (Bitmap, Icon) are constructed from the underlying byte array
/// and written using their formal methods. Some resources (WAV files for example) are encoded
/// as plain byte arrays, so they are written directly to a file.
/// Note from Greg - I'm not really sure that this code represents the easiest way of
/// extracting the binary resources. I searched through the System.Resources namespace looking
/// for some standard utility classes to help me produce short and elegant code, but I couldn't
/// find any. So I'm stuck with the logic described above to inspect the Types, which I'm
/// not really happy with, as it doesn't seem very general purpose. Any advice on this matter
/// would be most welcome.
///
class AppMain
{
//==========================================================================================
[STAThread]
static int Main(string[] args)
{
AppMain app = new AppMain();
try
{
return app.Run(args);
}
catch (Exception ex)
{
Console.WriteLine("Failed to process '{0}' - {1}",args[0],ex.Message);
return 4;
}
}
//==========================================================================================
public AppMain()
{
}
//==========================================================================================
public int Run(string[] args)
{
if ((args.Length == 0) || ((args.Length == 1) && (args[0] == "/?")))
{
ShowHelp();
return 1;
}
if (!File.Exists(args[0]))
{
Console.WriteLine("Resource file '{0}' does not exist",args[0]);
return 2;
}
string outFolder = null;
if (args.Length >= 2)
{
if (!Directory.Exists(args[1]))
{
Console.WriteLine("Output folder '{0}' does not exist",args[1]);
return 3;
}
outFolder = args[1];
}
XmlDocument xdoc = new XmlDocument();
xdoc.Load(args[0]);
XmlNodeList nl = xdoc.GetElementsByTagName("data");
foreach (XmlNode n in nl)
{
string name = SafeSafeAttr(n,"name");
string type = SafeSafeAttr(n,"type");
string mime = SafeSafeAttr(n,"mimetype");
string val = n["value"].InnerText;
if (type != null)
{
Type t = Type.GetType(type);
//-----------------------------------------------------------------
if (t == typeof(Bitmap))
{
string ext = Path.GetExtension(name).ToLower(CultureInfo.InvariantCulture);
byte[] buffer = Convert.FromBase64String(val);
MemoryStream ms = new MemoryStream(buffer);
Bitmap img = new Bitmap(ms);
switch (ext)
{
case ".bmp" :
img.Save(MakeFileName(outFolder,name),System.Drawing.Imaging.ImageFormat.Bmp);
break;
case ".gif" :
img.Save(MakeFileName(outFolder,name),System.Drawing.Imaging.ImageFormat.Gif);
break;
case ".jpg" :
case ".jpeg" :
img.Save(MakeFileName(outFolder,name),System.Drawing.Imaging.ImageFormat.Jpeg);
break;
default :
img.Save(MakeFileName(outFolder,name),System.Drawing.Imaging.ImageFormat.Bmp);
break;
}
ms.Close();
img.Dispose();
Console.WriteLine("Extracted Bitmap '{0}' ({1} bytes)",name,buffer.Length);
}
//-----------------------------------------------------------------
if (t == typeof(Icon))
{
byte[] buffer = Convert.FromBase64String(val);
MemoryStream ms = new MemoryStream(buffer);
Icon ico = new Icon(ms);
FileStream fs = new FileStream(MakeFileName(outFolder,name),FileMode.Create,FileAccess.Write);
ico.Save(fs);
fs.Close();
Console.WriteLine("Extracted Icon '{0}' ({1} bytes)",name,buffer.Length);
ico.Dispose();
}
//-----------------------------------------------------------------
if (t.IsArray && (t.GetElementType() == typeof(byte)))
{
byte[] buffer = Convert.FromBase64String(val);
BinaryWriter bf = new BinaryWriter(new FileStream(MakeFileName(outFolder,name),FileMode.Create,FileAccess.Write));
bf.Write(buffer);
bf.Close();
Console.WriteLine("Extracted Buffer '{0}' ({1} bytes)",name,buffer.Length);
}
}
}
return 0;
}
//==========================================================================================
private string MakeFileName(string folder, string fileName)
{
if ((folder == null) || (folder.Length == 0))
return fileName;
return Path.Combine(folder,fileName);
}
//==========================================================================================
private string SafeSafeAttr(XmlNode n, string attrName)
{
XmlAttribute attr = n.Attributes[attrName];
if (attr == null)
return null;
return attr.Value;
}
//==========================================================================================
private void ShowHelp()
{
string[] lines =
{
"DESCRIPTION",
" Extracts binary objects from xml resource (resx) files.",
"SYNTAX\n" +
" resxtract resxfile [ outfolder ]",
"PARAMETERS",
" resxfile ....... The resx file to process.",
" outfolder ...... The optional output folder, default is the current folder."
};
for (int i=0; i