diff --git a/docs/unrar.html b/docs/unrar.html new file mode 100755 index 0000000..11dc7f6 --- /dev/null +++ b/docs/unrar.html @@ -0,0 +1,558 @@ + + + + Documentation of the RAR format + + + +
+

The RAR Format

+
+ +
+
+

1 Introduction

+
+ +

This document, a work-in-progress, describes the RAR format. It serves a similar role that the ZIP App Note does for the ZIP format.

+ +

NOTE 1: This documentation MUST NOT be used to create RAR-compatible archive programs like WinRAR. It is only for the purposes of writing decompression software (i.e. unrar) in various languages. It was reverse-engineered from the UnRAR source located at this page with Eugene Roshal's permission.

+ +

NOTE 2: This documentation will initially focus on what I believe is Version 3 of the RAR format.

+ +
+
+

1.1 License

+
+ +

The author of this document is Jeff Schiller <codedread@gmail.com>. It is licensed under the CC-BY-3.0 License.

+ +
+ +
+ +
+
+

2 General Format of a .RAR File

+
+ +

Overall .RAR file format:

+ +
+signature               7 bytes    (0x52 0x61 0x72 0x21 0x1A 0x07 0x00)
+[1st volume header]
+...
+[2nd volume header]
+...
+...
+[nth volume header]
+...
+
+ +

In general, a modern single-volume RAR file has a MAIN_HEAD structure followed by multiple FILE_HEAD structures.

+ +
+

2.1 Volume Header Format

+
+ +

The Base Header Block is:

+ +
+header_crc              2 bytes
+header_type             1 byte
+header_flags            2 bytes
+header_size             2 bytes
+
+ +

The header_size indicates how many total bytes the header requires. The header_type field determines how the remaining bytes should be interpreted.

+ +
+

2.1.1 Header Type

+
+ +

The header type is 8 bits (1 byte) and can have the following values:

+ + + + + + + + + + + + + +
ValueType
0x72MARK_HEAD
0x73MAIN_HEAD
0x74FILE_HEAD
0x75COMM_HEAD
0x76AV_HEAD
0x77SUB_HEAD
0x78PROTECT_HEAD
0x79SIGN_HEAD
0x7aNEWSUB_HEAD
0x7bENDARC_HEAD
+ +
+
2.1.1.1 MARK_HEAD
+
+ +

TBD

+ +
+
2.1.1.2 MAIN_HEAD
+
+ +

The remaining bytes in the volume header for MAIN_HEAD are:

+ +
+HighPosAv               2 bytes
+PosAV                   4 bytes
+EncryptVer              1 byte (only present if MHD_ENCRYPTVER is set) 
+
+ +
+
2.1.1.3 FILE_HEAD
+
+ +

The remaining bytes in the FILE_HEAD structure are:

+ +
+PackSize                4 bytes
+UnpSize                 4 bytes
+HostOS                  1 byte
+FileCRC                 4 bytes
+FileTime                4 bytes
+UnpVer                  1 byte
+Method                  1 byte
+NameSize                2 bytes
+FileAttr                4 bytes
+HighPackSize            4 bytes (only present if LHD_LARGE is set)
+HighUnpSize             4 bytes (only present if LHD_LARGE is set)
+FileName                (NameSize) bytes
+Salt                    8 bytes (only present if LHD_SALT is set)
+ExtTime Structure       See Description (only present if LHD_EXTTIME is set)
+Packed Data             (Total Packed Size) bytes
+
+ +

If the LHD_LARGE flag is set, then the archive is large and 64-bits are needed to represent the packed and unpacked size. HighPackSize is used as the upper 32-bits and PackSize is used as the lower 32-bits for the packed size in bytes. HighUnpSize is used as the upper 32-bits and UnpSize is used as the lower 32-bits for the unpacked size in bytes.

+ +
+
ExtTime Structure
+
+ +

Follow the following pseudo-code to read in the ExtTime Structure.

+

TODO: Fill in details of what this structure represents.

