1
1
using System ;
2
+ using System . Collections . Generic ;
2
3
using ICSharpCode . SharpZipLib . Zip . Compression . Streams ;
3
4
4
5
namespace ICSharpCode . SharpZipLib . Zip . Compression
@@ -7,100 +8,148 @@ class InflaterDynHeader
7
8
{
8
9
#region Constants
9
10
10
- static readonly int [ ] BL_ORDER =
11
- { 16 , 17 , 18 , 0 , 8 , 7 , 9 , 6 , 10 , 5 , 11 , 4 , 12 , 3 , 13 , 2 , 14 , 1 , 15 } ;
11
+ // maximum number of literal/length codes
12
+ const int LITLEN_MAX = 286 ;
13
+
14
+ // maximum number of distance codes
15
+ const int DIST_MAX = 30 ;
16
+
17
+ // maximum data code lengths to read
18
+ const int CODELEN_MAX = LITLEN_MAX + DIST_MAX ;
19
+
20
+ // maximum meta code length codes to read
21
+ const int META_MAX = 19 ;
22
+
23
+ static readonly int [ ] MetaCodeLengthIndex =
24
+ { 16 , 17 , 18 , 0 , 8 , 7 , 9 , 6 , 10 , 5 , 11 , 4 , 12 , 3 , 13 , 2 , 14 , 1 , 15 } ;
25
+
12
26
#endregion
13
27
14
- public bool Decode ( StreamManipulator input )
28
+ /// <summary>
29
+ /// Continue decoding header from <see cref="input"/> until more bits are needed or decoding has been completed
30
+ /// </summary>
31
+ /// <returns>Returns whether decoding could be completed</returns>
32
+ public bool AttemptRead ( )
33
+ => ! state . MoveNext ( ) || state . Current ;
34
+
35
+ public InflaterDynHeader ( StreamManipulator input )
15
36
{
16
- try
37
+ this . input = input ;
38
+ stateMachine = CreateStateMachine ( ) ;
39
+ state = stateMachine . GetEnumerator ( ) ;
40
+ }
41
+
42
+ private IEnumerable < bool > CreateStateMachine ( )
43
+ {
44
+
45
+ // Read initial code length counts from header
46
+ while ( ! input . TryGetBits ( 5 , ref litLenCodeCount , 257 ) ) yield return false ;
47
+ while ( ! input . TryGetBits ( 5 , ref distanceCodeCount , 1 ) ) yield return false ;
48
+ while ( ! input . TryGetBits ( 4 , ref metaCodeCount , 4 ) ) yield return false ;
49
+ var dataCodeCount = litLenCodeCount + distanceCodeCount ;
50
+
51
+ if ( litLenCodeCount > LITLEN_MAX ) throw new ValueOutOfRangeException ( nameof ( litLenCodeCount ) ) ;
52
+ if ( distanceCodeCount > DIST_MAX ) throw new ValueOutOfRangeException ( nameof ( distanceCodeCount ) ) ;
53
+ if ( metaCodeCount > META_MAX ) throw new ValueOutOfRangeException ( nameof ( metaCodeCount ) ) ;
54
+
55
+ // Load code lengths for the meta tree from the header bits
56
+ for ( int i = 0 ; i < metaCodeCount ; i ++ )
57
+ {
58
+ while ( ! input . TryGetBits ( 3 , ref codeLengths , MetaCodeLengthIndex [ i ] ) ) yield return false ;
59
+ }
60
+
61
+ var metaCodeTree = new InflaterHuffmanTree ( codeLengths ) ;
62
+
63
+ // Decompress the meta tree symbols into the data table code lengths
64
+ int index = 0 ;
65
+ while ( index < dataCodeCount )
17
66
{
18
- lnum = input . GrabBits ( 5 ) + 257 ;
19
- dnum = input . GrabBits ( 5 ) + 1 ;
20
- blnum = input . GrabBits ( 4 ) + 4 ;
21
- num = lnum + dnum ;
67
+ byte codeLength ;
68
+ int symbol ;
22
69
23
- lengths = new byte [ 19 ] ;
70
+ while ( ( symbol = metaCodeTree . GetSymbol ( input ) ) < 0 ) yield return false ;
24
71
25
- for ( int i = 0 ; i < blnum ; i ++ )
72
+ if ( symbol < 16 )
26
73
{
27
- lengths [ BL_ORDER [ i ] ] = ( byte ) input . GrabBits ( 3 , true ) ;
74
+ // append literal code length
75
+ codeLengths [ index ++ ] = ( byte ) symbol ;
28
76
}
29
- blTree = new InflaterHuffmanTree ( lengths ) ;
30
- lengths = new byte [ num ] ;
31
-
32
- int index = 0 ;
33
- while ( index < lnum + dnum )
77
+ else
34
78
{
35
- byte len ;
36
-
37
- int symbol = blTree . GetSymbol ( input ) ;
38
- if ( symbol < 0 )
39
- return false ;
40
- if ( symbol < 16 )
41
- lengths [ index ++ ] = ( byte ) symbol ;
42
- else
79
+ int repeatCount = 0 ;
80
+
81
+ if ( symbol == 16 ) // Repeat last code length 3..6 times
82
+ {
83
+
84
+ if ( index == 0 )
85
+ throw new StreamDecodingException ( "Cannot repeat previous code length when no other code length has been read" ) ;
86
+
87
+ codeLength = codeLengths [ index - 1 ] ;
88
+
89
+ // 2 bits + 3, [3..6]
90
+ while ( ! input . TryGetBits ( 2 , ref repeatCount , 3 ) ) yield return false ;
91
+ }
92
+ else if ( symbol == 17 ) // Repeat zero 3..10 times
43
93
{
44
- len = 0 ;
45
- if ( symbol == 16 )
46
- {
47
- if ( index == 0 )
48
- return false ; // No last length!
49
- len = lengths [ index - 1 ] ;
50
- symbol = input . GrabBits ( 2 , true ) + 3 ;
51
- }
52
- else if ( symbol == 17 )
53
- {
54
- // repeat zero 3..10 times
55
- symbol = input . GrabBits ( 3 , true ) + 3 ;
56
- }
57
- else
58
- {
59
- // (symbol == 18), repeat zero 11..138 times
60
- symbol = input . GrabBits ( 7 , true ) + 11 ;
61
- }
62
-
63
- if ( index + symbol > lnum + dnum )
64
- return false ; // too many lengths!
65
-
66
- // repeat last or zero symbol times
67
- while ( symbol -- > 0 )
68
- lengths [ index ++ ] = len ;
94
+ codeLength = 0 ;
95
+
96
+ // 3 bits + 3, [3..10]
97
+ while ( ! input . TryGetBits ( 3 , ref repeatCount , 3 ) ) yield return false ;
69
98
}
70
- }
99
+ else // (symbol == 18), Repeat zero 11..138 times
100
+ {
101
+ codeLength = 0 ;
71
102
72
- if ( lengths [ 256 ] == 0 )
73
- return false ; // No end-of-block code!
103
+ // 7 bits + 11, [11..138]
104
+ while ( ! input . TryGetBits ( 7 , ref repeatCount , 11 ) ) yield return false ;
105
+ }
74
106
75
- return true ;
76
- }
77
- catch ( Exception x )
78
- {
79
- return false ;
107
+ if ( index + repeatCount > dataCodeCount )
108
+ throw new StreamDecodingException ( "Cannot repeat code lengths past total number of data code lengths" ) ;
109
+
110
+ while ( repeatCount -- > 0 )
111
+ codeLengths [ index ++ ] = codeLength ;
112
+ }
80
113
}
81
- }
82
114
83
- public InflaterHuffmanTree BuildLitLenTree ( )
84
- {
85
- byte [ ] litlenLens = new byte [ lnum ] ;
86
- Array . Copy ( lengths , 0 , litlenLens , 0 , lnum ) ;
87
- return new InflaterHuffmanTree ( litlenLens ) ;
88
- }
115
+ if ( codeLengths [ 256 ] == 0 )
116
+ throw new StreamDecodingException ( "Inflater dynamic header end-of-block code missing" ) ;
89
117
90
- public InflaterHuffmanTree BuildDistTree ( )
91
- {
92
- byte [ ] distLens = new byte [ dnum ] ;
93
- Array . Copy ( lengths , lnum , distLens , 0 , dnum ) ;
94
- return new InflaterHuffmanTree ( distLens ) ;
118
+ litLenTree = new InflaterHuffmanTree ( new ArraySegment < byte > ( codeLengths , 0 , litLenCodeCount ) ) ;
119
+ distTree = new InflaterHuffmanTree ( new ArraySegment < byte > ( codeLengths , litLenCodeCount , distanceCodeCount ) ) ;
120
+
121
+ yield return true ;
95
122
}
96
123
124
+ /// <summary>
125
+ /// Get literal/length huffman tree, must not be used before <see cref="AttemptRead"/> has returned true
126
+ /// </summary>
127
+ /// <exception cref="StreamDecodingException">If hader has not been successfully read by the state machine</exception>
128
+ public InflaterHuffmanTree LiteralLengthTree
129
+ => litLenTree ?? throw new StreamDecodingException ( "Header properties were accessed before header had been successfully read" ) ;
130
+
131
+ /// <summary>
132
+ /// Get distance huffman tree, must not be used before <see cref="AttemptRead"/> has returned true
133
+ /// </summary>
134
+ /// <exception cref="StreamDecodingException">If hader has not been successfully read by the state machine</exception>
135
+ public InflaterHuffmanTree DistanceTree
136
+ => distTree ?? throw new StreamDecodingException ( "Header properties were accessed before header had been successfully read" ) ;
137
+
97
138
#region Instance Fields
98
- byte [ ] lengths ;
99
139
100
- InflaterHuffmanTree blTree ;
140
+ private readonly StreamManipulator input ;
141
+ private readonly IEnumerator < bool > state ;
142
+ private readonly IEnumerable < bool > stateMachine ;
143
+
144
+ private byte [ ] codeLengths = new byte [ CODELEN_MAX ] ;
145
+
146
+ private InflaterHuffmanTree litLenTree ;
147
+ private InflaterHuffmanTree distTree ;
148
+
149
+ int litLenCodeCount , distanceCodeCount , metaCodeCount ;
101
150
102
- int lnum , dnum , blnum , num ;
103
151
#endregion
104
152
105
153
}
154
+
106
155
}
0 commit comments