2017-09-25 32 views

回答

1

這裏是一個可行的解決方案,天真的和低效的,雖然它可能是:

using System; 
using System.IO; 
using System.Text; 
using System.Resources; 

namespace ResUtil { 

class Substream: Stream 
{ Stream Base; 
    long Orig; 
    long Len; 

    public override bool CanSeek 
    { get 
     { return Base.CanSeek; } 
    } 

    public override bool CanRead 
    { get 
     { return Base.CanRead && Position < Len; } 
    } 

    public override bool CanTimeout 
    { 
     get { return Base.CanTimeout; } 
    } 

    public override Boolean CanWrite { 
     get { 
     return Base.CanWrite; 
     } 
    } 

    public override long Position 
    { get 
     { return Base.Position - Orig; } 
     set 
     { Base.Position = value + Orig; } 
    } 

    public override Int64 Length { 
     get { return Len; } 
    } 

    public override void SetLength(Int64 value) 
    { throw new NotSupportedException(); } 

    // This is unnecessary, but very desirable, in order to override the default 
    // inefficient implementation via Read(Byte[],...): 
    // see: https://msdn.microsoft.com/en-us/library/system.io.stream.readbyte%28v=vs.110%29.aspx 
    public override Int32 ReadByte() 
    { return Base.ReadByte(); } 

    public override Int32 Read(Byte[] buffer,Int32 offset,Int32 count) 
    { return Base.Read(buffer, offset, count); } 

    public override void Write(Byte[] buffer,Int32 offset,Int32 count) 
    { throw new NotSupportedException(); } 

    public Substream(Stream s, long l) 
    { Base = s; 
     Orig = s.Position; 
     Len = l; 
    } 

    public override long Seek(long ofs, SeekOrigin orig) 
    { if(orig == SeekOrigin.Begin) 
     { ofs = ofs + Orig; } 
     return Base.Seek(ofs, orig); 
    } 

    public override void Flush() 
    { Base.Flush(); } 
} 

public static class BinResReader { // TODO: a more generic overload accepting a stream instead of the file path 

public static void Get 
(string file, string resName, out string type, out byte[] data) 
{ FileStream s; 
    ResourceReader rr; 
    bool found; 
    long len; 

    type = null; 
    data = null; 
    s = new FileStream(file, FileMode.Open); 
    while(true) 
    { if(!FindResHeader(s, out len)) 
     { break; } 
     try 
     { Substream ss = new Substream(s, len); 
     rr = new ResourceReader(ss); 
     } 
     catch(BadImageFormatException) // no resource here 
     { continue; } 

     found = true; 
     try 
     { rr.GetResourceData(resName, out type, out data); } 
     catch // resource may not be present 
     { found = false; } 
     ((IDisposable)rr).Dispose(); // rr.Dispose() won't compile in .NET 3.5 
     if(found) 
     { break; } 
     if(!s.CanRead) 
     { break; } 
    } 
    s.Dispose(); 
} 

// ---------------- Shift-based eight-byte queue in a UInt64 ---------------- 

static void Q_LR_In(ref UInt64 data, byte b) 
{ data = data << 8; 
    data = data | b; 
} 

static void Q_RL_In(ref UInt64 data, byte b) 
{ UInt64 bm; 

    data = data >> 8; 
    bm = (ulong)b << 7 * 8; 
    data = data | bm; 
} 

static uint Q_High(ulong data) 
{ return (uint)(data); } 

static uint Q_Low (ulong data) 
{ return (uint)((data >> 32)); } 

// ------------- Find the next location of suspected resource --------------- 

// locate next resource in stream s, return its length in bytes 
static bool FindResHeader(Stream s, out long len) 
{ bool found = false; 

    ulong data; 

    System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); 

    len  = 0; 
    data = 0xFFFFFFFFFFFFFFFF; // to decrease false alarms 

    if(s.Length < 9) 
    { goto NotFound; } 

    sw.Start(); 

    /* Buffered reading: */ 
    const int BufSize = 1024; 
    int i; 
    byte[] buffer = new byte[BufSize]; 
    int read; 

    while(!found) 
    { read = s.Read(buffer, 0, BufSize); 
     if(read == 0) 
     { break; } 
     for(i = 0; i < read; i++) 
     { Q_RL_In(ref data, buffer[i]); 
     if(Q_Low(data) != MagicNumber) 
     { continue; } 
     len = Q_High(data); 
     if(len > s.Length - s.Position - 4) 
     { continue; } 
     s.Seek(-4 - read + i + 1, SeekOrigin.Current); 
     found = true; 
     break; 
     } 
    } 
    sw.Stop(); 

NotFound: 
    return found; 
} 

// --------- Parsing of the various formats of string resource ----------- 

public static string GetStr(string file, string resName) 
{ return GetStr(file, resName, Encoding.ASCII); } 

public static string GetStr(string file, string resName, Encoding enc) 
{ byte[] data; 
    string text; 
    string type; 
    int count; 
    int index; 
    text = null; 
    Get(file, resName, out type, out data); 
    if(data != null) 
    { switch(type) 
     { case "ResourceTypeCode.ByteArray": 
      count = GetIntBE(data); 
      index = 4; 
     break; 
     case "ResourceTypeCode.String": 
      count = Read7BitEncodedInt(data, out index); 
     break; 
     case "ResourceTypeCode.Stream": 
      goto case "ResourceTypeCode.ByteArray"; 
     default: throw new Exception("Cannot convert resource type " + 
      type + " to string."); 
     } 
     text = enc.GetString(data, index, count); 
    } 
    return text; 
} 

// This is copied from the reference source: 
static int Read7BitEncodedInt(byte[] data, out int offset) 
{ 
    int count = 0; 
    int shift = 0; 
    offset = 0; 
    byte b; 
    do 
    { b = data[offset]; 
     offset++; 
     count |= (b & 0x7F) << shift; 
     shift += 7; 
    } 
    while ((b & 0x80) != 0); 
    return count; 
} 

// -------------------------- Utility routines --------------------------- 

static int GetIntBE(byte[] bytes) 
{ return bytes[0] | bytes[1]<<8 | bytes[2]<<16 | bytes[3]<<24; } 

static int GetIntLE(byte[] bytes) 
{ return bytes[3] | bytes[2]<<8 | bytes[1]<<16 | bytes[0]<<24; } 

// -------------------------- Initialization ----------------------------- 
static long MagicNumber; 
static BinResReader() 
{ MagicNumber = (uint)ResourceManager.MagicNumber; } 

}} 

它希望至少這些改進:

一個。一次讀取幾個或所有資源,

b。在搜索過程中提取並使用嵌入資源文件的名稱,而不是全部掃描。

另一種選擇是使用Mono.Cecil-thanks來自microsoft.public.dotnet.languages.csharp的ArneVajhøj。

相關問題