2008/06/17

如何把純文字檔放到 C 執行檔中?

請見 Embedding a File in an ExecutableConvert a File to a C Data Structure

一般方法至少三大類,最常見的就是利用 fopen 之類的 API 來自行處理 file I/O, 一種是第一篇文章說的,把 text file 轉成 object file 後再來引用指標的方式操作,一種是第二篇文章講的,將 text file 轉成 c char array struct。

先來看看文字檔,我改成多行:

$ cat data.txt
Hello, Wade.
This is a test line here
And this is the last line.
Add 4th line here.


底下是執行畫面,是在 cygwin 下執行的,因為 objcopy 的參數不太一樣,請修改成適當的,值得注意的是用 objdump 來看轉換後的 object file 內部的 symbol name 為 _binary_data_txt_start

$ objcopy.exe -I binary -O elf32-i386 -B i386 data.txt data.o

$ objdump.exe -x data.o

data.o: file format elf32-i386
data.o
architecture: i386, flags 0x00000010:
HAS_SYMS
start address 0x00000000

Sections:
Idx Name Size VMA LMA File off Algn
0 .data 00000054 00000000 00000000 00000034 2**0
CONTENTS, ALLOC, LOAD, DATA
SYMBOL TABLE:
00000000 l d .data 00000000 .data
00000000 g .data 00000000 _binary_data_txt_start
00000054 g .data 00000000 _binary_data_txt_end
00000054 g *ABS* 00000000 _binary_data_txt_size


底下列出測試用的 hello.c 及編譯、執行畫面,值得注意的是,因為 gcc 會在 extern symbol 前加上底線,因此命名方式跟原文不太一樣。


$ cat hello.c
#include

extern char binary_data_txt_start;
extern char binary_data_txt_end;

main()
{
char* p = &binary_data_txt_start;

while ( p != &binary_data_txt_end ) putchar(*p++);
}


$ gcc hello.c data.o

$ ./a
Hello, Wade.
This is a test line here
And this is the last line.
Add 4th line here.


第二種方式的 script 內容及執行畫面如下:

$ cat 2c.sh
#!/bin/bash

if [[ $# -ne 1 ]]; then
echo "Usage: $0 FILENAME"
exit 1
fi
file=$1

if [[ ! -f "$file" ]]; then
echo "File not found: $file"
exit 1
fi

cname=$file
cname=${cname//-/_}
cname=${cname//./_}

echo "static unsigned char $cname[] = {"
hexdump -v -e '" " 16/1 " 0x%02x, " "\n"' $file | \
sed -e '$s/0x ,//g'
echo "};"

$ ./2c.sh data.txt
static unsigned char data_txt[] = {
0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x57, 0x61, 0x64,
0x65, 0x2e, 0x0a, 0x54, 0x68, 0x69,
0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x74, 0x65, 0x73,
0x74, 0x20, 0x6c, 0x69, 0x6e, 0x65,
0x20, 0x68, 0x65, 0x72, 0x65, 0x0a, 0x41, 0x6e, 0x64, 0x20,
0x74, 0x68, 0x69, 0x73, 0x20, 0x69,
0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x61, 0x73, 0x74,
0x20, 0x6c, 0x69, 0x6e, 0x65, 0x2e,
0x0a, 0x41, 0x64, 0x64, 0x20, 0x34, 0x74, 0x68, 0x20, 0x6c,
0x69, 0x6e, 0x65, 0x20, 0x68, 0x65,
0x72, 0x65, 0x2e, 0x0a,
};

3 意見:

匿名 提到...

請問一個問題
我們在何種case下會需要把文字檔放進去阿?

菠蘿麵包 提到...

這種問題都有人問啊。很簡單,我的回答是,需要的時候。

我真的不是開玩笑的,舉例來說,有人會想要把密碼檔隱藏起來什麼的,也許你會說,這有另外十幾種方法,幹嘛用這種?嗯,只要你能想到,那當然都對,這邊也只是翻譯,另外,當成一種參考就好。

Kerwin 提到...

這招猛,
先學了...
謝謝分享!

有時明明只是簡單的程式,
卻要由檔案讀入一些設定,
有這招就省一些麻煩了!