詳解Cocoa資源文件嵌入
Cocoa資源文件嵌入是本文要介紹的內(nèi)容,主要是倆學習Cocoa/iPhone App/靜態(tài)庫 嵌入資源文件 rtb v0.1發(fā)布,軟件開發(fā)中,可能需要把用到的資源文件嵌入到二進制執(zhí)行文件中,例如生成單個執(zhí)行文件、防止機密或版權信息被PE工具查看或修改、嵌入圖片資源到靜態(tài)庫中等等。
在Mac OSX Cocoa 或iOS開發(fā)中,編譯生成的Product.app是一個APP包,其實就是個文件夾,右鍵Show Package Contents或者去掉,app 擴展后雙擊打開就可以查看包內(nèi)容,修改包里面的任何資源文件都不會影響程序正常運行,要提交到App Store的程序在修改資源文件后運行下codesign(安裝Xcode時已經(jīng)裝了這個dev tool)重簽名就可以了:
- $ codesign -fvs "Your Identity" path/to/appfile.app
我之前寫的 ElfCodeSigner 就是基于codesign的。
所以嵌入二進制資源文件也算是一種有效的保護手段。
結合我以前Windows開發(fā)中用到的措施,我想到了三種方案:
Base64編碼。
N久前在CSDN上給一個網(wǎng)友提供的方法,當時他的需求是對一些中英文字符串數(shù)據(jù)的編解碼。我當時給出的Base64方案算是比較簡便而且行之有效的。Base64方法同樣適用于今天要討論的嵌入資源問題。
NSString 和 NSData可以互轉,UIImage也提供了initWithData:的創(chuàng)建方法,所以將image data 進行base64編碼后保存在一個NSString常量中,在用到時進行base64解碼再[UIImage initWithData:]。
此方法在處理很小的數(shù)據(jù)時比較有用,網(wǎng)上也有比較成熟的NSData+Base64類別類供使用。
PNG等資源的壓縮加密
經(jīng)過加密處理的PNG圖像用普通看圖軟件查看時只能看到一片透明或空白圖帶點斑點這樣的無效圖,但在程序運行時圖像顯示正常,這個加密方法在j2me、iOS等游戲和應用開發(fā)被大量使用。網(wǎng)上現(xiàn)成的加密工具很多,但可以被簡單的逆向還原原圖。
轉換成bytes數(shù)組。
大多數(shù)資源嵌入都采用這種方案,原理很簡單,把資源文件的每位字符轉換成十六進制bytes[],幾乎所有語言都提供了bytes[]到data的直接轉換。
大多數(shù)十六進制編輯器可以將hex結果保存為文件。被解密或修改比較困難,需要知道圖形基本格式、熟練UE等十六進制編輯器、猜測、運氣等。
最近公司項目中需要把一些圖片資源嵌入到靜態(tài)庫中,我考慮了下還是用bytes的方法比較好,Cocoa原生支持其不會留下被修改的余地。一些簡單的圖標用CG畫上去。這樣公開出去的庫只有一個.a文件和幾個必要的.h文件。
下午閑著沒事,就操起Xcode在新配的MacBook上寫下了我這第一個跑在Mac OS上的C程序。
Release notes
rtb(Resource To Bytes)是一個命令行小工具,將二進制資源文件轉換為bytes數(shù)組,方便在程序中使用嵌入資源。
由于時間倉促,rtb僅在Mac OS SL上測試過,對應應用在Mac OS桌面程序和iOS App中測試過,以后有時間再改成跨平臺的。目前沒發(fā)現(xiàn)什么bug。
使用方法:打開Terminal,cd到rtb所在目錄,運行
- $ ./rtb image.png
將生成
- unsigned char image_png[] = { ..... };
- unsigned int image_png_len = 16045;
變量名稱根據(jù)資源文件名而來,數(shù)字開頭的會加前綴 "__" ,文件名中非英文和數(shù)字的字符轉換為下劃線"_"(使用了isalnum()測試函數(shù)),在數(shù)組變量名稱添加"_len"后綴作為數(shù)組長度變量名稱。
例如"123te的 st5.png"將生成變量名
- unsigned char __123te____st5_png[] 和 unsigned int __123te____st5_png_len
Example
首先執(zhí)行rtb生成.h文件:
- $ ./rtb test.png > test.png.h
新建一個Window Base的iPhone項目,添加test.png.h文件到項目中,在
- - (BOOL)application: didFinishLaunchingWithOptions:
方法中創(chuàng)建一個UIImage并把它添加到一個ImageView中:
- #import "test.png.h"
- //............
- - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
- {
- [self.window makeKeyAndVisible];
- 8 unsigned char *imgBytes = test_png;
- NSUInteger imgLenght = test_png_len;
- NSData *imgData = [NSData dataWithBytesNoCopy:imgBytes length:imgLenght freeWhenDone:NO];11
- // UIImage *image = [UIImage imageWithData:imgData];
- // or
- UIImage *image = [[UIImage alloc] initWithData:imgData];
- 15 UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
- imageView.frame = self.window.frame;
- imageView.contentMode = UIViewContentModeCenter;
- [self.window addSubview:imageView];
- [imageView release];
- [image release];
- return YES;
- }
因為在程序加載時已經(jīng)將test.png.h中的數(shù)組加載到內(nèi)存中,所以使用NSData的dataWithBytesNoCopy方法即可,不需要再Copy一份,轉換成NSData后也不需要釋放它,所以freeWhenDonw參數(shù)值NO.
Code Review
我C語言很爛,就不貼代碼了。注釋、空行加起來80多行,核心功能代碼就是fopen這個資源文件:
- if ((fp = fopen(argv[1], "r")) != NULL)
- 從文件頭取到(getc(fp))到EOF,fprintf(stdout,"0x%02x",ch):
- for (p = 0; (length < 0 || p < length) && (ch = getc(fp)) != EOF; p++)
- {
- char *c = p ? ",\n " : " ";
- fprintf(fpo, "%s0x%02x", (p % COLS) ? ", " : c, ch);
- }
Download
已收錄至Cocoa-Utilities: https://github.com/Sundae/Cocoa-Utilities
小結:詳解Cocoa資源文件嵌入的內(nèi)容介紹完了,希望通過本文的學習能對你有所幫助!