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 FDIERROR_NONE = 0
17 FDIERROR_CABINET_NOT_FOUND
18 FDIERROR_NOT_A_CABINET
19 FDIERROR_UNKNOWN_CABINET_VERSION
20 FDIERROR_CORRUPT_CABINET
21 FDIERROR_ALLOC_FAIL
22 FDIERROR_BAD_COMPR_TYPE
23 FDIERROR_MDI_FAIL
24 FDIERROR_TARGET_FILE
25 FDIERROR_RESERVE_MISMATCH
26 FDIERROR_WRONG_CABINET
27 FDIERROR_USER_ABORT
28 }
29
30 type FDINOTIFICATION
31 {
32 uint cb
33 uint psz1
34 uint psz2
35 uint psz3
36 uint pv
37 uint hf
38 ushort date
39 ushort time
40 ushort attribs
41 ushort setID
42 ushort iCabinet
43 ushort iFolder
44 uint fdie
45 }
46
47 type FDICABINETINFO
48 {
49 uint cbCabinet // Total length of cabinet file
50 ushort cFolders // Count of folders in cabinet
51 ushort cFiles // Count of files in cabinet
52 ushort setID // Cabinet set ID
53 ushort iCabinet // Cabinet number in set (0 based)
54 uint fReserve // TRUE => RESERVE present in cabinet
55 uint hasprev // TRUE => Cabinet is chained prev
56 uint hasnext // TRUE => Cabinet is chained next
57 }
58
59 type decabinfo
60 {
61 ERF erf
62 FDICABINETINFO fdic
63 uint call
64 uint islist
65 uint fncnotify
66 uint fncsysnotify
67 uint hf
68 str destfile
69 uint percent
70 uint cursize
71 uint fileinfo
72 str nextvolume
73 str destdir
74 uint param
75 }
76
77
78 func uint decab_notify( uint code, str param, decabinfo decab )
79 {
80 return 0
81 }
82
83 func uint decab_sysnotify( uint code, uint param, decabinfo decab )
84 {
85 str stemp
86 filetime lft
87 uint fdin
88
89 fdin as param->FDINOTIFICATION
90 switch code
91 {
92 case $FLN_NEXTVOLUME
93 {
94 if !*decab.nextvolume : decab.nextvolume.copy( fdin.psz1 )
95 }
96 case $FLN_FILEBEGIN
97 {
98 uint item
99
100 if decab.islist
101 {
102 uint files = decab.fileinfo
103 files as arr of finfo
104 item as files[ files.expand(1) ]
105 }
106 else : item = decab.fileinfo
107
108 item as finfo
109
110 item.fullname.copy( fdin.psz1 )
111 item.name.fnameext( item.fullname )
112 item.attrib = fdin.attribs
113 item.sizelo = fdin.cb
114 DosDateTimeToFileTime( fdin.date, fdin.time, lft )
115 LocalFileTimeToFileTime( lft, item.lastwrite )
116 if decab.islist : return 0
117 ( decab.destfile = decab.destdir ).faddname( item.fullname )
118 return decab.fncnotify->func( $FLN_FILEBEGIN, decab.destfile, decab )
119 }
120 case $FLN_FILEEND
121 {
122 file fi
123
124 setattribnormal( decab.destfile )
125 fi.open( decab.destfile, 0 )
126 fi.settime( decab.fileinfo->finfo.lastwrite )
127 fi.close()
128 setfileattrib( decab.destfile, fdin.attribs )
129 decab.fncnotify->func( $FLN_FILEEND, decab.destfile, decab )
130 return 1
131 }
132 default : stemp.copy( param )
133 }
134 return decab.fncnotify->func( code, stemp, decab )
135 }
136
137
138 func decab_error( decabinfo decab, str prefix )
139 {
140 str strerr
141
142 switch decab.erf.erfOper
143 {
144 case $FDIERROR_NONE: strerr = "No error"
145 case $FDIERROR_CABINET_NOT_FOUND: strerr = "Cabinet not found"
146 case $FDIERROR_NOT_A_CABINET: strerr = "Not a cabinet"
147 case $FDIERROR_UNKNOWN_CABINET_VERSION: strerr = "Unknown cabinet version"
148 case $FDIERROR_CORRUPT_CABINET: strerr = "Corrupt cabinet"
149 case $FDIERROR_ALLOC_FAIL: strerr = "Memory allocation failed"
150 case $FDIERROR_BAD_COMPR_TYPE: strerr = "Unknown compression type"
151 case $FDIERROR_MDI_FAIL: strerr = "Failure decompressing data"
152 case $FDIERROR_TARGET_FILE: strerr = "Failure writing to target file"
153 case $FDIERROR_RESERVE_MISMATCH
154 {
155 strerr = "Cabinets in set have different RESERVE sizes"
156 }
157 case $FDIERROR_WRONG_CABINET
158 {
159 strerr = "Cabinet strerr = ed on fdintNEXT_CABINET is incorrect"
160 }
161 case $FDIERROR_USER_ABORT: strerr = "User aborted"
162 default : strerr = "Unknown error"
163 }
164 decab.fncnotify->func( $FLN_ERROR,
165 "\(prefix) failed: \(decab.erf.erfOper) [\(strerr)]", decab )
166 }
167
168 func uint cab_decodeinit( str cabfile, decabinfo decab )
169 {
170 uint hfdi ret
171 str path name
172
173 decab.fncsysnotify = &decab_sysnotify;
174 decab.call = gentee_ptr( 4 ); // GPTR_CALL
175
176 if !( hfdi = gcabd_create( &decab ))
177 {
178 decab_error( decab, "FDICreate" )
179 return 0
180 }
181 if !gcabd_iscabinet( hfdi, cabfile.ptr(), &decab )
182 {
183 decab.fncnotify->func( $FLN_NOTVALID, cabfile, decab )
184 goto end
185 }
186 path.fgetdir( cabfile ).fappendslash()
187 name.fnameext( cabfile )
188 do
189 {
190 if !gcabd_copy( hfdi, name.ptr(), path.ptr(), &decab )
191 {
192 decab_error( decab, "FDICopy" )
193 goto end
194 }
195 name = decab.nextvolume
196 decab.nextvolume.clear()
197 } while *name
198 ret = 1
199 label end
200 gcabd_destroy( hfdi )
201 return ret
202 }
203
204
205 func uint cab_list( str cabfile, arr files of finfo, uint notify )
206 {
207 decabinfo decab
208
209 decab.fncnotify = ?( notify, notify, &decab_notify )
210 decab.islist = 1
211 decab.fileinfo = &files
212
213 return cab_decodeinit( cabfile, decab )
214 }
215
216 func uint cab_decode( str cabfile destdir, uint notify param )
217 {
218 decabinfo decab
219 finfo fi
220
221 decab.destdir = destdir
222 decab.fileinfo = &fi
223 decab.param = param
224 decab.fncnotify = ?( notify, notify, &decab_notify )
225
226 return cab_decodeinit( cabfile, decab )
227 }
228
229 func uint cab_decode( str cabfile destdir, uint notify )
230 {
231 return cab_decode( cabfile, destdir, notify, 0 )
232 }