+ +
+var extTimeFlags = readBits(16)
+
+mtime:
+mtime_rmode = extTimeFlags >> 12
+if ((mtime_rmode & 8)==0) goto ctime
+mtime_count = mtime_rmode & 0x3
+mtime_reminder = readBits(8*mtime_count);
+
+ctime:
+ctime_rmode = extTimeFlags >> 8
+if ((ctime_rmode & 8)==0) goto atime
+Set ctime to readBits(16)
+ctime_count = ctime_rmode & 0x3
+ctime_reminder = readBits(8*ctime_count)
+
+atime:
+atime_rmode = extTimeFlags >> 4
+if ((atime_rmode & 8)==0) goto arctime
+Set atime to readBits(16)
+atime_count = atime_rmode & 0x3
+atime_reminder = readBits(8*atime_count)
+
+arctime:
+arctime_rmode = extTimeFlags
+if ((arctime_rmode & 8)==0) goto done_exttime
+Set arctime to readBits(16)
+arctime_count = arctime_rmode & 0x3
+arctime_reminder = readBits(8*arctime_count)
+
+done_exttime
+
+ + +
+
2.1.1.4 COMM_HEAD
+
+ +

TBD

+ +
+
2.1.1.5 AV_HEAD
+
+ +

TBD

+ +
+
2.1.1.6 SUB_HEAD
+
+ +

TBD

+ +
+
2.1.1.7 PROTECT_HEAD
+
+ +

TBD

+ +
+
2.1.1.8 SIGN_HEAD
+
+ +

TBD

+ +
+
2.1.1.9 NEWSUB_HEAD
+
+ +

TBD

+ +
+
2.1.1.10 ENDARC_HEAD
+
+ +

TBD

+ +
+

2.1.2 Header Flags

+
+ +

The header flags are 16 bits (2 bytes). Depending on the type of Volume Header, the flags are interpreted differently.

+ +

The Main Header Flags are:

+ + + + + + + + + + + + + +
ValueFlag
0x0001MHD_VOLUME
0x0002MHD_COMMENT
0x0004MHD_LOCK
0x0008MHD_SOLID
0x0010MHD_PACK_COMMENT or MHD_NEWNUMBERING
0x0020MHD_AV
0x0040MHD_PROTECT
0x0080MHD_PASSWORD
0x0100MHD_FIRSTVOLUME
0x0200MHD_ENCRYPTVER
+ +

The File Header Flags are:

+ + + + + + + + + + + + + + +
ValueFlag
0x0001LHD_SPLIT_BEFORE
0x0002LHD_SPLIT_AFTER
0x0004LHD_PASSWORD
0x0008LHD_COMMENT
0x0010LHD_SOLID
0x0100LHD_LARGE
0x0200LHD_UNICODE
0x0400LHD_SALT
0x0800LHD_VERSION
0x1000LHD_EXTTIME
0x2000LHD_EXTFLAGS
+ +
+
2.1.2.1 MHD_VOLUME
+
+ +

Value 0x0001. TBD

+ +
+
2.1.2.2 MHD_COMMENT
+
+ +

Value 0x0002. TBD

+ +
+
2.1.2.3 MHD_LOCK
+
+ +

Value 0x0004. TBD

+ +
+
2.1.2.4 MHD_SOLID
+
+ +

Value 0x0008. TBD

+ +
+
2.1.2.5 MHD_PACK_COMMENT
+
+ +

Value 0x0010. TBD

+ +
+
2.1.2.6 MHD_AV
+
+ +

Value 0x0020. TBD

+ +
+
2.1.2.7 MHD_PROTECT
+
+ +

Value 0x0040. TBD

+ +
+
2.1.2.8 MHD_PASSWORD
+
+ +

Value 0x0080. TBD

+ +
+
2.1.2.9 MHD_FIRSTVOLUME
+
+ +

Value 0x0100. TBD

+ +
+
2.1.2.10 MHD_ENCRYPTVER
+
+ +

Value 0x0200. Indicates whether encryption is present in the archive volume.

+ +
+
2.1.2.11 LHD_SPLIT_BEFORE
+
+ +

Value 0x0001. TBD

+ +
+
2.1.2.12 LHD_SPLIT_AFTER
+
+ +

Value 0x0002. TBD

+ +
+
2.1.2.13 LHD_PASSWORD
+
+ +

Value 0x0004. TBD

+ +
+
2.1.2.14 LHD_COMMENT
+
+ +

Value 0x0008. TBD

+ +
+
2.1.2.15 LHD_SOLID
+
+ +

Value 0x0010. TBD

+ +
+
2.1.2.16 LHD_LARGE
+
+ +

Value 0x0100. Indicates if the archive is large. In this case, 64 bits are used to describe the packed and unpacked size.

+ +
+
2.1.2.17 LHD_UNICODE
+
+ +

