1 /******************************************************************************
2 *
3 * Copyright (C) 2009, The Gentee Group. All rights reserved.
4 * This file is part of the Gentee open source project - http://www.gentee.com.
5 *
6 * THIS FILE IS PROVIDED UNDER THE TERMS OF THE GENTEE LICENSE ("AGREEMENT").
7 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS FILE CONSTITUTES RECIPIENTS
8 * ACCEPTANCE OF THE AGREEMENT.
9 *
10 * Author: Alexey Krivonogov ( gentee )
11 *
12 ******************************************************************************/
13
14 method str gead.getdiskname( uint num, str result )
15 {
16 str stemp
17
18 if !num : return result = this.filename
19
20 // int2str( stemp, this.pattern, num )
21 stemp.out4( this.pattern, num )
22
23 return ( result = this.lastpath ).faddname( stemp )
24 }
25
26 //--------------------------------------------------------------------------
27
28 method uint gead.opendisk( uint num )
29 {
30 str diskname dir
31 buf head
32
33 if this.curdisk == num : return 1
34
35 close( this.handle )
36
37 getcurdir( dir )
38 // Существует ли файл
39 while 1
40 {
41 this.getdiskname( num + 1, diskname )
42 // print( "\(num) \(this.curdisk) Disk = \(diskname) \(this.lastpath)\n")
43 if !fileexist( diskname )
44 {
45 if this.mess( $GEAMESS_GETVOLUME, %{ diskname, num + 1 }) ==
46 $GEA_ABORT : return 0
47 getcurdir( this.lastpath )
48 }
49 else : break
50 }
51 setcurdir( dir )
52 this.curfilename = diskname
53 if !( this.handle = gea_fileopen( diskname, $OP_READONLY,
54 this.userfunc )) : return 0
55 this.curdisk = num
56
57 if num
58 { // Проверка на правильность тома
59 uint gv
60 long size
61
62 read( this.handle, head, sizeof( geavolume ))
63 gv as head.ptr()->geavolume
64 if gv.name != $GEA_NAME
65 {
66 return this.mess( $GEAERR_NOTGEA, %{ diskname })
67 }
68 if gv.unique != this.volume.unique
69 {
70 return this.mess( $GEAERR_WRONGVOLUME, %{ diskname })
71 }
72 if num == this.head.count - 1 : size = this.head.lastsize
73 else : size = this.head.volsize
74 if getlongsize( this.handle ) < size
75 {
76 return this.mess( $GEAERR_WRONGSIZE, %{ diskname })
77 }
78 }
79 return 1
80 }
81
82 //--------------------------------------------------------------------------
83
84 method uint gead.read( long off, uint size )
85 { // Метод читает и возвращает указатель на данные
86 uint ptr = this.input.ptr()
87 uint curoff
88
89 // print("Enter = \(off) \(size) \( this.inoff ) \( this.insize )\n")
90 // Данные уже прочитаны
91 if off >= this.inoff && off + long( size ) <= this.inoff + long( this.insize )
92 {
93 // print("Ooops\n")
94 return ptr + uint( off - this.inoff )
95 }
96 // print("Read 1 \(uint( off - this.inoff )) \(uint( this.inoff +
97 // long( this.insize ) - off ))\n")
98 // Данные прочитаны частично
99 if off >= this.inoff && off < this.inoff + long( this.insize )
100 {
101 mmove( ptr, ptr + uint( off - this.inoff ), uint( this.inoff +
102 long( this.insize ) - off ))
103 // print("Move = \(off - this.inoff) size \(this.inoff + long( this.insize ) - off)\n")
104 this.insize -= uint( off - this.inoff )
105 size -= this.insize
106 curoff = this.insize
107 }
108 else : this.insize = 0
109
110 this.inoff = off
111 off += long( this.insize )
112
113 if off + long( size ) > this.head.summary
114 {
115 return this.mess( $GEAERR_INTERNAL, %{ this.filename, 1 })
116 }
117 // print("0 = \(curoff) \(this.insize) off=\(off) \( size )\n")
118 while size
119 {
120 uint i canread
121 long moveoff
122
123 moveoff = this.voloff[ this.head.count ]
124 // Если перемещенные данные
125 if this.head.movedsize && off >= moveoff
126 {
127 // print("Moved off = \( off ) \(uint( off - moveoff )) size = \(size) curoff = \(curoff)\n")
128 mcopy( ptr + curoff, this.moved.ptr() + uint( off - moveoff ),
129 size )
130 curoff += size
131 // this.insize += size
132 break
133 }
134 // Определяем требуемый том
135 fornum i, *this.voloff - 1
136 {
137 if !this.volsize[i] : continue
138 if off < this.voloff[ i + 1 ] : break
139 }
140 if i >= this.head.count : i = this.head.count - 1
141 if !this.opendisk( i ) : return 0
142 moveoff = off - this.voloff[ i ]
143 canread = min( size, uint( this.volsize[i] - moveoff ))
144 if !i
145 {
146 moveoff += long( this.head.size + this.head.movedsize + this.geaoff )
147 }
148 else : moveoff += long( sizeof( geavolume ))
149
150 setlongpos( this.handle, moveoff, $FILE_BEGIN )
151 // print("Read 3 \( moveoff ) Off=\( this.voloff[ i ] ) size=\(this.volsize[i]) \(canread) \(size)\n")
152 size -= canread
153 off += long( canread )
154 /* if uint( this.volsize[i] - moveoff ) > canread
155 {
156 canread = min( 0x80000, uint( this.volsize[i] - moveoff + 10L))
157 }*/
158 canread = max( canread, min( this.input.size - curoff, 0x80000 ))
159 // print("Read \( this.curfilename) fileoff = \(setpos(this.handle, 0, $FILE_CURRENT )) \( canread )\n ")
160 uint ri rw
161 ri = ReadFile( this.handle, ptr + curoff, canread, &canread, 0 )
162 if !i && moveoff + long( canread ) > this.head.geasize
163 { // Дать возможность добавлять Digital Signature
164 canread = uint( this.head.geasize - moveoff )
165 }
166 /* if !ri
167 {
168 ri = ReadFile( this.handle, ptr + curoff, canread, &rw, 0 )
169 print("Read ERR \(ri) \(rw) \(getsize( this.handle )) \(setpos(this.handle, 0, $FILE_CURRENT )) \( curoff)\n")
170 }*/
171 // print("Read 4 \(ri) \(off) \(canread) \(ptr + curoff) \(setpos(this.handle, 0, $FILE_CURRENT ))\n")
172 curoff += canread
173 // print("Read 5 \(curoff) \(canread) \(size) \n")
174 }
175 // print("Read 6 \(curoff) \(ptr) \n")
176 this.insize = curoff
177 return ptr
178 }
179
180 //--------------------------------------------------------------------------
181
182 /*func uint geacrc( uint ptr size param )
183 {
184 param->uint = crc( ptr, size, param->uint )
185 return 1
186 }*/
187
188 //--------------------------------------------------------------------------
189
190 //method uint gead.unpack( uint off, uint size )
191 method uint gead.unpack( uint id out )
192 {
193 uint gf ctype corder
194 uint input
195 uint ptr size
196 geadata gd
197 long off
198 geaparam gp
199 uint icrc = 0xFFFFFFFF
200
201 // this.output.clear()
202 if id >= *this.fileinfo : return 0
203
204 // binput.expand( this.head.blocksize )
205 gf as this.fileinfo[ id ]
206 if gf.flags & $GEAF_SOLID && id - 1 != this.lastsolid
207 {
208 uint demode ptemp = this.userfunc
209 this.userfunc = 0
210 // print("------------ \(id - 1) \(this.lastsolid)\n")
211 this.unpack( id - 1, 0 )
212 this.userfunc = ptemp
213 // print("============\n")
214 }
215 this.mess( $GEAMESS_DEBEGIN, %{ this.filename, &gf })
216 // print("Name=\(gf.name) \(id)\n")
217
218 size = gf.size
219 off = this.offset[ id ]
220
221 // print( "size 0 =\(size)\n")
222 subfunc uint readdata
223 {
224 uint solidoff
225
226 input = this.read( off, sizeof( geadata ))
227
228 gd.order = uint( input->geadata.order ) & ~0x80
229 gd.size = input->geadata.size
230 off += long( sizeof( geadata ))
231 ctype = gd.order >> 4
232 corder = ( uint( gd.order ) & 0x0F ) + 1
233 // print( "corder = \( corder )\n")
234 // Обнуляем output
235 if ( ctype != $GEA_LZGE || corder > 1 )
236 {
237 this.output.clear()
238 }
239 else
240 {
241 // Сдвигаем данные для solid
242 if *this.output + min( size, this.blocksize ) >
243 this.blocksize + this.solidsize
244 {
245 this.output.del( 0, *this.output - this.solidsize )
246 }
247 solidoff = *this.output
248 }
249 return solidoff
250 }
251 gp.done = 0
252 gp.name = ""//fullname
253 gp.info = &gf
254 gp.mode = 1
255
256 if gf.idpass // разшифровываем
257 {
258 label againpass
259
260 // print("ID=\(gf.idpass) \()\n")
261 if !*this.passwords[ gf.idpass - 1 ]
262 {
263 if this.mess( $GEAMESS_PASSWORD, %{ this.filename, gf })
264 {
265 goto againpass
266 }
267 else : return 0
268 }
269 }
270
271 while size
272 {
273 lzge lz
274 ppmd ppm
275
276 if !gd.size : lz.solidoff = readdata()
277
278 // print("1 =\( uint(off->long) + this.head.size ) \(gd.size + sizeof( geadata )) == \(size) \(gd.order) \(input->geadata.order)\n")
279
280 uint isize osize
281
282 ptr = this.output.ptr()
283 isize = min( this.blocksize, gd.size )
284 input = this.read( off, isize )
285 if gf.idpass // раcшифровываем
286 {
287 gea_protect( input, isize, this.passbufs[ gf.idpass - 1 ] )
288 }
289
290 off += long( isize )
291 osize = ?( ctype, min( this.blocksize, size ), isize )
292 switch ( ctype )
293 {
294 case $GEA_STORE
295 {
296 ptr = input
297 this.mess( $GEAMESS_PROCESS, %{ this.filename, gf, osize + gp.done })
298 }
299 case $GEA_LZGE
300 {
301 // print("Input=\(input - this.input.ptr()) Outsize=\( this.output.size) Out=\(*this.output) Solidoff=\(lz.solidoff ) osize=\( osize ) isize = \(isize)\n")
302 lz.userfunc = this.userfunc
303 lz.pgeaparam = &gp
304 // print("\n1 \(lz.solidoff + osize) \( *this.output ) \( this.output.size )
305 // Off = \( input - this.input.ptr() )\n")
306 lzge_decode( input, ptr, lz.solidoff + osize, lz )
307 this.output.use = lz.solidoff + osize
308 ptr += lz.solidoff
309 // ptr += lz.solidoff
310 }
311 case $GEA_PPMD
312 {
313 ppm.order = corder
314 ppm.userfunc = this.userfunc
315 ppm.pgeaparam = &gp
316 ppmd_decode( input, gd.size, ptr, osize, ppm )
317 // ptr = this.output.ptr()
318 }
319 }
320 gp.done += osize
321 gd.size -= isize
322 icrc = crc( ptr, osize, icrc )
323 if out
324 {
325 if this.demode == $GEAD_MEM : out->buf.append( ptr, osize )
326 elif this.demode == $GEAD_FILE
327 {
328 uint iw
329 if !WriteFile( out, ptr, osize, &iw, 0 ) || iw != osize
330 {
331 this.mess( $GEAERR_FILEWRITE, %{ gf.name })
332 return 0
333 }
334 }
335 }
336 // print( "SS = 6 \( osize ) \(*( out->buf ))\n")
337 // geacrc( ptr, osize, param )
338 size -= osize
339 }
340 if icrc != gf.crc
341 {
342 this.mess( $GEAERR_CRC, %{ this.filename, &gf } )
343 }
344 this.mess( $GEAMESS_DEEND, %{ this.filename, &gf })
345
346 this.lastsolid = id
347 return 1
348 }
349
350 //--------------------------------------------------------------------------
351
352 method uint gead.test( uint id )
353 {
354 this.demode = $GEAD_TEST
355 return this.unpack( id, 0 )
356 }
357
358 //--------------------------------------------------------------------------
359
360 method uint gead.file2mem( uint id, buf output )
361 {
362 this.demode = $GEAD_MEM
363 output.clear()
364 return this.unpack( id, &output )
365 }
366
367 //--------------------------------------------------------------------------
368
369 method uint gead.file2file( uint id handle )
370 {
371 this.demode = $GEAD_FILE
372 return this.unpack( id, handle )
373 }
374
375 //--------------------------------------------------------------------------
376
377 method long gead.summarysize
378 {
379 uint i
380 long result
381
382 fornum i, *this.fileinfo
383 {
384 // print("i =\(i) Name=\(this.fileinfo[ i ].name) Subfolder = \(this.fileinfo[ i ].subfolder) Size = \( this.fileinfo[ i ].size )\n")
385 result += long( this.fileinfo[ i ].size )
386 }
387 return result
388 }
389
390 //--------------------------------------------------------------------------
391
392
393