EnglishРусский  

   ..

   gea.g

   gead.g

   geademo.g

   geae.g

   geaefile.g

   geafile.g

The project is closed! You can look at a new scripting language. It is available on GitHub.
Also, try our open source cross-platform automation software.

Ads

Installer and installation software
Commercial and Freeware installers.

source\lib\gea\geaefile.g
  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 type geacomp
 15 {
 16     uint    idgroup     // id of the file group
 17     str     subfolder   // subfolder
 18     str     password    // password
 19     uint    compmethod  // compression algorithms
 20     uint    order       // compression order
 21     uint    solid       // 1 if solid archive
 22 }
 23 
 24 // Функция прямой записи в файл
 25 method uint geae.write( uint ptr size )
 26 {
 27    uint iw
 28    
 29    if !WriteFile( this.curhandle, ptr, size, &iw, 0 ) || 
 30                   iw != size
 31    {
 32       this.mess( $GEAERR_FILEWRITE, %{ this.curfilename })
 33       return 0
 34    }
 35 //   this.volumes[ *this.volumes - 1 ] += long( size )
 36    this.volumes[ this.curvol ] = getlongsize( this.curhandle )
 37    return 1
 38 }
 39 
 40 // Функция записи в файл с учетом разбивки на тома
 41 method uint geae.writevolume( uint ptr size )
 42 {
 43    uint num 
 44    str  stemp
 45    
 46    if !size : return 1
 47    
 48    if !*this.volumes   // Первая запись данных
 49    {
 50       buf   btemp
 51       
 52       btemp.expand( $GEA_DESCRESERVE )
 53       mzero( btemp.ptr(), $GEA_DESCRESERVE )
 54       btemp.use = $GEA_DESCRESERVE
 55       this.volumes.expand( 1 )
 56       this.volumes[ 0 ] = long( this.geaoff ) 
 57       if this.volsize && this.volsize < long( this.geaoff +
 58                                                  $GEA_DESCRESERVE )
 59       {    // Оставляем первый том полностью пустым
 60          this.emptyvol = 1    
 61 //         this.volumes.expand( 1 )
 62 //         this.curvol = 1
 63       } 
 64       else  // Резервируем место 
 65       {
 66          if !this.write( btemp.ptr(), $GEA_DESCRESERVE ) : return 0
 67       }
 68    }
 69    label volume
 70    if this.volsize  // Проверка на заполнение тома
 71    {
 72       num = this.curvol //= *this.volumes - 1
 73 //         print("OK 1 \(this.volumes[ num ]) \(wsize) \(this.volsize)\n") 
 74       if this.volumes[ num ] + long( size ) >= this.volsize
 75       {
 76          uint rem
 77          
 78          if this.volsize > this.volumes[ num ] && ( num || !this.emptyvol )
 79          {  // Дописываем остатки
 80             rem = uint( this.volsize - this.volumes[ num ] )
 81             if !this.write( ptr, rem ) : return 0
 82          }
 83          size -= rem
 84          ptr += rem
 85          // Закрываем том
 86          if num : close( this.curhandle )
 87          // Создаем новый том
 88          num++
 89          if num > $GEA_MAXVOLUMES
 90          {
 91             this.mess( $GEAERR_MANYVOLUMES, %{this.curfilename })
 92             return 0
 93          }
 94          this.curvol = this.volumes.expand( 1 )
 95          geavolume gv
 96          gv.name = 0x414547 
 97          gv.unique = this.unique
 98          gv.number = num
 99 //         int2str( stemp.clear(), this.pattern, num + 1 )
100          stemp.clear()
101          stemp.out4( this.pattern, num + 1 )                   
102          this.volnames += stemp
103          ( this.curfilename = this.volpath ).faddname( stemp )
104          label again
105          if !( this.curhandle = open( this.curfilename, $OP_EXCLUSIVE | 
106                                        $OP_CREATE ))
107          {
108             switch this.mess( $GEAERR_FILEOPEN, %{ this.curfilename })
109             {
110                case $GEA_RETRY : goto again
111                case $GEA_ABORT : return 0
112             }
113          }
114          if !this.write( &gv, sizeof( geavolume )) : return 0
115          goto volume
116       }
117    }
118    if !this.write( ptr, size ) : return 0
119 //   congetch("Ooops = \(size)\n")
120    return 1
121 }
122 
123 method uint geae.put( uint ptr size )
124 {
125    uint avail
126    uint pout  full end start stop
127    
128    subfunc uint  storebuf( uint rem )
129    {
130       uint iw = full - avail - rem        // Сколько записать
131 
132       if start + iw < stop
133       {
134          if !this.writevolume( start, iw ) : return 0
135          start += iw
136       }
137       else
138       {
139          if !this.writevolume( start, stop - start ) : return 0
140          iw -= stop - start
141          if !this.writevolume( pout, iw ) : return 0
142          start = pout + iw
143       }
144       if !rem
145       {
146          start = pout
147          end = pout 
148       }
149       avail = full - rem
150       return 1
151    }
152    subfunc uint finish()
153    {  // Запись оставшихся данных
154       if !*this.volumes
155       {   // Записей не было и заголовок уже записан. Пишем все данные
156          this.volumes.expand( 1 )
157          this.volumes[ 0 ] = getlongsize( this.curhandle )
158 //         print("Volume = \( this.volumes[ 0 ] )\n")
159       }
160       else  // Есть зарезервированное место
161       {
162          if this.emptyvol
163          {  // Нет зарезервированного места
164             this.volumes[ 0 ] = getlongsize( this.handle )
165             if this.volsize > this.volumes[ 0 ]
166             {
167                // this.volsize - this.volumes[ 0 ] не больше uint иначе не
168                //  может быть emptyvol 
169                this.head.movedsize = uint( this.volsize - this.volumes[ 0 ] )
170             }
171          }
172          else
173          {
174             this.head.movedsize = $GEA_DESCRESERVE - this.head.size
175          }
176          setpos( this.curhandle, 0, $FILE_END )
177          // Дописываем остатки
178          if !storebuf( this.head.movedsize ) : return 0
179          if this.curhandle != this.handle : close( this.curhandle )
180          // Дописываем в главный файл
181          this.curhandle = this.handle
182          setpos( this.handle, this.geaoff + this.head.size, $FILE_BEGIN )
183          this.curvol = 0
184          this.volsize = 0L
185       }
186       // Записываем все из буфера в первый том
187       if !storebuf( 0 ) : return 0
188 
189       return 1
190    }
191    pout = this.out.ptr()
192    full = *this.out
193    end = this.end
194    start = this.start
195    stop = this.stop
196    avail = ?( end >= start, full - ( end - start ), start - end )
197 
198    if !ptr : return finish()
199 
200    this.head.summary += long( size )
201    this.fileinfo[ *this.fileinfo - 1 ].compsize += size
202 //   print("\n\(this.fileinfo[ *this.fileinfo - 1 ].compsize)\n")
203 
204    if size >= avail
205    {  // Необходимо записать лишнее на диск
206       if size > $GEA_DESCRESERVE
207       {
208          // Записываем все из буфера
209          if !storebuf( 0 ) : return 0
210          // Записываем часть из ptr
211          if !this.writevolume( ptr, size - $GEA_DESCRESERVE ) : return 0
212          ptr += size - $GEA_DESCRESERVE
213          size = $GEA_DESCRESERVE
214       }
215       else
216       {     // Записываем часть из буфера
217          if !storebuf( $GEA_DESCRESERVE - size ) : return 0
218       } 
219    }
220    // Записываем данные в буфер
221    if stop - end  > size
222    {
223       mcopy( end, ptr, size )
224       end += size
225    }     
226    else
227    {
228       uint rem = stop - end
229       mcopy( end, ptr, rem )
230       mcopy( pout, ptr + rem, size - rem )
231       end = pout + size - rem     
232    }
233    this.end = end
234    this.start = start
235    return 1
236 }
237 
238 method  uint geae.add( str filename, geacomp gc )
239 {
240    geaparam   gp
241    uint cursize blocksize solidsize
242    uint handle curid gf i
243    str  fullname fpath fname
244    buf  in out
245    
246    fullname.ffullname( filename )
247    fname.fnameext( fullname )
248    fpath.fgetdir( fullname )
249    
250    if fpath %== this.volpath   // Проверка на имя тома
251    { 
252       foreach curvol, this.volnames : if curvol %== fname : return 1  
253    }
254    // Проверка на то, что уже добавлен
255    if i = this.addedfiles.find( fullname )
256    {
257       this.mess( $GEAMESS_COPY, %{ fullname })
258       if this.flags & $GEAI_IGNORECOPY : return 1
259    } 
260    else
261    {  // Добавление в добавленные
262       this.addedfiles[ fullname ] = 1 
263    }
264 
265    // Открываем файл
266    if !( handle = gea_fileopen( fullname, $OP_READONLY, this.userfunc ))
267    {
268       return 0
269    }
270    // Не принимаем слишком большие файлы
271    if getlongsize( handle ) >= 0xFFFF0000L
272    {
273       close( handle )  
274       return this.mess( $GEAERR_TOOBIG, %{ fullname }) == $GEA_IGNORE
275    }  
276    curid = this.fileinfo.expand( 1 ) 
277    gf as this.fileinfo[ curid ]
278    gf.name = fname
279    gf.crc = 0xFFFFFFFF
280    gf.idgroup = gc.idgroup
281    gf.subfolder = gc.subfolder
282    // Получаем время, размер, атрибуты, версию 
283    getftime( handle, gf.ft )
284    gf.size = getsize( handle )
285    gf.attrib = getfileattrib( fullname ) 
286    getfversion( fullname, &gf.hiver, &gf.lowver )
287    if *gc.password
288    {  // Есть такой пароль или нет
289       fornum i = 0, *this.passwords
290       { 
291          if this.passwords[ i ] == gc.password
292          { 
293             gf.idpass = i + 1
294             break
295          }
296       }
297       if !gf.idpass   // Если не нашли то добавляем пароль
298       {
299          this.passwords += gc.password
300          gea_passgen( this.passbufs[ this.passbufs.expand( 1 ) ], 
301                       gc.password )
302          gf.idpass = *this.passwords
303       }
304    }
305    this.mess( $GEAMESS_ENBEGIN, %{ fullname, gf })
306    blocksize = 0x40000 * this.head.blocksize
307    solidsize = 0x40000 * this.head.solidsize
308    in.expand( blocksize + solidsize )
309    out.expand( blocksize + blocksize / 10 )
310    
311    uint       store failpack leadorder
312    lzge       lz
313    ppmd       ppm
314    
315    gc.order = max( 1, min( 10, gc.order ))
316    
317    gp.done = 0
318    gp.name = fullname
319    gp.info = &gf
320    gp.mode = 0
321    switch gc.compmethod
322    {
323       case $GEA_STORE
324       { 
325          geadata  gd
326    
327          gd.order |= 0x80
328          gd.size = gf.size
329          if gf.size
330          { 
331             if !this.put( &gd, sizeof( geadata )) : return 0 
332          }
333          store = 1
334       }
335       case $GEA_LZGE
336       {
337          lz.order = gc.order 
338          lz.userfunc = this.userfunc
339          lz.pgeaparam = &gp 
340       }
341       case $GEA_PPMD
342       {
343 //         ppm.memory = this.head.memory
344          ppm.order = gc.order + 1
345          ppm.userfunc = this.userfunc
346          ppm.pgeaparam = &gp 
347          leadorder = ppm.order
348       }
349    }
350    if gc.solid
351    {
352       // Сбрасываем если упаковали уже много с solid сжатием 
353       if this.prevsolid + gf.size > solidsize : this.prevsolid = 0 
354         
355       // Проверяем на совпадение предыдущих настроек
356       if this.prevsolid && this.prevmethod == gc.compmethod && 
357          this.prevorder == gc.order && gf.idpass == this.prevpass 
358       {
359          gf.flags |= $GEAF_SOLID
360          this.prevsolid += gf.size     
361       }
362       else : this.prevsolid = gf.size  
363       this.prevpass = gf.idpass
364    } 
365    else : this.prevsolid = 0
366 //   print("Prev=\(this.prevsolid) block=\( blocksize ) size=\( gf.size )\n")
367    if !( gf.flags & $GEAF_SOLID ) : this.bsolid.clear()
368                     
369    while cursize < gf.size
370    {
371       geadata  gd
372       uint issolid  pout psize pin
373       uint iread = min( gf.size - cursize, blocksize )
374     
375       in.use = solidsize
376       out.use = 0
377       if read( handle, in, iread ) != iread
378       {
379          this.mess( $GEAERR_FILEREAD, %{ fullname })
380          return 0         
381       }
382       pin = in.ptr() + solidsize
383       gf.crc = crc( pin, iread, gf.crc )
384       if gc.compmethod == $GEA_LZGE
385       {
386          lz.solidoff = 0//*this.bsolid
387          
388          if ( cursize || gf.flags & $GEAF_SOLID ) && !failpack         
389          { 
390             lz.solidoff = *this.bsolid
391             issolid = 1
392             pin -= lz.solidoff
393             mcopy( pin, this.bsolid.ptr(), lz.solidoff ) 
394          }
395          out.use = lzge_encode( pin, iread + lz.solidoff, out.ptr(), lz )
396 //         out.write("c:\\aa\\encode\(lz.solidoff).bin")
397          i = min( solidsize, iread + lz.solidoff )
398          this.bsolid.copy( pin + iread + lz.solidoff - i, i )  
399 //         print("\ni= \( i ) iread=\( iread ) ss = \(solidsize) bs=\( *this.bsolid )\n")
400       }
401       elif gc.compmethod == $GEA_PPMD
402       {
403          if ( cursize || gf.flags & $GEAF_SOLID ) && !failpack
404          { 
405             ppm.order = 1
406             issolid = 1
407          }
408          out.use = ppmd_encode( pin, iread, out.ptr(), out.size, ppm )
409          ppm.order = leadorder
410       }
411       if gc.compmethod && out.use > ( in.use - solidsize ) * 98 / 100
412       {
413 //         print("\n\(in.use) <= \(out.use)\n")
414          if !cursize
415          { 
416             gd.order |= 0x80
417             gf.flags &= ~$GEAF_SOLID
418          }
419          gd.size = iread 
420          if !this.put( &gd, sizeof( geadata )) : return 0
421          failpack = 1
422          issolid = 0
423          this.bsolid.clear()
424          if gc.compmethod == $GEA_LZGE : pin += lz.solidoff 
425       }
426       else : failpack = 0
427       if store || failpack
428       {
429          pout = pin
430          psize = iread
431          this.prevmethod = $GEA_STORE
432          this.prevsolid = 0
433          if store
434          {
435             this.mess( $GEAMESS_PROCESS, %{ fullname, gf, iread + gp.done })
436          }
437       }
438       else
439       {
440          this.prevmethod = gc.compmethod
441          this.prevorder = gc.order
442          
443          gd.order = ( gc.compmethod << 4 ) + ?( issolid, 0, gc.order )
444 //         print("Order = \(gd.order)\n")
445          if !cursize : gd.order |= 0x80
446          
447          gd.size = *out
448          if !this.put( &gd, sizeof( geadata )) : return 0
449          pout = out.ptr()
450          psize = *out
451       } 
452       if gf.idpass  // Шифруем 
453       {
454          gea_protect( pout, psize, this.passbufs[ gf.idpass - 1 ] )
455       }
456       if !this.put( pout, psize ) : return 0
457       cursize += blocksize
458       gp.done += iread
459    }   
460    close( handle )
461    this.mess( $GEAMESS_ENEND, %{ fullname, gf })
462    return 1
463 }
464 
465 method  uint geae.adddir( str filename, geacomp gc )
466 {
467    str  fullname fpath fname
468    uint curid i gf 
469       
470 /*   geaparam   gp
471    uint cursize blocksize solidsize
472    uint handle curid gf i
473    buf  in out
474 */   
475    fullname.ffullname( filename )
476    fname.fnameext( fullname )
477    fpath.fgetdir( fullname )
478    
479    // Проверка на то, что уже добавлен
480    if i = this.addedfiles.find( fullname )
481    {
482       this.mess( $GEAMESS_COPY, %{ fullname })
483       if this.flags & $GEAI_IGNORECOPY : return 1
484    } 
485    else
486    {  // Добавление в добавленные
487       this.addedfiles[ fullname ] = 1 
488    }
489 
490    curid = this.fileinfo.expand( 1 ) 
491    gf as this.fileinfo[ curid ]
492    gf.name = fname
493    gf.crc = 0xFFFFFFFF
494    gf.idgroup = gc.idgroup
495    gf.subfolder = gc.subfolder
496    // Получаем время, размер, атрибуты, версию 
497    gf.attrib = getfileattrib( fullname ) 
498    this.mess( $GEAMESS_ENBEGIN, %{ fullname, gf })
499    
500    this.prevmethod = $GEA_STORE
501    this.prevsolid = 0
502          
503 //   print("Prev=\(this.prevsolid) block=\( blocksize ) size=\( gf.size )\n")
504    this.bsolid.clear()
505                     
506    this.mess( $GEAMESS_ENEND, %{ fullname, gf })
507    return 1
508 }
509