有了檔案的格式,就可以按圖索驥,也就是根據檔案的格式來分析壓縮資料了。但檔案格式只是一種儲存的格式,還需要演算法才可以把資料解壓出來,下面就來理解gzip的壓縮演算法。gzip使用deflate的壓縮演算法來進行壓縮資料,這是一種無損的壓縮演算法,主要組合lz77和huffman的壓縮演算法。
lz77演算法是基於這樣的思路:當一串字元中,如果後面的字串已經在前面出現,那麼後面的字串只需要使用前面的位置和長度就表達相同的字串,從而達到字串使用最少的空間。現在看乙個簡單的例子,如下的字串:
aababbbabaababbbabbabb
在這個串中可以這樣表示,第乙個塊a寫作(0,a),第二個塊ab,就可以表達為索引和字母的方式(1,b),依這樣的編碼,就可以得到下面的**:
索引 塊 壓縮後表示
1 a (0,a)
2 ab (1,b)
3 abb (2,b)
4 b (0,b)
5 aba (2,a)
6 abab (5,b)
7 bb (4,b)
8 abba (3,a)
9 bb (7,0)
通過這樣壓縮處理後,就可以減少原來字串的大小,並且沒有資料損失。
huffman演算法是基於這樣的思路:當一串字元中,如果某個字元出現的頻率越高就使用最短的編碼記號,頻率越低的就使用最長的編碼記號,經過這樣編碼後達到壓縮的目的。可見huffman演算法是基於統計學來壓縮的,因此存在碼表和統計的過程。不過,huffman演算法也可以採用比較常見的預先定製靜態碼表來使用,這樣就不需要統計的過程了,這種演算法叫做靜態huffman演算法,反之叫做動態huffman演算法。
有了上面的基礎,就可以來學習gunzip
函式的**了,這個函式的**如下:
/**do the uncompression!
*/staticint init gunzip(void)
這段**是判斷是否gzip格式。
/* we only support method #8,deflated */
if (method != 8)
這段**是判斷是否為deflated壓縮方式。
flags = (uch)get_byte();
if ((flags & encrypted) != 0)
if ((flags & continuation) != 0)
if ((flags & reserved) != 0)
這段**是判斷是否使用特殊的標誌壓縮,如果有用就不能執行,因為這裡解壓**比較簡單。
nextbyte(); /* get timestamp */
nextbyte();
nextbyte();
nextbyte();
這段**跳過四個壓縮資料時的時間。
(void)nextbyte(); /* ignore extraflags for the moment */
(void)nextbyte(); /* ignore os typefor the moment */
這段**是跳過額外的標誌和作業系統型別。
if ((flags & extra_field) != 0)
這段**把所有額外欄位跳過,不作任何處理。
/* get original file name if it wastruncated */
if ((flags & orig_name) != 0)
這段**跳過原來壓縮檔案的名稱。
/* discard file comment if any */
if ((flags & comment) != 0)
這段**是跳過所有注釋的字元。
/* decompress */
if ((res = inflate()))
return -1;
}這段**是呼叫inflate來進行資料解壓。
/* get the crc and original length */
/* crc32 (see algorithm.doc)
* uncompressed input size modulo 2^32
*/ orig_crc = (ulg) nextbyte();
orig_crc |= (ulg) nextbyte() <<8;
orig_crc |= (ulg) nextbyte() <<16;
orig_crc |= (ulg) nextbyte() <<24;
這段**是獲取原來的crc32檢驗碼,以便跟解壓出來的資料計算的crc32檢驗碼比較。
orig_len = (ulg) nextbyte();
orig_len |= (ulg) nextbyte() <<8;
orig_len |= (ulg) nextbyte() <<16;
orig_len |= (ulg) nextbyte() <<24;
這段**是獲取壓縮之前資料長度。
/* validate decompression */
if (orig_crc != crc_value)
if (orig_len != bytes_out)
這段**是檢查crc32是否對,解壓後長度與壓縮前的長度是否一致。
return 0;
underrun: /* nextbyte() goto's hereif needed */
error("out of input data");
return -1;
}
Android培訓班 95 核心解壓過程8
核心在上面處理完關閉中斷,並且確認進入系統模式後,就需要解決第乙個問題 解決自己到底在那裡執行的問題。這個問題,就好比乙個人在大海浬航行而沒有指南針,根本找不到北在那裡,急切地想知道方向在那裡。如果在白天還可以靠大陽就知道了方向,在晚上可以靠北斗星,在核心裡是否也有這樣的大自然的指示呢?在核心裡沒有...
Android培訓班 96 核心解壓過程9
前面已經把定位的資料通重載入 lc0結構來載入到暫存器裡,已經具備了定位的條件。那麼核心進行重定位主要做些什麼事情呢?要了解整個過程,當然要學習編譯原理,因為進行重定位之後,主要是為了建立 c語言的執行環境的需求。由於 c語言是基於棧式的語言,又有全域性變數,說明記憶體結構至少有兩個,乙個是全域性資...
Android培訓班 97 核心解壓過程10
經過上面開啟 mmu 之後,就進入了另乙個主要環節,就是把壓縮的核心 解壓出來,變換回原來可執行 的模樣,這樣才可以讓 cpu理解並執行相應的指令。由於載入壓縮的核心就占用了一定的記憶體空間,如果這個壓縮的核心比較大,而物理記憶體比較小,那麼解壓後的核心就會把未解壓部份的核心資料覆蓋,否則就可以採用...