我正在使用幻数创建简单的自解压存档来标记内容的开头。现在它是一个文本文件:
MAGICNUMBER .... 文本文件的内容
接下来,将文本文件复制到可执行文件的末尾:
复制programm.exe/b+textfile.txt/b sfx.exe
我正在尝试使用以下代码查找幻数的第二次出现(第一个显然是硬编码常量):
string my_filename = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
StreamReader file = new StreamReader(my_filename);
const int block_size = 1024;
const string magic = "MAGICNUMBER";
char[] buffer = new Char[block_size];
Int64 count = 0;
Int64 glob_pos = 0;
bool flag = false;
while (file.ReadBlock(buffer, 0, block_size) > 0)
{
var rel_pos = buffer.ToString().IndexOf(magic);
if ((rel_pos > -1) & (!flag))
{
flag = true;
continue;
}
if ((rel_pos > -1) & (flag == true))
{
glob_pos = block_size * count + rel_pos;
break;
}
count++;
}
using (FileStream fs = new FileStream(my_filename, FileMode.Open, FileAccess.Read))
{
byte[] b = new byte[fs.Length - glob_pos];
fs.Seek(glob_pos, SeekOrigin.Begin);
fs.Read(b, 0, (int)(fs.Length - glob_pos));
File.WriteAllBytes("c:/output.txt", b);
但由于某种原因,我复制了几乎整个文件,而不是最后的几千字节。是因为编译器优化,在类似的while循环中内联魔术常量吗?
我应该如何正确地进行自解压存档?
猜想我应该向后读取文件以避免编译器内联魔术常数乘法次数的问题。所以我通过以下方式修改了我的代码:
string my_filename = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
StreamReader file = new StreamReader(my_filename);
const int block_size = 1024;
const string magic = "MAGIC";
char[] buffer = new Char[block_size];
Int64 count = 0;
Int64 glob_pos = 0;
while (file.ReadBlock(buffer, 0, block_size) > 0)
{
var rel_pos = buffer.ToString().IndexOf(magic);
if (rel_pos > -1)
{
glob_pos = block_size * count + rel_pos;
}
count++;
}
using (FileStream fs = new FileStream(my_filename, FileMode.Open, FileAccess.Read))
{
byte[] b = new byte[fs.Length - glob_pos];
fs.Seek(glob_pos, SeekOrigin.Begin);
fs.Read(b, 0, (int)(fs.Length - glob_pos));
File.WriteAllBytes("c:/output.txt", b);
}
所以我扫描了所有文件一次,发现我将是最后一次出现幻数并从这里复制到它的末尾。虽然此过程创建的文件似乎比以前的尝试小,但它绝不是我附加到我的“自解压”存档中的相同文件。为什么?
我的猜测是,由于使用了从二进制到字符串的转换,附件开头的位置计算是错误的。如果是这样,我应该如何修改我的头寸计算以使其正确?
另外我应该如何选择幻数然后使用真实文件,例如pdf?我将无法轻松修改 pdf 以在其中包含预定义的幻数。