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 : $"..\other\random.g"
15 include : $"..\gea\filelist.g"
16
17 define
18 {
19 tcompTYPE_NONE = 0x0000 // No compression
20 tcompTYPE_MSZIP = 0x0001 // MSZIP
21 tcompTYPE_QUANTUM = 0x0002 // Quantum
22 tcompTYPE_LZX = 0x0003 // LZX
23
24 CB_MAX_FILENAME = 256
25 CB_MAX_CABINET_NAME = 256
26 CB_MAX_CAB_PATH = 256
27 CB_MAX_DISK_NAME = 256
28 FOLDER_THRESHOLD = 1000000 // 900000
29
30 // Level
31 LZX_HI = 0
32 LZX_NORMAL = 1
33 LZX_LOW = 2
34
35 FCIERR_NONE = 0
36 FCIERR_OPEN_SRC
37 FCIERR_READ_SRC
38 FCIERR_ALLOC_FAIL
39 FCIERR_TEMP_FILE
40 FCIERR_BAD_COMPR_TYPE
41 FCIERR_CAB_FILE
42 FCIERR_USER_ABORT
43 FCIERR_MCI_FAIL
44
45 }
46
47 type CCAB {
48 // LONG
49 uint cb // size available for cabinet on this media
50 uint cbFolderThresh // Thresshold for forcing a new Folder
51 // UINT
52 uint cbReserveCFHeader // Space to reserve in CFHEADER
53 uint cbReserveCFFolder // Space to reserve in CFFOLDER
54 uint cbReserveCFData // Space to reserve in CFDATA
55 int iCab // sequential numbers for cabinets
56 int iDisk // Disk number
57 //ifndef REMOVE_CHICAGO_M6_HACK
58 int fFailOnIncompressible // TRUE => Fail if a block is incompressible
59 //endif
60 ushort setID // Cabinet set ID
61
62 reserved szDisk[ $CB_MAX_DISK_NAME ] // current disk name
63 reserved szCab[ $CB_MAX_CABINET_NAME ] // current cabinet name
64 reserved szCabPath[ $CB_MAX_CAB_PATH ] // path for creating cabinet
65 }
66
67 type cabinit
68 {
69 uint volumesize
70 // uint flags
71 str disk
72 arrstr exclude
73 uint notify
74 uint level
75 }
76
77 method str str.gettempfile( str dir prefix )
78 {
79 random rnd
80
81 rnd.init()
82 rnd.randseed( 'A', 'Z' )
83 do
84 {
85 str name
86 uint i
87 fornum i, 6 : name.appendch( rnd.randseed() )
88 ( this = dir ).faddname( "\( prefix )\( name ).tmp" )
89 } while fileexist( this )
90
91 return this
92 }
93
94 func uint cab_gettempfile( uint ret, int length, uint pv )
95 {
96 str dir filename
97
98 gettempdir( dir )
99 filename.gettempfile( dir, "cab_" )
100 /* uint i
101 do
102 {
103 ( filename = dir ).faddname( "cab_\(i++).tmp" )
104 } while fileexist( filename )*/
105 if ( *filename + 1 ) < length
106 {
107 mcopy( ret, filename.ptr(), *filename + 1 )
108 return 1
109 }
110 return 0
111 }
112
113 // -----------------------------------------------------------------
114
115 func cab_error( cabinfo cabi, str prefix )
116 {
117 str strerr
118
119 switch cabi.erf.erfOper
120 {
121 case $FCIERR_NONE : strerr = "No error"
122 case $FCIERR_OPEN_SRC: strerr = "Failure opening file to be stored in cabinet"
123 case $FCIERR_READ_SRC: strerr = "Failure reading file to be stored in cabinet"
124 case $FCIERR_ALLOC_FAIL: strerr = "Insufficient memory in FCI"
125 case $FCIERR_TEMP_FILE: strerr = "Could not create a temporary file"
126 case $FCIERR_BAD_COMPR_TYPE: strerr = "Unknown compression type"
127 case $FCIERR_CAB_FILE: strerr = "Could not create cabinet file"
128 case $FCIERR_USER_ABORT: strerr = "Client requested abort"
129 case $FCIERR_MCI_FAIL: strerr = "Failure compressing data"
130 default : strerr = "Unknown error"
131 }
132 cabi.fncnotify->func( $FLN_ERROR,
133 "\(prefix) failed: \(cabi.erf.erfOper) [\(strerr)]", cabi )
134 }
135
136 func uint cab_notify( uint code, str param, cabinfo cabi )
137 {
138 return 0
139 }
140
141 func uint cab_sysnotify( uint code, uint param, cabinfo cabi )
142 {
143 str stemp
144
145 stemp.copy( param )
146 return cabi.fncnotify->func( code, stemp, cabi )
147 }
148
149 // -----------------------------------------------------------------
150
151 func uint cab_create( str cabfile, arrstr files, arr flags of uint, cabinit cabini )
152 {
153 CCAB ccab
154 cabinfo cabi
155 str stemp pattern ext
156 uint hfci ret
157 uint i
158 arrstr exeext = %{ "exe", "dll" }
159
160 if !cabini.volumesize : cabini.volumesize = 0xFFFFFFF
161
162 cabi.finish = 0
163 cabi.cabsize = 0
164 cabi.filesize = 0
165 cabi.call = gentee_ptr( 4 ); // GPTR_CALL
166
167 cabi.fnctempfile = &cab_gettempfile;
168
169 cabi.fncnotify = cabini.notify;
170 if !cabi.fncnotify : cabi.fncnotify = &cab_notify;
171 cabi.fncsysnotify = &cab_sysnotify;
172
173 callback( &cab_gettempfile, 1 )
174
175 ccab.cb = cabini.volumesize
176 ccab.cbFolderThresh = $FOLDER_THRESHOLD
177 ccab.cbReserveCFHeader = 0
178 ccab.cbReserveCFFolder = 0
179 ccab.cbReserveCFData = 0
180 ccab.iCab = 1
181 ccab.iDisk = 0
182 ccab.setID = 777
183
184 switch cabini.level
185 {
186 case 2 : cabini.level = 15
187 case 1 : cabini.level = 18
188 default : cabini.level = 21
189 }
190 cabi.lztype = $tcompTYPE_LZX | ( cabini.level << 8 )
191
192 mcopy( &ccab.szDisk, cabini.disk.ptr(), *cabini.disk + 1 )
193 stemp.fnameext( cabfile )
194 mcopy( &ccab.szCab, stemp.ptr(), *stemp + 1 )
195 cabfile.fgetparts( stemp, pattern, ext )
196 stemp.fappendslash()
197 mcopy( &ccab.szCabPath, stemp.ptr(), *stemp + 1 )
198 pattern += "%i.\(ext)"
199
200 cabi.pattern = pattern.ptr()
201
202 if !( hfci = gcabe_create( &ccab, &cabi ))
203 {
204 cab_error( cabi, "FCICreate" )
205 goto end
206 }
207
208 filelist fl
209 str root folder
210
211 fl.addfiles( files, cabini.exclude, flags )
212 foreach curfl, fl
213 {
214 str fullname filename ext
215
216 switch curfl.itype
217 {
218 case $FL_FOLDER
219 {
220 folder = curfl.name
221 if !gcabe_flushfolder( hfci )
222 {
223 cab_error( cabi, "FCIFlushFolder" )
224 goto end
225 }
226 }
227 case $FL_ROOT : root = curfl.name
228 case $FL_FILE
229 {
230 (fullname = root ).faddname( folder ).faddname( curfl.name )
231 filename.copy( fullname.ptr() + *root + 1 )
232 cabi.fncnotify->func( $FLN_FILEBEGIN, fullname, cabi )
233 // ext = filename.fgetext()
234 if !gcabe_addfile( hfci, fullname.ptr(), filename.ptr(),
235 /*ext %== exeext[0] || ext %== exeext[1],*/ cabi )
236 {
237 cab_error( cabi, "FCIAddFile" )
238 goto end
239 }
240 cabi.fncnotify->func( $FLN_FILEEND, fullname, cabi )
241 }
242 }
243 }
244 cabi.finish = 1
245 if !gcabe_close( hfci )
246 {
247 cab_error( cabi, "FCIFlushCabinet" )
248 goto end
249 }
250 ret = 1
251 label end:
252 return ret
253 }
254