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 //include : $"k:\gentee\gentee language\libraries\filex\filex.g"
15 //include : $"k:\gentee\gentee language\libraries\filex\fileversion.g"
16
17 import "kernel32.dll" {
18 uint GetTickCount( )
19 }
20
21 type geae
22 {
23 geahead head // Заголовок
24 str filename // The main filename
25 uint flags
26 str pattern // The pattern of the volume
27 long volsize // 0 - one volume otherwise the size of the volume
28 uint userfunc // user function
29 // uint userparam // user parameter
30 // uint numvol // The number of the current volume
31 arr fileinfo of geafile // The array of file descriptions
32 hash addedfiles // Added files
33 str volpath // Path to volumes
34 arrstr volnames // Volume names
35 arr volumes of long // Volume sizes
36 arrstr passwords // Passwords
37 arr passbufs of buf // Long passwords
38
39 // Для solid сжатия
40 buf bsolid // Предыдущие данные для solid сжатия
41 uint prevmethod // Предыдущий метод
42 uint prevorder // Предыдущий порядок
43 uint prevsolid // Предыдущий файл был с опцией solid
44 uint prevpass // Предыдущий пароль
45
46 // Вывод в файл
47 uint handle // Главный файл вывода
48 uint curhandle // Текущий файл вывода
49 str curfilename // Текущее имя тома
50 uint geaoff // Смещение GEA данных
51 uint unique
52 buf out // Временный буфер для записи
53 uint start // Указатель начала данных
54 uint end // Указатель конца данных
55 uint stop // Указатель конца буфера
56 uint emptyvol // В первый том ничего не писали
57 uint curvol // Номер текущего тома записи
58 }
59
60 define
61 {
62 // Flags of geaeinit.flag
63 GEAI_APPEND = 0x0001 // to append a file otherwise to create
64 // GEAI_COMPINFO = 0x0002 // Compress file descriptions
65 GEAI_IGNORECOPY = 0x0004 // Ignore copies of files
66 }
67
68 type geaeinit
69 {
70 uint flags // flags
71 str pattern // volume pattern
72 long volsize // 0 - one volume otherwise the size of the volume
73 uint userfunc // user function
74 // uint userparam // user parameter
75 }
76 /*
77 method uint geae.mess( uint code, str name )
78 {
79 return geafunc( this.userfunc, %{ code, name })
80 }
81
82 method uint geae.mess( uint code, str name, geafile gf )
83 {
84 return geafunc( this.userfunc, %{ code, name, gf })
85 }
86
87 method uint geae.mess( uint code, str name, geafile gf, uint process )
88 {
89 return geafunc( this.userfunc, %{code, name, gf, process })
90 }
91 */
92
93 method uint geae.mess( uint code, collection cl )
94 {
95 return geafunc( this.userfunc, code, cl )
96 }
97
98 include : "geaefile.g"
99
100 method uint geae.create( str filename, geaeinit geai )
101 {
102 str stemp
103
104 this.flags = geai.flags
105 this.pattern = geai.pattern
106 this.volsize = geai.volsize
107 this.userfunc = geai.userfunc
108 // this.userparam = geai.userparam
109 this.filename.ffullname( filename )
110 this.volpath.fgetdir( this.filename )
111 stemp.fnameext( this.filename )
112 this.volnames += stemp
113 this.curfilename = this.filename
114 verifypath( this.volpath, 0->arrstr )
115 this.mess( $GEAMESS_BEGIN, %{ this.filename })
116
117 // Открываем файл
118 if !( this.handle = gea_fileopen( this.filename, $OP_EXCLUSIVE |
119 ?( geai.flags & $GEAI_APPEND, $OP_ALWAYS, $OP_CREATE ),
120 this.userfunc ) ) : return 0
121
122 this.curhandle = this.handle
123 if this.geaoff = getsize( this.handle )
124 {
125 setpos( this.handle, 0, $FILE_END )
126 }
127 this.unique = GetTickCount()
128
129 // Проверяем размер тома и шаблон
130 if this.volsize
131 {
132 str sone
133
134 if this.volsize < long( $GEA_MINVOLSIZE )
135 {
136 this.volsize = long( $GEA_MINVOLSIZE )
137 }
138 if !*this.pattern
139 {
140 filename.fgetparts( 0->str, stemp, 0->str )
141 this.pattern = "\(stemp).g%02u"
142 }
143 // int2str( sone, this.pattern, 1 )
144 sone.out4( this.pattern, 1 )
145 // int2str( stemp, this.pattern, 2 )
146 stemp.out4( this.pattern, 2 )
147 if stemp == sone
148 {
149 this.mess( $GEAERR_PATTERN, %{ this.pattern })
150 return 0
151 }
152 }
153 this.addedfiles.ignorecase()
154 // Устанавливаем размеры
155 datetime dt
156 this.head.majorver = $GEA_MAJOR
157 this.head.minorver = $GEA_MINOR
158 datetimetoftime( dt.gettime(), this.head.date )
159 this.head.count = 1
160 this.head.blocksize = 8 // = 0x40000 * 8
161 this.head.memory = 8 // 8 MB для PPMD
162 this.head.solidsize = 4 // = 0x40000 * 8
163 this.bsolid.expand( 0x40000 * this.head.solidsize )
164
165 ppmd_start( this.head.memory )
166 this.out.expand( 2 * $GEA_DESCRESERVE )
167 this.out.use = 2 * $GEA_DESCRESERVE
168 this.end = this.start = this.out.ptr()
169 this.stop = this.out.ptr() + this.out.use
170 return 1
171 }
172
173 method geae.writeinfo( buf head )
174 {
175 uint i
176 buf btemp
177 buf out
178 geacompfile gcf
179 str prevfolder
180 uint prevattrib prevgroup prevpass
181 lzge lz
182
183 foreach cur, this.fileinfo
184 {
185 btemp.clear()
186 gcf.flags = cur.flags
187 gcf.ft = cur.ft
188 gcf.size = cur.size
189 gcf.compsize = cur.compsize
190 gcf.crc = cur.crc
191 if cur.attrib != prevattrib
192 {
193 gcf.flags |= $GEAF_ATTRIB
194 btemp += cur.attrib
195 prevattrib = cur.attrib
196 }
197 if cur.hiver || cur.lowver
198 {
199 gcf.flags |= $GEAF_VERSION
200 btemp += cur.hiver
201 btemp += cur.lowver
202 }
203 if cur.idgroup != prevgroup
204 {
205 gcf.flags |= $GEAF_GROUP
206 btemp += cur.idgroup
207 prevgroup = cur.idgroup
208 }
209 if cur.idpass != prevpass
210 {
211 gcf.flags |= $GEAF_PROTECT
212 btemp += cur.idpass
213 prevpass = cur.idpass
214 }
215 btemp += cur.name
216 if cur.subfolder != prevfolder
217 {
218 gcf.flags |= $GEAF_FOLDER
219 btemp += cur.subfolder
220 prevfolder = cur.subfolder
221 }
222 out.append( &gcf, sizeof( geacompfile ))
223 out += btemp
224 }
225 btemp.expand( max( 10000, *out + *out / 10 ))
226 lz.order = 10
227 btemp.use = lzge_encode( out.ptr(), *out, btemp.ptr(), lz )
228 if btemp.use < *out * 90 / 100
229 {
230 head += btemp
231 this.head.flags |= $GEAH_COMPRESS
232 }
233 else : head += out
234
235 // uint phead
236 // phead as ( head.ptr() + sizeof( geavolume ))->geahead
237 // phead.infosize = *out
238 this.head.infosize = *out
239 // phead.size = *head
240 }
241
242 method uint geae.close( )
243 {
244 buf head
245 geavolume gv
246 uint i
247
248 ppmd_stop()
249 // print( "All Files \(sizeof( geahead )) = \(*this.fileinfo) Summary: \( this.head.summary )\n")
250 // Формируем заголовок
251 this.mess( $GEAMESS_WRITEHEAD, %{ this.filename })
252 gv.name = $GEA_NAME
253 gv.unique = this.unique
254 if *this.passwords : this.head.flags |= $GEAH_PASSWORD
255
256 head.copy( &gv, sizeof( geavolume ))
257 head.append( &this.head, sizeof( geahead ))
258 head += this.pattern
259
260 // Записывем пароли
261 if *this.passwords
262 {
263 head += ushort( *this.passwords )
264 foreach curpass, this.passwords
265 {
266 head += curpass.crc()
267 }
268 }
269
270 this.writeinfo( head )
271 this.head.size = *head
272 this.head.volsize = this.volsize
273 // Записываем заголовок
274 setpos( this.handle, this.geaoff, $FILE_BEGIN )
275 if !write( this.handle, head )
276 {
277 return this.mess( $GEAERR_FILEWRITE, %{ this.filename })
278 }
279 // Записываем оставшиеся данные
280 if !this.put( 0, 0 ) : return 0
281 this.head.count = *this.volumes
282 this.head.geasize = getlongsize( this.handle )
283 this.head.lastsize = this.volumes[ *this.volumes - 1 ]
284 // Закрываем последний том
285 if this.curhandle != this.handle : close( this.curhandle )
286 // Записываем заново заголовок и информацию о томах
287 setpos( this.handle, this.geaoff + sizeof( geavolume ), $FILE_BEGIN )
288 WriteFile( this.handle, &this.head, sizeof( geahead ), &i, 0 )
289 close( this.handle )
290
291 this.mess( $GEAMESS_END, %{ this.filename })
292 return 1
293 }
294