Release 961102
[wine/hacks.git] / misc / ver.c
blobc53ba8534e2527e0e90c9fe13a31907fcc61b0eb
1 /*
2 * Implementation of VER.DLL
3 *
4 * Copyright 1996 Marcus Meissner
5 */
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <ctype.h>
11 #include "windows.h"
12 #include "win.h"
13 #include "winerror.h"
14 #include "ver.h"
15 #include "lzexpand.h"
16 #include "module.h"
17 #include "neexe.h"
18 #include "stddebug.h"
19 #include "debug.h"
20 #include "xmalloc.h"
21 #include "winreg.h"
22 #include "string32.h"
24 #define LZREAD(what) \
25 if (sizeof(*what)!=LZRead32(lzfd,what,sizeof(*what))) return 0;
26 #define LZTELL(lzfd) LZSeek(lzfd, 0, SEEK_CUR);
28 #define strdupW2A(x) STRING32_DupUniToAnsi(x)
29 #define strdupA2W(x) STRING32_DupAnsiToUni(x)
31 int
32 read_ne_header(HFILE lzfd,struct ne_header_s *nehd) {
33 struct mz_header_s mzh;
35 LZSeek(lzfd,0,SEEK_SET);
36 if (sizeof(mzh)!=LZRead32(lzfd,&mzh,sizeof(mzh)))
37 return 0;
38 if (mzh.mz_magic!=MZ_SIGNATURE)
39 return 0;
40 LZSeek(lzfd,mzh.ne_offset,SEEK_SET);
41 LZREAD(nehd);
42 if (nehd->ne_magic == NE_SIGNATURE) {
43 LZSeek(lzfd,mzh.ne_offset,SEEK_SET);
44 return 1;
46 /* must handle PE files too. Later. */
47 return 0;
51 int
52 find_ne_resource(
53 HFILE lzfd,struct ne_header_s *nehd,SEGPTR typeid,SEGPTR resid,
54 BYTE **resdata,int *reslen,DWORD *off
55 ) {
56 NE_TYPEINFO ti;
57 NE_NAMEINFO ni;
58 int i;
59 WORD shiftcount;
60 DWORD nehdoffset;
62 nehdoffset = LZTELL(lzfd);
63 LZSeek(lzfd,nehd->resource_tab_offset,SEEK_CUR);
64 LZREAD(&shiftcount);
65 dprintf_ver(stddeb,"shiftcount is %d\n",shiftcount);
66 dprintf_ver(stddeb,"reading resource typeinfo dir.\n");
68 if (!HIWORD(typeid)) typeid = (SEGPTR)(LOWORD(typeid) | 0x8000);
69 if (!HIWORD(resid)) resid = (SEGPTR)(LOWORD(resid) | 0x8000);
70 while (1) {
71 int skipflag;
73 LZREAD(&ti);
74 if (!ti.type_id)
75 return 0;
76 dprintf_ver(stddeb," ti.typeid =%04x,count=%d\n",ti.type_id,ti.count);
77 skipflag=0;
78 if (!HIWORD(typeid)) {
79 if ((ti.type_id&0x8000)&&(typeid!=ti.type_id))
80 skipflag=1;
81 } else {
82 if (ti.type_id & 0x8000) {
83 skipflag=1;
84 } else {
85 BYTE len;
86 char *str;
87 DWORD whereleft;
89 whereleft = LZTELL(lzfd);
90 LZSeek(
91 lzfd,
92 nehdoffset+nehd->resource_tab_offset+ti.type_id,
93 SEEK_SET
95 LZREAD(&len);
96 str=xmalloc(len);
97 if (len!=LZRead32(lzfd,str,len))
98 return 0;
99 dprintf_ver(stddeb,"read %s to compare it with %s\n",
100 str,(char*)PTR_SEG_TO_LIN(typeid)
102 if (lstrcmpi32A(str,(char*)PTR_SEG_TO_LIN(typeid)))
103 skipflag=1;
104 free(str);
105 LZSeek(lzfd,whereleft,SEEK_SET);
108 if (skipflag) {
109 LZSeek(lzfd,ti.count*sizeof(ni),SEEK_CUR);
110 continue;
112 for (i=0;i<ti.count;i++) {
113 WORD *rdata;
114 int len;
116 LZREAD(&ni);
117 dprintf_ver(stddeb," ni.id=%4x,offset=%d,length=%d\n",
118 ni.id,ni.offset,ni.length
120 skipflag=1;
121 if (!HIWORD(resid)) {
122 if (ni.id == resid)
123 skipflag=0;
124 } else {
125 if (!(ni.id & 0x8000)) {
126 BYTE len;
127 char *str;
128 DWORD whereleft;
130 whereleft = LZTELL(lzfd);
131 LZSeek(
132 lzfd,
133 nehdoffset+nehd->resource_tab_offset+ni.id,
134 SEEK_SET
136 LZREAD(&len);
137 str=xmalloc(len);
138 if (len!=LZRead32(lzfd,str,len))
139 return 0;
140 dprintf_ver(stddeb,"read %s to compare it with %s\n",
141 str,(char*)PTR_SEG_TO_LIN(typeid)
143 if (!lstrcmpi32A(str,(char*)PTR_SEG_TO_LIN(typeid)))
144 skipflag=0;
145 free(str);
146 LZSeek(lzfd,whereleft,SEEK_SET);
149 if (skipflag)
150 continue;
151 LZSeek(lzfd,((int)ni.offset<<shiftcount),SEEK_SET);
152 *off = (int)ni.offset<<shiftcount;
153 len = ni.length<<shiftcount;
154 rdata=(WORD*)xmalloc(len);
155 if (len!=LZRead32(lzfd,rdata,len)) {
156 free(rdata);
157 return 0;
159 dprintf_ver(stddeb,"resource found.\n");
160 *resdata= (BYTE*)rdata;
161 *reslen = len;
162 return 1;
167 /* GetFileResourceSize [VER.2] */
168 DWORD
169 GetFileResourceSize(LPCSTR filename,SEGPTR restype,SEGPTR resid,LPDWORD off) {
170 HFILE lzfd;
171 OFSTRUCT ofs;
172 BYTE *resdata;
173 int reslen;
174 struct ne_header_s nehd;
176 dprintf_ver(stddeb,"GetFileResourceSize(%s,%lx,%lx,%p)\n",
177 filename,(LONG)restype,(LONG)resid,off
179 lzfd=LZOpenFile16(filename,&ofs,OF_READ);
180 if (lzfd==0)
181 return 0;
182 if (!read_ne_header(lzfd,&nehd)) {
183 LZClose(lzfd);
184 return 0;
186 if (!find_ne_resource(lzfd,&nehd,restype,resid,&resdata,&reslen,off)) {
187 LZClose(lzfd);
188 return 0;
190 free(resdata);
191 LZClose(lzfd);
192 return reslen;
195 /* GetFileResource [VER.3] */
196 DWORD
197 GetFileResource(LPCSTR filename,SEGPTR restype,SEGPTR resid,
198 DWORD off,DWORD datalen,LPVOID data
200 HFILE lzfd;
201 OFSTRUCT ofs;
202 BYTE *resdata;
203 int reslen=datalen;
204 struct ne_header_s nehd;
205 dprintf_ver(stddeb,"GetFileResource(%s,%lx,%lx,%ld,%ld,%p)\n",
206 filename,(LONG)restype,(LONG)resid,off,datalen,data
209 lzfd=LZOpenFile16(filename,&ofs,OF_READ);
210 if (lzfd==0)
211 return 0;
212 if (!off) {
213 if (!read_ne_header(lzfd,&nehd)) {
214 LZClose(lzfd);
215 return 0;
217 if (!find_ne_resource(lzfd,&nehd,restype,resid,&resdata,&reslen,&off)) {
218 LZClose(lzfd);
219 return 0;
221 free(resdata);
223 LZSeek(lzfd,off,SEEK_SET);
224 if (reslen>datalen)
225 reslen=datalen;
226 LZRead32(lzfd,data,reslen);
227 LZClose(lzfd);
228 return reslen;
231 /* GetFileVersionInfoSize [VER.6] */
232 DWORD
233 GetFileVersionInfoSize16(LPCSTR filename,LPDWORD handle) {
234 DWORD len,ret;
235 BYTE buf[72];
236 VS_FIXEDFILEINFO *vffi;
238 dprintf_ver(stddeb,"GetFileVersionInfoSize16(%s,%p)\n",filename,handle);
239 len=GetFileResourceSize(filename,VS_FILE_INFO,VS_VERSION_INFO,handle);
240 if (!len)
241 return 0;
242 ret=GetFileResource(
243 filename,VS_FILE_INFO,VS_VERSION_INFO,*handle,sizeof(buf),buf
245 if (!ret)
246 return 0;
248 vffi=(VS_FIXEDFILEINFO*)(buf+0x14);
249 if (vffi->dwSignature != VS_FFI_SIGNATURE)
250 return 0;
251 if (*(WORD*)buf < len)
252 len = *(WORD*)buf;
253 dprintf_ver(stddeb,"->strucver=%ld.%ld,filever=%ld.%ld,productver=%ld.%ld,flagmask=%lx,flags=%lx,OS=",
254 (vffi->dwStrucVersion>>16),vffi->dwStrucVersion&0xFFFF,
255 vffi->dwFileVersionMS,vffi->dwFileVersionLS,
256 vffi->dwProductVersionMS,vffi->dwProductVersionLS,
257 vffi->dwFileFlagsMask,vffi->dwFileFlags
259 switch (vffi->dwFileOS&0xFFFF0000) {
260 case VOS_DOS:dprintf_ver(stddeb,"DOS,");break;
261 case VOS_OS216:dprintf_ver(stddeb,"OS/2-16,");break;
262 case VOS_OS232:dprintf_ver(stddeb,"OS/2-32,");break;
263 case VOS_NT:dprintf_ver(stddeb,"NT,");break;
264 case VOS_UNKNOWN:
265 default:
266 dprintf_ver(stddeb,"UNKNOWN(%ld),",vffi->dwFileOS&0xFFFF0000);break;
268 switch (vffi->dwFileOS & 0xFFFF) {
269 case VOS__BASE:dprintf_ver(stddeb,"BASE");break;
270 case VOS__WINDOWS16:dprintf_ver(stddeb,"WIN16");break;
271 case VOS__WINDOWS32:dprintf_ver(stddeb,"WIN32");break;
272 case VOS__PM16:dprintf_ver(stddeb,"PM16");break;
273 case VOS__PM32:dprintf_ver(stddeb,"PM32");break;
274 default:dprintf_ver(stddeb,"UNKNOWN(%ld)",vffi->dwFileOS&0xFFFF);break;
276 switch (vffi->dwFileType) {
277 default:
278 case VFT_UNKNOWN:
279 dprintf_ver(stddeb,"filetype=Unknown(%ld)",vffi->dwFileType);
280 break;
281 case VFT_APP:dprintf_ver(stddeb,"filetype=APP");break;
282 case VFT_DLL:dprintf_ver(stddeb,"filetype=DLL");break;
283 case VFT_DRV:
284 dprintf_ver(stddeb,"filetype=DRV,");
285 switch(vffi->dwFileSubtype) {
286 default:
287 case VFT2_UNKNOWN:
288 dprintf_ver(stddeb,"UNKNOWN(%ld)",vffi->dwFileSubtype);
289 break;
290 case VFT2_DRV_PRINTER:
291 dprintf_ver(stddeb,"PRINTER");
292 break;
293 case VFT2_DRV_KEYBOARD:
294 dprintf_ver(stddeb,"KEYBOARD");
295 break;
296 case VFT2_DRV_LANGUAGE:
297 dprintf_ver(stddeb,"LANGUAGE");
298 break;
299 case VFT2_DRV_DISPLAY:
300 dprintf_ver(stddeb,"DISPLAY");
301 break;
302 case VFT2_DRV_MOUSE:
303 dprintf_ver(stddeb,"MOUSE");
304 break;
305 case VFT2_DRV_NETWORK:
306 dprintf_ver(stddeb,"NETWORK");
307 break;
308 case VFT2_DRV_SYSTEM:
309 dprintf_ver(stddeb,"SYSTEM");
310 break;
311 case VFT2_DRV_INSTALLABLE:
312 dprintf_ver(stddeb,"INSTALLABLE");
313 break;
314 case VFT2_DRV_SOUND:
315 dprintf_ver(stddeb,"SOUND");
316 break;
317 case VFT2_DRV_COMM:
318 dprintf_ver(stddeb,"COMM");
319 break;
320 case VFT2_DRV_INPUTMETHOD:
321 dprintf_ver(stddeb,"INPUTMETHOD");
322 break;
324 break;
325 case VFT_FONT:
326 dprintf_ver(stddeb,"filetype=FONT.");
327 switch (vffi->dwFileSubtype) {
328 default:
329 dprintf_ver(stddeb,"UNKNOWN(%ld)",vffi->dwFileSubtype);
330 break;
331 case VFT2_FONT_RASTER:dprintf_ver(stddeb,"RASTER");break;
332 case VFT2_FONT_VECTOR:dprintf_ver(stddeb,"VECTOR");break;
333 case VFT2_FONT_TRUETYPE:dprintf_ver(stddeb,"TRUETYPE");break;
335 break;
336 case VFT_VXD:dprintf_ver(stddeb,"filetype=VXD");break;
337 case VFT_STATIC_LIB:dprintf_ver(stddeb,"filetype=STATIC_LIB");break;
339 dprintf_ver(stddeb,"filedata=%lx.%lx\n",vffi->dwFileDateMS,vffi->dwFileDateLS);
340 return len;
343 /* GetFileVersionInfoSize32A [VERSION.1] */
344 DWORD
345 GetFileVersionInfoSize32A(LPCSTR filename,LPDWORD handle) {
346 dprintf_ver(stddeb,"GetFileVersionInfoSize32A(%s,%p)\n",filename,handle);
347 return GetFileVersionInfoSize16(filename,handle);
350 /* GetFileVersionInfoSize32W [VERSION.2] */
351 DWORD
352 GetFileVersionInfoSize32W(LPCWSTR filename,LPDWORD handle) {
353 LPSTR xfn;
354 DWORD ret;
356 xfn = strdupW2A(filename);
357 ret=GetFileVersionInfoSize16(xfn,handle);
358 free(xfn);
359 return ret;
362 /* GetFileVersionInfo [VER.7] */
363 DWORD
364 GetFileVersionInfo16(LPCSTR filename,DWORD handle,DWORD datasize,LPVOID data) {
365 dprintf_ver(stddeb,"GetFileVersionInfo16(%s,%ld,%ld,%p)\n->",
366 filename,handle,datasize,data
368 return GetFileResource(
369 filename,VS_FILE_INFO,VS_VERSION_INFO,handle,datasize,data
373 /* GetFileVersionInfoA [VERSION.0] */
374 DWORD
375 GetFileVersionInfo32A(LPCSTR filename,DWORD handle,DWORD datasize,LPVOID data) {
376 return GetFileVersionInfo16(filename,handle,datasize,data);
379 /* GetFileVersionInfoW [VERSION.3] */
380 DWORD
381 GetFileVersionInfo32W(LPCWSTR filename,DWORD handle,DWORD datasize,LPVOID data){
382 DWORD ret;
383 LPSTR fn;
385 fn = strdupW2A(filename);
386 ret = GetFileVersionInfo16(fn,handle,datasize,data);
387 free(fn);
388 return ret;
391 /* VerFindFile [VER.8] */
392 DWORD
393 VerFindFile16(
394 UINT16 flags,LPCSTR filename,LPCSTR windir,LPCSTR appdir,
395 LPSTR curdir,UINT16 *curdirlen,LPSTR destdir,UINT16 *destdirlen
397 dprintf_ver(stddeb,"VerFindFile(%x,%s,%s,%s,%p,%d,%p,%d)\n",
398 flags,filename,windir,appdir,curdir,*curdirlen,destdir,*destdirlen
400 strcpy(curdir,"Z:\\ROOT\\.WINE\\");/*FIXME*/
401 *curdirlen=strlen(curdir);
402 strcpy(destdir,"Z:\\ROOT\\.WINE\\");/*FIXME*/
403 *destdirlen=strlen(destdir);
404 return 0;
407 /* VerFindFileA [VERSION.5] */
408 DWORD
409 VerFindFile32A(
410 UINT32 flags,LPCSTR filename,LPCSTR windir,LPCSTR appdir,
411 LPSTR curdir,UINT32 *pcurdirlen,LPSTR destdir,UINT32 *pdestdirlen )
413 UINT16 curdirlen, destdirlen;
414 DWORD ret = VerFindFile16(flags,filename,windir,appdir,
415 curdir,&curdirlen,destdir,&destdirlen);
416 *pcurdirlen = curdirlen;
417 *pdestdirlen = destdirlen;
418 return ret;
421 /* VerFindFileW [VERSION.6] */
422 DWORD
423 VerFindFile32W(
424 UINT32 flags,LPCWSTR filename,LPCWSTR windir,LPCWSTR appdir,
425 LPWSTR curdir,UINT32 *pcurdirlen,LPWSTR destdir,UINT32 *pdestdirlen )
427 UINT16 curdirlen, destdirlen;
428 LPSTR wfn,wwd,wad,wdd,wcd;
429 DWORD ret;
431 wfn = strdupW2A(filename);
432 wwd = strdupW2A(windir);
433 wad = strdupW2A(appdir);
434 wcd = (LPSTR)malloc(*pcurdirlen);
435 wdd = (LPSTR)malloc(*pdestdirlen);
436 ret=VerFindFile16(flags,wfn,wwd,wad,wcd,&curdirlen,wdd,&destdirlen);
437 STRING32_AnsiToUni(curdir,wcd);
438 STRING32_AnsiToUni(destdir,wdd);
439 *pcurdirlen = strlen(wcd);
440 *pdestdirlen = strlen(wdd);
441 return ret;
444 /* VerInstallFile [VER.9] */
445 DWORD
446 VerInstallFile16(
447 UINT16 flags,LPCSTR srcfilename,LPCSTR destfilename,LPCSTR srcdir,
448 LPCSTR destdir,LPSTR tmpfile,UINT16 *tmpfilelen
450 dprintf_ver(stddeb,"VerInstallFile(%x,%s,%s,%s,%s,%p,%d)\n",
451 flags,srcfilename,destfilename,srcdir,destdir,tmpfile,*tmpfilelen
454 /* FIXME: Implementation still missing .... */
456 return VIF_SRCOLD;
459 /* VerFindFileA [VERSION.5] */
460 DWORD
461 VerInstallFile32A(
462 UINT32 flags,LPCSTR srcfilename,LPCSTR destfilename,LPCSTR srcdir,
463 LPCSTR destdir,LPSTR tmpfile,UINT32 *tmpfilelen )
465 UINT16 filelen;
466 DWORD ret= VerInstallFile16(flags,srcfilename,destfilename,srcdir,
467 destdir,tmpfile,&filelen);
468 *tmpfilelen = filelen;
469 return ret;
472 /* VerFindFileW [VERSION.6] */
473 DWORD
474 VerInstallFile32W(
475 UINT32 flags,LPCWSTR srcfilename,LPCWSTR destfilename,LPCWSTR srcdir,
476 LPCWSTR destdir,LPWSTR tmpfile,UINT32 *tmpfilelen
478 LPSTR wsrcf,wsrcd,wdestf,wdestd,wtmpf;
479 DWORD ret;
481 wsrcf = strdupW2A(srcfilename);
482 wsrcd = strdupW2A(srcdir);
483 wdestf = strdupW2A(destfilename);
484 wdestd = strdupW2A(destdir);
485 wtmpf = strdupW2A(tmpfile);
486 ret=VerInstallFile32A(flags,wsrcf,wdestf,wsrcd,wdestd,wtmpf,tmpfilelen);
487 free(wsrcf);
488 free(wsrcd);
489 free(wdestf);
490 free(wdestd);
491 free(wtmpf);
492 return ret;
495 /* FIXME: This table should, of course, be language dependend */
496 static const struct map_id2str {
497 UINT langid;
498 const char *langname;
499 } languages[]={
500 {0x0401,"Arabisch"},
501 {0x0402,"Bulgarisch"},
502 {0x0403,"Katalanisch"},
503 {0x0404,"Traditionales Chinesisch"},
504 {0x0405,"Tschecisch"},
505 {0x0406,"Dänisch"},
506 {0x0407,"Deutsch"},
507 {0x0408,"Griechisch"},
508 {0x0409,"Amerikanisches Englisch"},
509 {0x040A,"Kastilisches Spanisch"},
510 {0x040B,"Finnisch"},
511 {0x040C,"Französisch"},
512 {0x040D,"Hebräisch"},
513 {0x040E,"Ungarisch"},
514 {0x040F,"Isländisch"},
515 {0x0410,"Italienisch"},
516 {0x0411,"Japanisch"},
517 {0x0412,"Koreanisch"},
518 {0x0413,"Niederländisch"},
519 {0x0414,"Norwegisch-Bokmal"},
520 {0x0415,"Polnisch"},
521 {0x0416,"Brasilianisches Portugiesisch"},
522 {0x0417,"Rätoromanisch"},
523 {0x0418,"Rumänisch"},
524 {0x0419,"Russisch"},
525 {0x041A,"Kroatoserbisch (lateinisch)"},
526 {0x041B,"Slowenisch"},
527 {0x041C,"Albanisch"},
528 {0x041D,"Schwedisch"},
529 {0x041E,"Thai"},
530 {0x041F,"Türkisch"},
531 {0x0420,"Urdu"},
532 {0x0421,"Bahasa"},
533 {0x0804,"Vereinfachtes Chinesisch"},
534 {0x0807,"Schweizerdeutsch"},
535 {0x0809,"Britisches Englisch"},
536 {0x080A,"Mexikanisches Spanisch"},
537 {0x080C,"Belgisches Französisch"},
538 {0x0810,"Schweizerisches Italienisch"},
539 {0x0813,"Belgisches Niederländisch"},
540 {0x0814,"Norgwegisch-Nynorsk"},
541 {0x0816,"Portugiesisch"},
542 {0x081A,"Serbokratisch (kyrillisch)"},
543 {0x0C1C,"Kanadisches Französisch"},
544 {0x100C,"Schweizerisches Französisch"},
545 {0x0000,"Unbekannt"},
548 /* VerLanguageName [VER.10] */
549 DWORD
550 VerLanguageName16(UINT16 langid,LPSTR langname,UINT16 langnamelen) {
551 int i;
552 char *buf;
554 dprintf_ver(stddeb,"VerLanguageName(%d,%p,%d)\n",langid,langname,langnamelen);
555 /* First, check \System\CurrentControlSet\control\Nls\Locale\<langid>
556 * from the registry.
558 buf=(char*)malloc(strlen("\\System\\CurrentControlSet\\control\\Nls\\Locale\\")+9);
559 sprintf(buf,"\\System\\CurrentControlSet\\control\\Nls\\Locale\\%08x",langid);
560 if (ERROR_SUCCESS==RegQueryValue16(HKEY_LOCAL_MACHINE,buf,langname,(LPDWORD)&langnamelen)) {
561 langname[langnamelen-1]='\0';
562 return langnamelen;
564 /* if that fails, use the interal table */
565 for (i=0;languages[i].langid!=0;i++)
566 if (langid==languages[i].langid)
567 break;
568 strncpy(langname,languages[i].langname,langnamelen);
569 langname[langnamelen-1]='\0';
570 return strlen(languages[i].langname);
573 /* VerLanguageNameA [VERSION.9] */
574 DWORD
575 VerLanguageName32A(UINT32 langid,LPSTR langname,UINT32 langnamelen) {
576 return VerLanguageName16(langid,langname,langnamelen);
579 /* VerLanguageNameW [VERSION.10] */
580 DWORD
581 VerLanguageName32W(UINT32 langid,LPWSTR langname,UINT32 langnamelen) {
582 int i;
583 char *buf;
584 LPWSTR keyname,result;
586 /* First, check \System\CurrentControlSet\control\Nls\Locale\<langid>
587 * from the registry.
589 buf=(char*)malloc(strlen("\\System\\CurrentControlSet\\control\\Nls\\Locale\\")+9);
590 sprintf(buf,"\\System\\CurrentControlSet\\control\\Nls\\Locale\\%08x",langid);
591 keyname=strdupA2W(buf);free(buf);
592 if (ERROR_SUCCESS==RegQueryValue32W(HKEY_LOCAL_MACHINE,keyname,langname,(LPDWORD)&langnamelen)) {
593 free(keyname);
594 return langnamelen;
596 free(keyname);
597 /* if that fails, use the interal table */
598 for (i=0;languages[i].langid!=0;i++)
599 if (langid==languages[i].langid)
600 break;
601 result=strdupA2W(languages[i].langname);
602 i=lstrlen32W(result)*sizeof(WCHAR);
603 if (i>langnamelen)
604 i=langnamelen;
605 memcpy(langname,result,i);
606 langname[langnamelen-1]='\0';
607 free(result);
608 return strlen(languages[i].langname); /* same as strlenW(result); */
611 /* FIXME: UNICODE? */
612 struct db {
613 WORD nextoff;
614 WORD datalen;
615 /* in memory structure... */
616 char name[1]; /* padded to dword alignment */
617 /* ....
618 char data[datalen]; padded to dword alignemnt
619 BYTE subdirdata[]; until nextoff
623 static BYTE*
624 _find_data(BYTE *block,LPCSTR str) {
625 char *nextslash;
626 int substrlen;
627 struct db *db;
629 while (*str && *str=='\\')
630 str++;
631 if (NULL!=(nextslash=strchr(str,'\\')))
632 substrlen=nextslash-str;
633 else
634 substrlen=strlen(str);
635 if (nextslash!=NULL) {
636 while (*nextslash && *nextslash=='\\')
637 nextslash++;
638 if (!*nextslash)
639 nextslash=NULL;
643 while (1) {
644 db=(struct db*)block;
645 dprintf_ver(stddeb,"db=%p,db->nextoff=%d,db->datalen=%d,db->name=%s,db->data=%s\n",
646 db,db->nextoff,db->datalen,db->name,(char*)((char*)db+4+((strlen(db->name)+4)&~3))
648 if (!db->nextoff)
649 return NULL;
651 dprintf_ver(stddeb,"comparing with %s\n",db->name);
652 if (!strncmp(db->name,str,substrlen)) {
653 if (nextslash)
654 return _find_data(
655 block+4+((strlen(db->name)+4)&~3)+((db->datalen+3)&~3)
656 ,nextslash
658 else
659 return block;
661 block=block+((db->nextoff+3)&~3);
665 /* VerQueryValue [VER.11] */
666 /* take care, 'buffer' is NOT a SEGPTR, it just points to one */
667 DWORD
668 VerQueryValue16(SEGPTR segblock,LPCSTR subblock,SEGPTR *buffer,UINT16 *buflen)
670 BYTE *block=PTR_SEG_TO_LIN(segblock),*b;
671 struct db *db;
672 char *s;
674 dprintf_ver(stddeb,"VerQueryValue16(%p,%s,%p,%d)\n",
675 block,subblock,buffer,*buflen
677 s=(char*)xmalloc(strlen("VS_VERSION_INFO")+strlen(subblock)+1);
678 strcpy(s,"VS_VERSION_INFO");strcat(s,subblock);
679 b=_find_data(block,s);
680 if (b==NULL) {
681 *buflen=0;
682 return 0;
684 db=(struct db*)b;
685 *buflen = db->datalen;
686 /* let b point to data area */
687 b = b+4+((strlen(db->name)+4)&~3);
688 /* now look up what the resp. SEGPTR would be ... */
689 *buffer = (b-block)+segblock;
690 dprintf_ver(stddeb," -> %s=%s\n",subblock,b);
691 return 1;
694 DWORD
695 VerQueryValue32A(LPVOID vblock,LPCSTR subblock,LPVOID *vbuffer,UINT32 *buflen)
697 BYTE *b,*block=(LPBYTE)vblock,**buffer=(LPBYTE*)vbuffer;
698 struct db *db;
699 char *s;
701 dprintf_ver(stddeb,"VerQueryValue32A(%p,%s,%p,%d)\n",
702 block,subblock,buffer,*buflen
704 s=(char*)xmalloc(strlen("VS_VERSION_INFO")+strlen(subblock)+1);
705 strcpy(s,"VS_VERSION_INFO");strcat(s,subblock);
706 b=_find_data(block,s);
707 if (b==NULL) {
708 *buflen=0;
709 return 0;
711 db=(struct db*)b;
712 *buflen = db->datalen;
713 /* let b point to data area */
714 b = b+4+((strlen(db->name)+4)&~3);
715 *buffer = b;
716 dprintf_ver(stddeb," -> %s=%s\n",subblock,b);
717 return 1;
720 DWORD
721 VerQueryValue32W(LPVOID vblock,LPCWSTR subblock,LPVOID *vbuffer,UINT32 *buflen)
723 /* FIXME: hmm, we not only need to convert subblock, but also
724 * the content...or?
725 * And what about UNICODE version info?
726 * And the NAMES of the values?
728 BYTE *b,**buffer=(LPBYTE*)vbuffer,*block=(LPBYTE)vblock;
729 struct db *db;
730 char *s,*sb;
732 sb=strdupW2A(subblock);
733 s=(char*)xmalloc(strlen("VS_VERSION_INFO")+strlen(sb)+1);
734 strcpy(s,"VS_VERSION_INFO");strcat(s,sb);
735 b=_find_data(block,s);
736 if (b==NULL) {
737 *buflen=0;
738 free(sb);
739 return 0;
741 db=(struct db*)b;
742 *buflen = db->datalen;
743 /* let b point to data area */
744 b = b+4+((strlen(db->name)+4)&~3);
745 *buffer = b;
746 dprintf_ver(stddeb," -> %s=%s\n",sb,b);
747 free(sb);
748 return 1;
750 /* 20 GETFILEVERSIONINFORAW */