1 /******************************************************************************
2 *
3 * Copyright (C) 2004-2007, 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 * ID: res 15.08.07 0.0.A.
11 *
12 * Author: Alexey Krivonogov ( gentee )
13 *
14 ******************************************************************************/
15
16 type reshead32 {
17 uint ressize
18 uint hdrsize
19 ushort restypeid
20 ushort restype
21 ushort resnameid
22 ushort resname
23 uint dversion
24 ushort memflag
25 ushort lang
26 uint version
27 uint characts
28 }
29
30 type res
31 {
32 buf data
33 uint iconid // Последний занятый номер для иконок
34 uint ismanifest // Есть или нет манифест
35 uint flags
36 uint owner // Linker
37 }
38
39 include : "ico.g"
40
41 define
42 {
43 // Memory/ flags
44 RCF_MOVEABLE = 0x0010
45 RCF_PURE = 0x0020
46 RCF_PRELOAD = 0x0040
47 RCF_DISCARDABLE = 0x1000
48
49 // Resource type IDs
50 RC_CURSOR = 1
51 RC_BITMAP = 2
52 RC_ICON = 3
53 RC_MENU = 4
54 RC_DIALOG = 5
55 RC_STRING = 6
56 RC_FONTDIR = 7
57 RC_FONT = 8
58 RC_ACCELERATOR = 9
59 RC_RCDATA = 10
60 RC_MESSAGETABLE = 11
61 RC_GROUP_CURSOR = 12
62 RC_GROUP_ICON = 14
63 RC_VERSION = 16
64 RC_DLGINCLUDE = 17
65 RC_PLUGPLAY = 19
66 RC_VXD = 20
67 RC_ANICURSOR = 21
68 RC_ANIICON = 22
69 RC_MANIFEST = 24
70 RC_DLGINIT = 240
71 RC_TOOLBAR = 241
72 RC_BITMAPNEW = 0x2002
73 RC_MENUNEW = 0x2004
74 RC_DIALOGNEW = 0x2005
75
76 CP_ACP = 0 // default to ANSI code page
77 CP_OEMCP = 1 // default to OEM code page
78 MB_PRECOMPOSED = 0x00000001 // use precomposed chars
79 }
80
81 method res res.init
82 {
83 // Добавляем пустой reshead32
84 this.data = '\h4 0 20 ffff ffff 0 0 0 0'
85 return this
86 }
87
88 method res.error( uint code, str param )
89 {
90 if this.owner : this.owner->linker.errfunc->func( code, param )
91 else : exit( 0 )
92 /* print( "Resource error: \(msgtext)\nPress any key..." )
93 getch()
94 exit( 0 )*/
95 }
96
97 method res.nfy( uint code, str param )
98 {
99 if this.owner : this.owner->linker.nfy( code, param )
100 }
101
102 method res.addresource( uint typeres, str name, buf data )
103 {
104 buf uname
105 uint headsize
106
107 if name[0] > '9' // Указано имя ресурса
108 {
109 uname.expand( 128 )
110 // Переводим в Unicode
111 uname.use = MultiByteToWideChar( $CP_ACP, $MB_PRECOMPOSED,
112 name.ptr(), 0xFFFFFFFF, uname.ptr(), 64 ) * 2
113 uname.align()
114 }
115 this.data += *data
116 if *uname
117 {
118 this.data += sizeof( reshead32 ) + *uname - 4
119 /* - 4 Включенный размер reshead32 resnameid resname */
120 }
121 else : this.data += sizeof( reshead32 )
122
123 this.data += ushort( 0xFFFF )
124 this.data += ushort( typeres )
125
126 if *uname
127 {
128 this.data += uname
129 }
130 else
131 {
132 this.data += ushort( 0xFFFF )
133 this.data += ushort( uint( name ))
134 }
135 this.data += '\h4 0 4090000 0 0'
136 this.data += data
137 this.data.align()
138 }
139
140 method uint res.addicon( str idname iconfile )
141 {
142 uint i
143 buf groupicon
144 arr icons of iconinfo
145
146 if !geticoninfo( iconfile, icons ) : return 0
147 groupicon += ushort( 0 )
148 groupicon += ushort( 1 )
149 groupicon += ushort( *icons )
150 fornum i, *icons
151 {
152 uint idir
153 idir as icons[i].icondir
154
155 this.addresource( $RC_ICON, str( ++this.iconid ), icons[i].data )
156 groupicon += byte( idir.bWidth )
157 groupicon += byte( idir.bHeight )
158 groupicon += byte( idir.bColorCount )
159 groupicon += byte( 0)
160 groupicon += ushort( idir.wPlanes )
161 groupicon += ushort( idir.wBitCount )
162 groupicon += idir.dwBytesInRes
163 groupicon += ushort( this.iconid )
164 }
165 this.addresource( $RC_GROUP_ICON, idname, groupicon )
166 return 1
167 }
168
169 method uint res.addmanifest( str name )
170 {
171 str manifest access level
172
173 access = ?( this.flags & $RES_ACCESS, "true", "false" )
174 level = ?( this.flags & $RES_ADMIN, "requireAdministrator", "asInvoker" )
175
176 manifest = "\[..]<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assemblyIdentity version="1.0.0.0" name="[..]\(name)\[..]" processorArchitecture="*" type="win32"/> <dependency> <dependentAssembly> <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" language="*" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" /> </dependentAssembly> </dependency>
177 <description>Description</description>
178 <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
179 <security>
180 <requestedPrivileges>
181 <requestedExecutionLevel
182 level="[..]\(level)\[..]"
183 uiAccess="[..]\(access)\[..]"/>
184 </requestedPrivileges>
185 </security>
186 </trustInfo>
187 </assembly>[..]"
188
189 /* <requestedExecutionLevel
190 level="requireAdministrator"
191 uiAccess="false"/>
192 </requestedPrivileges> */
193 manifest->buf.use--
194 this.addresource( $RC_MANIFEST, "1", manifest->buf )
195 this.ismanifest = 1
196 return 1
197 }
198
199 method uint res.addres( str filename )
200 {
201 buf newres
202 uint cur end reshead maxicon data
203
204 newres.read( filename )
205 if !*newres : return 0
206
207 end = newres.ptr() + *newres
208 cur = newres.ptr() + 0x20
209
210 while cur < end
211 {
212 reshead as cur->reshead32
213 if reshead.restypeid == 0xFFFF
214 {
215 switch reshead.restype
216 {
217 case $RC_ICON
218 {
219 if reshead.resnameid == 0xFFFF
220 {
221 reshead.resname += this.iconid
222 if maxicon < reshead.resname : maxicon = reshead.resname
223 }
224 }
225 case $RC_GROUP_ICON
226 {
227 uint count
228
229 data = cur + reshead.hdrsize + 4
230 count = data->ushort
231 data += 2
232 while count--
233 {
234 ( data + 12 )->ushort += this.iconid
235 data += 14
236 }
237 }
238 case $RC_MANIFEST
239 {
240 this.ismanifest = 1
241 }
242 }
243 }
244 // Переход на следующий элемент
245 cur += reshead.ressize + reshead.hdrsize
246 // Выравнивание
247 if ( cur - newres.ptr()) & 0x3 : cur += 4 - ( ( cur - newres.ptr()) & 0x3 )
248 }
249 this.data.append( newres.ptr() + 0x20, *newres - 0x20 )
250 this.data.align()
251 if maxicon : this.iconid = maxicon
252 return 1
253 }
254
255 method uint res.write( str filename )
256 {
257 return this.data.write( filename )
258 }
259
260 // Добавление иконок из проекта
261 method uint res.icons( arrstr icolist )
262 {
263 foreach curico, icolist
264 {
265 arrstr icons
266
267 curico.split( icons, ',', $SPLIT_FIRST | $SPLIT_NOSYS )
268 if *icons == 1
269 {
270 icons += icons[0]
271 icons[0] = "ICON_APP"
272 }
273 if !fileexist( icons[1] ) || !this.addicon( icons[0], icons[1] )
274 {
275 this.error( $RERR_LOADICON, icons[1] )
276 }
277 }
278 return 1
279 }
280
281 // Упаковка и добавление временных файлов
282 method res.temps( arrstr temps, str geaname )
283 {
284 uint i
285 geae egea
286 geaeinit geai
287 geacomp gc
288 str tempdir
289 buf btemp
290
291 if *geaname : goto readtemp
292
293 if !*temps : return
294
295 gc.compmethod = $GEA_LZGE
296 gc.order = 10
297 gc.solid = 0
298 geai.flags = $GEAI_IGNORECOPY
299 geai.userfunc = ?( this.owner, this.owner->linker.geafunc, 0 )
300
301 gettempdir( tempdir )
302 geaname = "\(tempdir)\\setup_temp.gea"
303 if !egea.create( geaname, geai )
304 {
305 this.error( $LERR_OPEN, geaname )
306 }
307 // print("qqq \(geaname)\n")
308 this.nfy( $LNFY_ADDTEMP, "temporary" )
309
310 fornum i, *temps
311 {
312 arrstr items
313
314 temps[i].split( items, ',', $SPLIT_FIRST | $SPLIT_NOSYS )
315 if *items != 2 : continue
316 // print("\(i)=\( temps[i] )\n")
317 gc.idgroup = uint( items[0] )
318 if !fileexist( items[1] ) || !egea.add( items[1], gc )
319 {
320 this.error( $RERR_PACK, items[1] )
321 }
322 }
323 egea.close()
324 label readtemp
325 btemp.read( geaname )
326 this.addresource( $RC_RCDATA, "SETUP_TEMP", btemp )
327 }
328
329 // Добавление файлов ресурсов
330 method res.resfiles( arrstr reslist )
331 {
332 foreach curres, reslist
333 {
334 if !fileexist( curres ) || !this.addres( curres )
335 {
336 this.error( $LERR_ADDRES, curres )
337 }
338 }
339 }