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 define
15 {
16 GEAD_TEST = 0 // Testing
17 GEAD_MEM // Writing to buf
18 GEAD_FILE // Writing to file
19 }
20
21 type gead
22 {
23 geavolume volume // GEA volume
24 geahead head // GEA header
25 uint userfunc // user function
26 str filename // The main filename
27 str lastpath // The last path to GEA files
28 str curfilename // The current filename
29 uint geaoff // The offset of GEA data
30 buf moved // The last data
31 str pattern // The pattern of the volume
32 arr passcrc // CRC of passwords
33 arr fileinfo of geafile // The array of file descriptions
34 arr offset of long // The offsets of the beginning of the files
35 buf input // The input buffer
36 long inoff // The offset of the read input
37 uint insize // The size of the read input
38 buf output // The output buffer
39
40 uint handle // Текущий открытый файл
41 uint curdisk // Номер текущего открытого тома
42
43 arr voloff of long // The offset of volumes
44 arr volsize of long // The size of volumes
45
46 uint blocksize
47 uint solidsize
48 uint lastsolid // The last unpacked solid file
49 uint demode // See GEAD_* defines
50 arrstr passwords // Passwords
51 arr passbufs of buf // Long passwords
52 // uint storesize
53 // uint handle // The handle of the main file
54 /* uint flags
55 str pattern // The pattern of the volume
56 long volsize // 0 - one volume otherwise the size of the volume
57 uint userparam // user parameter
58 // uint numvol // The number of the current volume
59 arr fileinfo of geafile // The array of file descriptions
60 hash addedfiles // Added files
61 str volpath // Path to volumes
62 arr volnames of str // Volume names
63 arr volumes of long // Volume sizes
64 */
65 }
66
67 type geadinit
68 {
69 uint userfunc // user function
70 uint geaoff // the offset of GEA data
71 // uint userparam // user parameter
72 }
73
74 method uint gead.validatepass( uint id, str password )
75 {
76 uint ret i
77
78 if id > *this.passcrc : return 1
79
80 fornum i, *this.passcrc
81 {
82 if !id || id == i + 1
83 {
84 if this.passcrc[ i ] == password.crc()
85 {
86 this.passwords[ i ] = password
87 gea_passgen( this.passbufs[ i ], password )
88 ret = 1
89 }
90 }
91 }
92 return ret
93 }
94
95 method uint gead.mess( uint code, collection cl )
96 {
97 return geafunc( this.userfunc, code, cl )
98 }
99
100 include : "geadfile.g"
101
102 method uint gead.open( str filename, geadinit gi )
103 {
104 uint handle cur i count
105 buf head btemp
106
107 this.userfunc = gi.userfunc
108 this.geaoff = gi.geaoff
109 this.filename.ffullname( filename )
110
111 // Открываем файл
112 if !( handle = gea_fileopen( this.filename, $OP_READONLY,
113 this.userfunc )) : return 0
114 this.lastpath.fgetdir( this.filename )
115 setpos( handle, this.geaoff, $FILE_BEGIN )
116 read( handle, head, $GEA_DESCRESERVE )
117 mcopy( &this.volume, head.ptr(), sizeof( geavolume ))
118 mcopy( &this.head, head.ptr() + sizeof( geavolume ), sizeof( geahead ))
119 if this.volume.name != $GEA_NAME
120 {
121 return this.mess( $GEAERR_NOTGEA, %{ this.filename })
122 }
123 if this.head.majorver != $GEA_MAJOR || this.head.minorver != $GEA_MINOR
124 {
125 if this.mess( $GEAMESS_WRONGVER, %{ this.filename }) != $GEA_IGNORE
126 {
127 return 0
128 }
129 }
130 if getlongsize( handle ) < this.head.geasize
131 {
132 return this.mess( $GEAERR_WRONGSIZE, %{ this.filename })
133 }
134 cur = head.ptr() + sizeof( geavolume ) + sizeof( geahead )
135 this.pattern.copy( cur )
136 cur += *this.pattern + 1
137 if this.head.flags & $GEAH_PASSWORD
138 {
139 count = cur->ushort
140 cur += sizeof( ushort )
141 fornum i = 0, count
142 {
143 this.passcrc[ this.passcrc.expand( 1 ) ] = cur->uint
144 this.passwords += ""
145 this.passbufs.expand( 1 )
146 cur += sizeof( uint )
147 }
148 }
149 if this.head.flags & $GEAH_COMPRESS
150 {
151 lzge lz
152
153 btemp.expand( this.head.infosize )
154 lzge_decode( cur, btemp.ptr(), this.head.infosize, lz )
155 btemp.use = this.head.infosize
156 cur = btemp.ptr()
157 }
158 uint end = cur + this.head.infosize
159 uint curattrib curgroup curpass
160 str curfolder
161 long curoff
162
163 while cur < end
164 {
165 uint gf gc
166
167 this.fileinfo.expand( 1 )
168 gf as this.fileinfo[ *this.fileinfo - 1 ]
169 gc as cur->geacompfile
170 gf.flags = gc.flags
171 gf.ft = gc.ft
172 gf.size = gc.size
173 gf.compsize = gc.compsize
174 gf.crc = gc.crc
175 cur += sizeof( geacompfile )
176 if gf.flags & $GEAF_ATTRIB
177 {
178 curattrib = gf.attrib = cur->uint
179 cur += 4
180 }
181 else : gf.attrib = curattrib
182 if gf.flags & $GEAF_VERSION
183 {
184 gf.hiver = cur->uint
185 cur += 4
186 gf.lowver = cur->uint
187 cur += 4
188 }
189 if gf.flags & $GEAF_GROUP
190 {
191 curgroup = gf.idgroup = cur->uint
192 cur += 4
193 }
194 else : gf.idgroup = curgroup
195 if gf.flags & $GEAF_PROTECT
196 {
197 curpass = gf.idpass = cur->uint
198 cur += 4
199 }
200 else : gf.idpass = curpass
201 gf.name.copy( cur )
202 cur += *gf.name + 1
203 if gf.flags & $GEAF_FOLDER
204 {
205 curfolder = gf.subfolder.copy( cur )
206 cur += *gf.subfolder + 1
207 }
208 else : gf.subfolder = curfolder
209 // Добавляем смещения
210 this.offset.expand( 1 )
211 this.offset[ *this.offset - 1 ] = curoff
212 curoff += long( gf.compsize )
213 }
214 if this.head.movedsize
215 {
216 this.moved.copy( head.ptr() + this.head.size, this.head.movedsize )
217 }
218 else
219 { // Копируем данные в буфер
220 this.input.copy( head.ptr() + this.head.size, *head - this.head.size )
221 this.insize = *head - this.head.size
222 }
223 this.handle = handle
224 // Вычисляем смещения и размеры томов
225 long voloff
226
227 this.volsize.expand( this.head.count + 1 )
228 this.voloff.expand( this.head.count + 1 )
229 fornum i = 0, this.head.count
230 {
231 long size
232 if !i
233 {
234 size = this.head.geasize - long( this.head.movedsize ) -
235 long( this.head.size ) - long( this.geaoff )
236 }
237 elif i == this.head.count - 1
238 {
239 size = this.head.lastsize - long( sizeof( geavolume ))
240 }
241 else : size = this.head.volsize - long( sizeof( geavolume ))
242 this.volsize[ i ] = size
243 this.voloff[ i ] = voloff
244 voloff += size
245 }
246 if this.head.movedsize
247 {
248 this.volsize[ this.head.count ] = long( this.head.movedsize )
249 this.voloff[ this.head.count ] = voloff
250 }
251 this.blocksize = 0x40000 * this.head.blocksize
252 this.solidsize = 0x40000 * this.head.solidsize
253
254 this.input.expand( this.blocksize + 64 )
255 this.output.expand( this.blocksize + this.solidsize + 64 )
256 this.lastsolid = 0xFFFFFFFF
257 ppmd_start( this.head.memory )
258
259 return 1
260 }
261
262 method uint gead.close
263 {
264 ppmd_stop()
265 close( this.handle )
266 return 1
267 }