Value 0x0200. Indicates if the filename is Unicode.

+ +
+
2.1.2.18 LHD_SALT
+
+ +

Value 0x0400. Indicates if the 64-bit salt value is present.

+ +
+
2.1.2.19 LHD_VERSION
+
+ +

Value 0x0800. TBD

+ +
+
2.1.2.20 LHD_EXTTIME
+
+ +

Value 0x1000. The ExtTime Structure is present in the FILE_HEAD header.

+ +
+
2.1.2.21 LHD_EXTFLAGS
+
+ +

Value 0x2000. TBD

+
+ +
+
+

3 Unpacking

+
+ +

Once the header information and packed bytes have been extracted, the packed bytes must then be unpacked. RAR uses a variety of algorithms for this. Chief among these are Lempel-Ziv compression and Prediction by Partial Matching. The details of the unpacking are specified in the following subsections based on the values of UnpVer and Method as decoded in the FILE_HEAD structure.

+ +

If Method is 0x30 (decimal 48), then the packed bytes are the unpacked bytes and no decompression/unpacking is necessary (i.e. the file was not compressed).

+ +

Otherwise:

+ + + + + + + +
UnpVer Value (decimal)Algorithm To Use
15Unpack15
20Unpack20
26
29Unpack29
36
+ +
+

3.1 Unpack15

+
+ +

TBD

+ +
+

3.2 Unpack20

+
+ +

TBD

+ +
+

3.3 Unpack29

+
+ +

The structure of packed data consists of N number of blocks. If the first bit of a block is set, then process the block as a PPM block. Otherwise, this is an LZ block.

+ +
+

3.3.1 LZ Block

+
+ +

The format of a LZ block is:

+ +
+isPPM                   1 bit
+keepOldTable            1 bit
+huffmanCodeTable        (variable size)
+
+ +
+
3.3.1.1 Huffman Code Tables
+
+ +

The Huffman Encoding tables consist a series of bit lengths. For a more thorough treatment of the concepts of Huffman Encoding, see the Deflate spec. The RAR format uses a set of twenty bit lengths to construct Huffman Codes. The Huffman Encoding tables in RAR files consist of at most twenty entries of the format:

+ +
+BitLength               4 bits
+ZeroCount               4 bits (only present if BitLength is 15)
+
+ +

If BitLength is 15, then the next 4 bits are read as ZeroCount. If the ZeroCount is 0, then the bit length is 15, otherwise (ZeroCount+2) is the number of consecutive zero bit lengths that are in the table. For instance, if the following 4-bit numbers are present:

+ + + + + + + + + + + + + + +
0x8indicates a bit-length of 8
0x4indicates a bit-length of 4
0x4indicates a bit-length of 4
0x2indicates a bit-length of 2
0xFthese two 4-bit numbers specify a bit-length of 15
0x0
0xFthese two 4-bit numbers specify a run of 5 zeros
0x3
0x9indicates a bit-length of 9
0x3indicates a bit-length of 3
0xFthese two 4-bit numbers specify a run of 8 zeros
0x6
+ +

This example describes a Huffman Encoding Bit Length table of:

+ + + + + + + + + + + + + +
CodeBit LengthCodeBitLength
18119
24123
34130
42140
515150
60160
70170
80180
90190
100200
+ +

Once the twenty bit lengths are obtained, the Huffman Encoding table is constructed by using the following algorithm:

+ +
+1) Count the number of codes for each code length.  Let
+   LenCount[N] be the number of codes of length N, where N = {1..16}.
+             
+2) Find the decode length and positions:
+
+        N = 0
+        TmpPos[0] = 0
+        DecodePos[0] = 0
+        DecodeLen[0] = 0
+        for (I = 1; I < 16; I++) 
+        {
+            N = 2 * (N+LenCount[I])
+            M = N << (15-I)
+            if (M > 0xFFFF) M = 0xFFFF
+            
+            DecodeLen[I] = (unsigned int)M
+            TmpPos[I] = DecodePos[I] = DecodePos[I-1] + LenCount[I-1]
+        }
+
+3) Assign numerical values to all codes:
+
+        for (I = 0; I < TableSize; I++)
+        {
+            if (BitLength[I] != 0)
+                DecodeNum[ TmpPos[BitLength[I] & 0xF]++ ] = I
+        }
+
+
+
+ +
+
+

Appendix A. Credits

+
+ + +
+ + + \ No newline at end of file