我曾在某論壇裡,為解釋檔案讀寫時, binary mode 與 txt mode 之差異,

所以寫了份 demo code 與簡要說明。

但由於該論壇必須註冊才可看到內容,後續在他處遇到有類似問題的人,

反而讓我感到不便,我不願因要回答一個問題答,便要求別人註冊一個論壇帳號,

於是將論壇該文重整過來,放上。若有該論壇之帳號,

倒是可直接先看原文與相關討論串。

 

[問題] 如何讀內存 16 進制的整數檔

[分享] Ultra-Edit / PSPad 部份實做

 

以下之敘述與原文有些出入,但模式大致相同,只加強了一點 binary mode 之說明;

程式碼只小修一點地方,從 .cpp 改成 .c (變 C compiler,不用 C++ compiler)。

 


 

text mode 和 binary mode 差異我就不說了,直接用案例來說明。假設我有一個 data.txt 文字檔,用記事本 (notepad.exe) 開啟,內容大致如下所示看到的東西如下

 

u_000.png

 

接著我們用專門看 binary code 的軟體 - Ultra Edit / PSPad (free)去看 data.txt,一開始並沒太大變化,只是環境變了而已。

 

u_001.png

 

接下來是重點, PSPad 中,在 Menu 那裡按「檢視」-> HEX 編輯模式;

若為 UltraEditor,可直接按快捷鍵 Ctrl + H 做為切換。

 

u_002.png

 

接下來看到的便是一堆莫名的數字。左半部代表的是該文字檔裡所儲存的 16 進位碼

右半段所顯示的為該文字檔被 PSPad 「 "畫" 」出來的文字,

別忘了,電腦裡面其實只有存 0/1 而已,至於「顯示」、「畫」出來的,

全部都是經過轉換而已,像 PSPad / Notepad.exe ,甚至一般寫的 console 程式,

也都是根據字元編碼 (最常見是 ASCII / ANSI) 方式,把那個「字」畫出來。

 

u_003.png

 

注意到上面反白處,一開始的 "5468",去查 ASCII Table

0x54 代表的是 'T' / 0x68 代表 'h'; 

(如果您從 ASCII Table 查到 'T" 是 84,代表你看到的是 10 進位,不是 16 進位)。

 

但一些本身就用 binary mode 寫進去的檔案,舉例而言,像是 mp3,

這時硬要用 notepad.exe ,以文本模式開啟本身就是一堆亂碼,

原因是裡面所存的數字,沒辦法被正確翻譯成某些文字,也就沒辦法被正確畫出,

而用 PSPad/UltraEditor 開啟時,便長得像這樣

 

u_012.png

 

這次裡面的數字是「完全看不懂」的,只有一開始的 0x49 0x44 0x33 去找

ASCII 有意義,代表 ID3(因 mp3 前面這 3 bytes 就固定是 ID3),

其它的 hex value,沒去翻過 mp3 format ,就看看就算吧。

 

再多看一例,rar 壓縮後再以 pspad 開啟,發現前面 3  bytes 固定為

0x52 0x61 0x72,固定為 rar,其他的都是亂碼,要去查 rar format 才知道意義。

u_013.png  

 

鑑於這種現象,於是寫了一份 C code,欲仿 pspad / Ultra 去觀查

binary - txt mode 之文字與編碼,程式碼如下。

 

/*******************************************************************/
/*                                                                 */
/*     filename : Ultra.c                                          */
/*     author   : edison.shih/edisonx                              */
/*     compiler : Visual C++ 2008                                  */
/*     date     : 2009.03.07                                       */
/*                                                                 */
/*******************************************************************/

#include <stdio.h>
#include <conio.h>

// filesize must < 2GB
unsigned long GetFileLength(const char* filename)
{
     unsigned long len = 0;
     FILE *fp=fopen(filename, "rb");
     if(fp==NULL){
           printf("error!!\n");
           return 0;
     }   
     fseek ( fp, 0L, SEEK_END );
     len = ftell (fp);
     fclose(fp);
     return len;
}

void ShowBinary(const char* filename)
{
     unsigned long i, j;
     unsigned file_size;
     unsigned char buffer[17]={0};
     unsigned char ch;
     unsigned long counter=0;
     FILE *fp=fopen(filename, "rb");
     if(fp==NULL){
           printf("error!!\n");
           return;
     }

     // start show
     file_size = GetFileLength(filename);

     // title
     printf("%8s|", " ");
     for(i=0x00; i<=0x0F; i++) printf("%02X ", i);
     printf("|");
     for(i=0x00; i<=0x0F; i++) printf("%1X", i);
     printf("\n");

     // --- sp ---
     for(i=0; i<8; i++) putchar('-');
     putchar('|');
     for(i=0x00; i<=0x0f; i++) printf("---");
     putchar('|');
     for(i=0x00; i<=0x0f; i++) putchar('-');

     // ---- show the context
     for(i=0; i<file_size; i++){
           if(i%0x10==0) printf("\n%08X|",i);
           ch = (unsigned char)fgetc(fp), printf("%02X ", ch);

           //
將可能換行、tab 之文字用. 去取代
           if(ch=='\r' || ch=='\n' || ch=='\t') buffer[i%0x10] = '.';
           else buffer[i%0x10] = ch;

           if(i%0x10==0x0f) {
                printf("|%s", buffer);
                getch(); //
加上去為16筆筆慢慢看, 隨便按一鍵繼續
           }
     }

     printf("\n");
     printf("%s filelength:%lu", filename, file_size);
     // end show
     fclose(fp);
}

int main()
{
     ShowBinary("data.txt");
     return 0;
}

 

在執行時,一開始「可能」會顯示不正常,長這樣

u_004.png

 

 

那是因為 console 沒調好,在抬頭處按一下右鍵,選「內容」

 

u_005.png

 

切到版面設定,螢幕緩衝區大小寬度設80,視窗大小寬度也設 80。


 

u_006.png

 

上面前二個數值,螢幕緩衝區大小設定為 80,30。代表寬可以輸入 80 個字元,而整個 Console 可以有 30 行的暫存;

視窗大小即為一個 Console 畫面,寬度一次可看 80 個字元,高度一次可看 25 個字元。

若螢幕緩衝區大小大於視窗大小的時候,便產生了,一次不能看到所有的字元,故會產生捲軸出來,

這在遊戲設計的時候必須避免,也可以實際自己調過觀查後再做設定,好了之後按確定。

 

出現對話框,按「儲存內容,讓相同的標題視窗使用」。

 

u_007.png

 

妙的是,回到 console 裡雖然視窗寬度有變寬,還是一樣顯示不正常。

 

u_008.png

 

關掉它,重新再執行一次執行檔,這次正常多了。

 

u_009.png

 

由於在碼程式裡有加非標準函式 getch,所以每次讀 16 bytes ,都會停一下,

等待按任意鍵 (當初設計是方便觀查),多按幾次後執行結果如下。

 

u_010.png            

 

console 版,簡單 PSPad / UltraEditor 功能已完成。

 

筆者自白,雖然標題很聳動,其實實作不到裡面的 1% 功能,

但希望藉由這種模式,

一方面能釐清 txt / binary 之讀寫模式,一方面也希望引起一些興趣。

 

這份 code 只到這裡,沒繼續開發下去原因在於,

UltraEditor / PSPad 類似軟體較適合以視窗方式開發,

且真正麻煩地方在於 語法分析、高亮、筆對、使用者自定義巨集 等,

要做得好,一個人必須花不少時間。

arrow
arrow
    全站熱搜

    edisonx 發表在 痞客邦 留言(0) 人氣()