@@ -43,7 +43,6 @@ public const long
4343 SIG_LZDIFF41 = 0x3134464649445a4c ,
4444 SIG_NONONONO = 0x4f4e4f4e4f4e4f4e ;
4545 public const int HEADER_SIZE = 32 ;
46- public const int BUFFER_SIZE = 1024 * 1024 * 8 ; //8MiB
4746
4847 private const int LZMA_DICTSIZE_ULTRA = 1024 * 1024 * 64 ; //64MiB, 7z 'Ultra'
4948
@@ -87,32 +86,28 @@ public static Stream GetEncodingStream(Stream stream, long signature, bool outpu
8786 /// the patch to be opened concurrently.</param>
8887 /// <param name="output">A <see cref="Stream"/> to which the patched data is written.</param>
8988 public static unsafe void Apply ( byte * pInput , long length , byte * pPatch , long patchLength , Stream output )
89+ {
90+ Stream controlStream , diffStream , extraStream ;
91+ var newSize = CreatePatchStreams ( pPatch , patchLength , out controlStream , out diffStream , out extraStream ) ;
92+
93+ // prepare to read three parts of the patch in parallel
94+ ApplyInternal ( newSize , new UnmanagedMemoryStream ( pInput , length ) , controlStream , diffStream , extraStream , output ) ;
95+ }
96+
97+ public static unsafe void Apply ( Stream input , byte * pPatch , long patchLength , Stream output )
98+ {
99+ Stream controlStream , diffStream , extraStream ;
100+ var newSize = CreatePatchStreams ( pPatch , patchLength , out controlStream , out diffStream , out extraStream ) ;
101+
102+ // prepare to read three parts of the patch in parallel
103+ ApplyInternal ( newSize , input , controlStream , diffStream , extraStream , output ) ;
104+ }
105+
106+ static unsafe long CreatePatchStreams ( byte * pPatch , long patchLength , out Stream ctrl , out Stream diff , out Stream extra )
90107 {
91108 Func < long , long , Stream > openPatchStream = ( u_offset , u_length ) =>
92109 new UnmanagedMemoryStream ( pPatch + u_offset , u_length > 0 ? u_length : patchLength - u_offset ) ;
93110
94- // check arguments
95- if ( pInput == null )
96- throw new ArgumentNullException ( "input" ) ;
97- if ( openPatchStream == null )
98- throw new ArgumentNullException ( "openPatchStream" ) ;
99- if ( output == null )
100- throw new ArgumentNullException ( "output" ) ;
101-
102- /*
103- File format:
104- 0 8 "BSDIFF40"
105- 8 8 X
106- 16 8 Y
107- 24 8 sizeof(newfile)
108- 32 X bzip2(control block)
109- 32+X Y bzip2(diff block)
110- 32+X+Y ??? bzip2(extra block)
111- with control block a set of triples (x,y,z) meaning "add x bytes
112- from oldfile to x bytes from the diff block; copy y bytes from the
113- extra block; seek forwards in oldfile by z bytes".
114- */
115-
116111 // read header
117112 long controlLength , diffLength , newSize , signature ;
118113 using ( Stream patchStream = openPatchStream ( 0 , HEADER_SIZE ) )
@@ -141,82 +136,71 @@ with control block a set of triples (x,y,z) meaning "add x bytes
141136 throw new InvalidOperationException ( "Corrupt patch." ) ;
142137 }
143138
144- // preallocate buffers for reading and writing
145- var newData = new byte [ BUFFER_SIZE ] ;
146-
147139 // prepare to read three parts of the patch in parallel
148- using ( Stream
140+ Stream
149141 compressedControlStream = openPatchStream ( HEADER_SIZE , controlLength ) ,
150142 compressedDiffStream = openPatchStream ( HEADER_SIZE + controlLength , diffLength ) ,
151- compressedExtraStream = openPatchStream ( HEADER_SIZE + controlLength + diffLength , - 1 ) ,
143+ compressedExtraStream = openPatchStream ( HEADER_SIZE + controlLength + diffLength , - 1 ) ;
144+
145+ // decompress each part (to read it)
146+ ctrl = GetEncodingStream ( compressedControlStream , signature , false ) ;
147+ diff = GetEncodingStream ( compressedDiffStream , signature , false ) ;
148+ extra = GetEncodingStream ( compressedExtraStream , signature , false ) ;
149+
150+ return newSize ;
151+ }
152+
153+ static void ApplyInternal ( long newSize , Stream input , Stream ctrl , Stream diff , Stream extra , Stream output )
154+ {
155+ long addSize , copySize , seekAmount ;
156+
157+ using ( ctrl )
158+ using ( diff )
159+ using ( extra )
160+ using ( BinaryReader
161+ diffReader = new BinaryReader ( diff ) ,
162+ extraReader = new BinaryReader ( extra ) )
163+ while ( output . Position < newSize )
164+ {
165+ //read control data
166+ //set of triples (x,y,z) meaning
167+ // add x bytes from oldfile to x bytes from the diff block;
168+ // copy y bytes from the extra block;
169+ // seek forwards in oldfile by z bytes;
170+ addSize = ReadInt64 ( ctrl ) ;
171+ copySize = ReadInt64 ( ctrl ) ;
172+ seekAmount = ReadInt64 ( ctrl ) ;
173+
174+ // sanity-check
175+ if ( output . Position + addSize > newSize )
176+ throw new InvalidOperationException ( "Corrupt patch." ) ;
152177
153- // decompress each part (to read it)
154- controlStream = GetEncodingStream ( compressedControlStream , signature , false ) ,
155- diffStream = GetEncodingStream ( compressedDiffStream , signature , false ) ,
156- extraStream = GetEncodingStream ( compressedExtraStream , signature , false ) )
157- {
158- long [ ] control = new long [ 3 ] ;
159- byte [ ] buffer = new byte [ 8 ] ;
160-
161- int oldPosition = 0 ;
162- int newPosition = 0 ;
163- fixed ( byte * pNew = newData )
164- fixed ( byte * pBuf = buffer )
165- while ( newPosition < newSize )
166178 {
167- // read control data
168- for ( int i = 0 ; i < 3 ; i ++ )
169- {
170- controlStream . Read ( buffer , 0 , 8 ) ;
171- control [ i ] = ReadInt64 ( pBuf ) ;
172- }
173-
174- // sanity-check
175- if ( newPosition + control [ 0 ] > newSize )
176- throw new InvalidOperationException ( "Corrupt patch." ) ;
177-
178- int bytesToCopy = ( int ) control [ 0 ] ;
179- while ( bytesToCopy > 0 )
180- {
181- int actualBytesToCopy = Math . Min ( bytesToCopy , BUFFER_SIZE ) ;
182-
183- // read diff string
184- diffStream . Read ( newData , 0 , actualBytesToCopy ) ;
185-
186- // add old data to diff string
187- int availableInputBytes = Math . Min ( actualBytesToCopy , ( int ) ( length - oldPosition ) ) ;
188- for ( int i = 0 ; i < availableInputBytes ; i ++ )
189- pNew [ i ] += pInput [ oldPosition + i ] ;
190-
191- output . Write ( newData , 0 , actualBytesToCopy ) ;
192-
193- // adjust counters
194- newPosition += actualBytesToCopy ;
195- oldPosition += actualBytesToCopy ;
196- bytesToCopy -= actualBytesToCopy ;
197- }
198-
199- // sanity-check
200- if ( newPosition + control [ 1 ] > newSize )
201- throw new InvalidOperationException ( "Corrupt patch." ) ;
202-
203- // read extra string
204- bytesToCopy = ( int ) control [ 1 ] ;
205- while ( bytesToCopy > 0 )
206- {
207- int actualBytesToCopy = Math . Min ( bytesToCopy , BUFFER_SIZE ) ;
208-
209- extraStream . Read ( newData , 0 , actualBytesToCopy ) ;
210- output . Write ( newData , 0 , actualBytesToCopy ) ;
211-
212- newPosition += actualBytesToCopy ;
213- bytesToCopy -= actualBytesToCopy ;
214- }
215-
216- // adjust position
217- oldPosition = ( int ) ( oldPosition + control [ 2 ] ) ;
179+ // read diff string
180+ var newData = diffReader . ReadBytes ( ( int ) addSize ) ;
181+
182+ // add old data to diff string
183+ var availableInputBytes = ( int ) Math . Min ( addSize , input . Length - input . Position ) ;
184+ for ( int i = 0 ; i < availableInputBytes ; i ++ )
185+ newData [ i ] += ( byte ) input . ReadByte ( ) ;
186+
187+ output . Write ( newData , 0 , ( int ) addSize ) ;
188+ //input.Seek(addSize, SeekOrigin.Current);
218189 }
219- }
190+
191+ // sanity-check
192+ if ( output . Position + copySize > newSize )
193+ throw new InvalidOperationException ( "Corrupt patch." ) ;
194+
195+ // read extra string
196+ {
197+ var newData = extraReader . ReadBytes ( ( int ) copySize ) ;
198+ output . Write ( newData , 0 , ( int ) copySize ) ;
199+ }
200+
201+ // adjust position
202+ input . Seek ( seekAmount , SeekOrigin . Current ) ;
203+ }
220204 }
221205
222206 public static unsafe long ReadInt64 ( byte * pb )
@@ -232,5 +216,18 @@ public static unsafe long ReadInt64(byte* pb)
232216
233217 return ( pb [ 7 ] & 0x80 ) != 0 ? - y : y ;
234218 }
219+
220+ public static long ReadInt64 ( Stream ps )
221+ {
222+ var buf = new byte [ sizeof ( long ) ] ;
223+ if ( ps . Read ( buf , 0 , sizeof ( long ) ) != sizeof ( long ) )
224+ throw new InvalidOperationException ( "Could not read long from stream" ) ;
225+
226+ unsafe
227+ {
228+ fixed ( byte * pb = buf )
229+ return ReadInt64 ( pb ) ;
230+ }
231+ }
235232 }
236233}
0 commit comments