| /* |
| * Implementation of VER.DLL |
| * |
| * Copyright 1996,1997 Marcus Meissner |
| * Copyright 1997 David Cuthbert |
| */ |
| #include <stdlib.h> |
| #include <string.h> |
| #include <ctype.h> |
| #include <unistd.h> |
| #include "windows.h" |
| #include "win.h" |
| #include "winerror.h" |
| #include "heap.h" |
| #include "ver.h" |
| #include "lzexpand.h" |
| #include "module.h" |
| #include "neexe.h" |
| #include "debug.h" |
| #include "xmalloc.h" |
| #include "winreg.h" |
| |
| #define LZREAD(what) \ |
| if (sizeof(*what)!=LZRead32(lzfd,what,sizeof(*what))) return 0; |
| #define LZTELL(lzfd) LZSeek32(lzfd, 0, SEEK_CUR); |
| |
| /****************************************************************************** |
| * |
| * void ver_dstring( |
| * char const * prologue, |
| * char const * teststring, |
| * char const * epilogue ) |
| * |
| * This function will print via dprintf[_]ver to stddeb the prologue string, |
| * followed by the address of teststring and the string it contains if |
| * teststring is non-null or "(null)" otherwise, and then the epilogue |
| * string followed by a new line. |
| * |
| * Revision history |
| * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu) |
| * Original implementation as dprintf[_]ver_string |
| * 05-Jul-1997 Dave Cuthbert (dacut@ece.cmu.edu) |
| * Fixed problem that caused bug with tools/make_debug -- renaming |
| * this function should fix the problem. |
| * 15-Feb-1998 Dimitrie Paun (dimi@cs.toronto.edu) |
| * Modified it to make it print the message using only one |
| * dprintf[_]ver call. |
| * |
| *****************************************************************************/ |
| |
| static void ver_dstring( |
| char const * prologue, |
| char const * teststring, |
| char const * epilogue ) |
| { |
| TRACE(ver, "%s %p (\"%s\") %s\n", prologue, |
| (void const *) teststring, |
| teststring ? teststring : "(null)", |
| epilogue); |
| } |
| |
| /****************************************************************************** |
| * |
| * This function will print via dprintf[_]ver to stddeb debug info regarding |
| * the file info structure vffi. |
| * 15-Feb-1998 Dimitrie Paun (dimi@cs.toronto.edu) |
| * Added this function to clean up the code. |
| * |
| *****************************************************************************/ |
| static void print_vffi_debug(VS_FIXEDFILEINFO *vffi) |
| { |
| dbg_decl_str(ver, 1024); |
| |
| TRACE(ver," structversion=0x%lx.0x%lx, fileversion=0x%lx.0x%lx, productversion=0x%lx.0x%lx, flagmask=0x%lx, flags=%s%s%s%s%s%s\n", |
| (vffi->dwStrucVersion>>16),vffi->dwStrucVersion&0xFFFF, |
| vffi->dwFileVersionMS,vffi->dwFileVersionLS, |
| vffi->dwProductVersionMS,vffi->dwProductVersionLS, |
| vffi->dwFileFlagsMask, |
| (vffi->dwFileFlags & VS_FF_DEBUG) ? "DEBUG," : "", |
| (vffi->dwFileFlags & VS_FF_PRERELEASE) ? "PRERELEASE," : "", |
| (vffi->dwFileFlags & VS_FF_PATCHED) ? "PATCHED," : "", |
| (vffi->dwFileFlags & VS_FF_PRIVATEBUILD) ? "PRIVATEBUILD," : "", |
| (vffi->dwFileFlags & VS_FF_INFOINFERRED) ? "INFOINFERRED," : "", |
| (vffi->dwFileFlags & VS_FF_SPECIALBUILD) ? "SPECIALBUILD," : "" |
| ); |
| |
| dsprintf(ver," OS=0x%lx.0x%lx ", |
| (vffi->dwFileOS&0xFFFF0000)>>16, |
| vffi->dwFileOS&0x0000FFFF |
| ); |
| switch (vffi->dwFileOS&0xFFFF0000) { |
| case VOS_DOS:dsprintf(ver,"DOS,");break; |
| case VOS_OS216:dsprintf(ver,"OS/2-16,");break; |
| case VOS_OS232:dsprintf(ver,"OS/2-32,");break; |
| case VOS_NT:dsprintf(ver,"NT,");break; |
| case VOS_UNKNOWN: |
| default: |
| dsprintf(ver,"UNKNOWN(0x%lx),",vffi->dwFileOS&0xFFFF0000);break; |
| } |
| switch (vffi->dwFileOS & 0xFFFF) { |
| case VOS__BASE:dsprintf(ver,"BASE");break; |
| case VOS__WINDOWS16:dsprintf(ver,"WIN16");break; |
| case VOS__WINDOWS32:dsprintf(ver,"WIN32");break; |
| case VOS__PM16:dsprintf(ver,"PM16");break; |
| case VOS__PM32:dsprintf(ver,"PM32");break; |
| default:dsprintf(ver,"UNKNOWN(0x%lx)",vffi->dwFileOS&0xFFFF);break; |
| } |
| TRACE(ver, "(%s)\n", dbg_str(ver)); |
| |
| dbg_reset_str(ver); |
| switch (vffi->dwFileType) { |
| default: |
| case VFT_UNKNOWN: |
| dsprintf(ver,"filetype=Unknown(0x%lx)",vffi->dwFileType); |
| break; |
| case VFT_APP:dsprintf(ver,"filetype=APP,");break; |
| case VFT_DLL:dsprintf(ver,"filetype=DLL,");break; |
| case VFT_DRV: |
| dsprintf(ver,"filetype=DRV,"); |
| switch(vffi->dwFileSubtype) { |
| default: |
| case VFT2_UNKNOWN: |
| dsprintf(ver,"UNKNOWN(0x%lx)",vffi->dwFileSubtype); |
| break; |
| case VFT2_DRV_PRINTER: |
| dsprintf(ver,"PRINTER"); |
| break; |
| case VFT2_DRV_KEYBOARD: |
| dsprintf(ver,"KEYBOARD"); |
| break; |
| case VFT2_DRV_LANGUAGE: |
| dsprintf(ver,"LANGUAGE"); |
| break; |
| case VFT2_DRV_DISPLAY: |
| dsprintf(ver,"DISPLAY"); |
| break; |
| case VFT2_DRV_MOUSE: |
| dsprintf(ver,"MOUSE"); |
| break; |
| case VFT2_DRV_NETWORK: |
| dsprintf(ver,"NETWORK"); |
| break; |
| case VFT2_DRV_SYSTEM: |
| dsprintf(ver,"SYSTEM"); |
| break; |
| case VFT2_DRV_INSTALLABLE: |
| dsprintf(ver,"INSTALLABLE"); |
| break; |
| case VFT2_DRV_SOUND: |
| dsprintf(ver,"SOUND"); |
| break; |
| case VFT2_DRV_COMM: |
| dsprintf(ver,"COMM"); |
| break; |
| case VFT2_DRV_INPUTMETHOD: |
| dsprintf(ver,"INPUTMETHOD"); |
| break; |
| } |
| break; |
| case VFT_FONT: |
| dsprintf(ver,"filetype=FONT."); |
| switch (vffi->dwFileSubtype) { |
| default: |
| dsprintf(ver,"UNKNOWN(0x%lx)",vffi->dwFileSubtype); |
| break; |
| case VFT2_FONT_RASTER:dsprintf(ver,"RASTER");break; |
| case VFT2_FONT_VECTOR:dsprintf(ver,"VECTOR");break; |
| case VFT2_FONT_TRUETYPE:dsprintf(ver,"TRUETYPE");break; |
| } |
| break; |
| case VFT_VXD:dsprintf(ver,"filetype=VXD");break; |
| case VFT_STATIC_LIB:dsprintf(ver,"filetype=STATIC_LIB");break; |
| } |
| TRACE(ver, "%s\n", dbg_str(ver)); |
| |
| TRACE(ver, " filedata=0x%lx.0x%lx\n", |
| vffi->dwFileDateMS,vffi->dwFileDateLS); |
| } |
| |
| /****************************************************************************** |
| * |
| * int testFileExistence( |
| * char const * path, |
| * char const * file ) |
| * |
| * Tests whether a given path/file combination exists. If the file does |
| * not exist, the return value is zero. If it does exist, the return |
| * value is non-zero. |
| * |
| * Revision history |
| * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu) |
| * Original implementation |
| * |
| *****************************************************************************/ |
| |
| static int testFileExistence( |
| char const * path, |
| char const * file ) |
| { |
| char filename[1024]; |
| int filenamelen; |
| OFSTRUCT fileinfo; |
| int retval; |
| |
| fileinfo.cBytes = sizeof(OFSTRUCT); |
| |
| strcpy(filename, path); |
| filenamelen = strlen(filename); |
| |
| /* Add a trailing \ if necessary */ |
| if(filenamelen) { |
| if(filename[filenamelen - 1] != '\\') |
| strcat(filename, "\\"); |
| } |
| else /* specify the current directory */ |
| strcpy(filename, ".\\"); |
| |
| /* Create the full pathname */ |
| strcat(filename, file); |
| |
| if(OpenFile32(filename, &fileinfo, OF_EXIST) == HFILE_ERROR32) |
| retval = 0; |
| else |
| retval = 1; |
| |
| return retval; |
| } |
| |
| /****************************************************************************** |
| * |
| * int testFileExclusiveExistence( |
| * char const * path, |
| * char const * file ) |
| * |
| * Tests whether a given path/file combination exists and ensures that no |
| * other programs have handles to the given file. If the file does not |
| * exist or is open, the return value is zero. If it does exist, the |
| * return value is non-zero. |
| * |
| * Revision history |
| * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu) |
| * Original implementation |
| * |
| *****************************************************************************/ |
| |
| static int testFileExclusiveExistence( |
| char const * path, |
| char const * file ) |
| { |
| char filename[1024]; |
| int filenamelen; |
| OFSTRUCT fileinfo; |
| int retval; |
| |
| fileinfo.cBytes = sizeof(OFSTRUCT); |
| |
| strcpy(filename, path); |
| filenamelen = strlen(filename); |
| |
| /* Add a trailing \ if necessary */ |
| if(filenamelen) { |
| if(filename[filenamelen - 1] != '\\') |
| strcat(filename, "\\"); |
| } |
| else /* specify the current directory */ |
| strcpy(filename, ".\\"); |
| |
| /* Create the full pathname */ |
| strcat(filename, file); |
| |
| if(OpenFile32(filename, &fileinfo, OF_EXIST | OF_SHARE_EXCLUSIVE) == |
| HFILE_ERROR32) |
| retval = 0; |
| else |
| retval = 1; |
| |
| return retval; |
| } |
| |
| |
| static int read_xx_header(HFILE32 lzfd) { |
| IMAGE_DOS_HEADER mzh; |
| char magic[3]; |
| |
| LZSeek32(lzfd,0,SEEK_SET); |
| if (sizeof(mzh)!=LZRead32(lzfd,&mzh,sizeof(mzh))) |
| return 0; |
| if (mzh.e_magic!=IMAGE_DOS_SIGNATURE) |
| return 0; |
| LZSeek32(lzfd,mzh.e_lfanew,SEEK_SET); |
| if (2!=LZRead32(lzfd,magic,2)) |
| return 0; |
| LZSeek32(lzfd,mzh.e_lfanew,SEEK_SET); |
| if (magic[0] == 'N' && magic[1] == 'E') |
| return IMAGE_OS2_SIGNATURE; |
| if (magic[0] == 'P' && magic[1] == 'E') |
| return IMAGE_NT_SIGNATURE; |
| magic[2]='\0'; |
| WARN(ver,"Can't handle %s files.\n",magic); |
| return 0; |
| } |
| |
| |
| static int find_ne_resource( |
| HFILE32 lzfd,SEGPTR typeid,SEGPTR resid, |
| BYTE **resdata,int *reslen,DWORD *off |
| ) { |
| IMAGE_OS2_HEADER nehd; |
| NE_TYPEINFO ti; |
| NE_NAMEINFO ni; |
| int i; |
| WORD shiftcount; |
| DWORD nehdoffset; |
| |
| nehdoffset = LZTELL(lzfd); |
| LZREAD(&nehd); |
| if (nehd.resource_tab_offset==nehd.rname_tab_offset) { |
| TRACE(ver,"no resources in NE dll\n"); |
| return 0; |
| } |
| LZSeek32(lzfd,nehd.resource_tab_offset+nehdoffset,SEEK_SET); |
| LZREAD(&shiftcount); |
| TRACE(ver,"shiftcount is %d\n",shiftcount); |
| TRACE(ver,"reading resource typeinfo dir.\n"); |
| |
| if (!HIWORD(typeid)) typeid = (SEGPTR)(LOWORD(typeid) | 0x8000); |
| if (!HIWORD(resid)) resid = (SEGPTR)(LOWORD(resid) | 0x8000); |
| while (1) { |
| int skipflag; |
| |
| LZREAD(&ti); |
| if (!ti.type_id) |
| return 0; |
| TRACE(ver," ti.typeid =%04x,count=%d\n",ti.type_id,ti.count); |
| |
| skipflag=0; |
| if (!HIWORD(typeid)) { |
| if ((ti.type_id&0x8000)&&(typeid!=ti.type_id)) |
| skipflag=1; |
| } else { |
| if (ti.type_id & 0x8000) { |
| skipflag=1; |
| } else { |
| BYTE len; |
| char *str; |
| DWORD whereleft; |
| |
| whereleft = LZTELL(lzfd); |
| LZSeek32( |
| lzfd, |
| nehdoffset+nehd.resource_tab_offset+ti.type_id, |
| SEEK_SET |
| ); |
| LZREAD(&len); |
| str=xmalloc(len); |
| if (len!=LZRead32(lzfd,str,len)) |
| return 0; |
| TRACE(ver,"read %s to compare it with %s\n", |
| str,(char*)PTR_SEG_TO_LIN(typeid) |
| ); |
| if (lstrcmpi32A(str,(char*)PTR_SEG_TO_LIN(typeid))) |
| skipflag=1; |
| free(str); |
| LZSeek32(lzfd,whereleft,SEEK_SET); |
| } |
| } |
| if (skipflag) { |
| LZSeek32(lzfd,ti.count*sizeof(ni),SEEK_CUR); |
| continue; |
| } |
| for (i=0;i<ti.count;i++) { |
| WORD *rdata; |
| int len; |
| |
| LZREAD(&ni); |
| TRACE(ver," ni.id=%4x,offset=%d,length=%d\n", |
| ni.id,ni.offset,ni.length |
| ); |
| skipflag=1; |
| if (!HIWORD(resid)) { |
| if (ni.id == resid) |
| skipflag=0; |
| } else { |
| if (!(ni.id & 0x8000)) { |
| BYTE len; |
| char *str; |
| DWORD whereleft; |
| |
| whereleft = LZTELL(lzfd); |
| LZSeek32( |
| lzfd, |
| nehdoffset+nehd.resource_tab_offset+ni.id, |
| SEEK_SET |
| ); |
| LZREAD(&len); |
| str=xmalloc(len); |
| if (len!=LZRead32(lzfd,str,len)) |
| return 0; |
| TRACE(ver,"read %s to compare it with %s\n", |
| str,(char*)PTR_SEG_TO_LIN(typeid) |
| ); |
| if (!lstrcmpi32A(str,(char*)PTR_SEG_TO_LIN(typeid))) |
| skipflag=0; |
| free(str); |
| LZSeek32(lzfd,whereleft,SEEK_SET); |
| } |
| } |
| if (skipflag) |
| continue; |
| LZSeek32(lzfd,((int)ni.offset<<shiftcount),SEEK_SET); |
| *off = (int)ni.offset<<shiftcount; |
| len = ni.length<<shiftcount; |
| rdata=(WORD*)xmalloc(len); |
| if (len!=LZRead32(lzfd,rdata,len)) { |
| free(rdata); |
| return 0; |
| } |
| TRACE(ver,"resource found.\n"); |
| *resdata= (BYTE*)rdata; |
| *reslen = len; |
| return 1; |
| } |
| } |
| } |
| |
| /* Loads the specified PE resource. |
| * FIXME: shouldn't load the whole image |
| */ |
| static int |
| find_pe_resource( |
| HFILE32 lzfd,LPWSTR typeid,LPWSTR resid, |
| BYTE **resdata,int *reslen,DWORD *off |
| ) { |
| IMAGE_NT_HEADERS pehd; |
| int i; |
| UINT32 nrofsections; |
| DWORD imagesize,pehdoffset; |
| BYTE *image; |
| IMAGE_DATA_DIRECTORY resdir; |
| LPIMAGE_RESOURCE_DIRECTORY resourcedir,xresdir; |
| LPIMAGE_RESOURCE_DATA_ENTRY xresdata; |
| LPIMAGE_SECTION_HEADER sections; |
| |
| pehdoffset = LZTELL(lzfd); |
| LZREAD(&pehd); |
| resdir = pehd.OptionalHeader.DataDirectory[IMAGE_FILE_RESOURCE_DIRECTORY]; |
| TRACE(ver,"(.,%p,%p,....)\n",typeid,resid); |
| if (!resdir.Size) { |
| WARN(ver,"No resource directory found in PE file.\n"); |
| return 0; |
| } |
| imagesize = pehd.OptionalHeader.SizeOfImage; |
| image = HeapAlloc(GetProcessHeap(),0,imagesize); |
| nrofsections = pehd.FileHeader.NumberOfSections; |
| |
| sections = (LPIMAGE_SECTION_HEADER)HeapAlloc(GetProcessHeap(),0,pehd.FileHeader.NumberOfSections*sizeof(IMAGE_SECTION_HEADER)); |
| LZSeek32(lzfd, |
| pehdoffset+ |
| sizeof(DWORD)+ /* Signature */ |
| sizeof(IMAGE_FILE_HEADER)+ |
| pehd.FileHeader.SizeOfOptionalHeader, |
| SEEK_SET |
| ); |
| if ( nrofsections*sizeof(IMAGE_SECTION_HEADER)!= |
| LZRead32(lzfd,sections,nrofsections*sizeof(IMAGE_SECTION_HEADER)) |
| ) { |
| HeapFree(GetProcessHeap(),0,image); |
| return 0; |
| } |
| for (i=0;i<nrofsections;i++) { |
| if (sections[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) |
| continue; |
| LZSeek32(lzfd,sections[i].PointerToRawData,SEEK_SET); |
| if ( sections[i].SizeOfRawData!= |
| LZRead32(lzfd,image+sections[i].VirtualAddress,sections[i].SizeOfRawData) |
| ) { |
| HeapFree(GetProcessHeap(),0,image); |
| return 0; |
| } |
| } |
| resourcedir = (LPIMAGE_RESOURCE_DIRECTORY)(image+resdir.VirtualAddress); |
| xresdir = GetResDirEntryW(resourcedir,typeid,(DWORD)resourcedir,FALSE); |
| if (!xresdir) { |
| TRACE(ver,"...no typeid entry found for %p\n",typeid); |
| HeapFree(GetProcessHeap(),0,image); |
| return 0; |
| } |
| xresdir = GetResDirEntryW(xresdir,resid,(DWORD)resourcedir,FALSE); |
| if (!xresdir) { |
| TRACE(ver,"...no resid entry found for %p\n",resid); |
| HeapFree(GetProcessHeap(),0,image); |
| return 0; |
| } |
| |
| xresdir = GetResDirEntryW(xresdir,0,(DWORD)resourcedir,TRUE); |
| if (!xresdir) { |
| TRACE(ver,"...no 0 (default language) entry found for %p\n",resid); |
| HeapFree(GetProcessHeap(),0,image); |
| return 0; |
| } |
| xresdata = (LPIMAGE_RESOURCE_DATA_ENTRY)xresdir; |
| *reslen = xresdata->Size; |
| *resdata= (LPBYTE)xmalloc(*reslen); |
| memcpy(*resdata,image+xresdata->OffsetToData,*reslen); |
| /* find physical address for virtual offset */ |
| for (i=0;i<nrofsections;i++) { |
| if (sections[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) |
| continue; |
| if ( (xresdata->OffsetToData >= sections[i].VirtualAddress)&& |
| (xresdata->OffsetToData < sections[i].VirtualAddress+sections[i].SizeOfRawData) |
| ) { |
| *off = (DWORD)(xresdata->OffsetToData)-(DWORD)(sections[i].VirtualAddress)+(DWORD)(sections[i].PointerToRawData); |
| break; |
| } |
| } |
| HeapFree(GetProcessHeap(),0,image); |
| HeapFree(GetProcessHeap(),0,sections); |
| return 1; |
| } |
| |
| /* GetFileResourceSize [VER.2] */ |
| DWORD WINAPI GetFileResourceSize(LPCSTR filename,SEGPTR restype,SEGPTR resid, |
| LPDWORD off) |
| { |
| HFILE32 lzfd; |
| OFSTRUCT ofs; |
| BYTE *resdata = NULL; |
| int reslen=0; |
| int res=0; |
| |
| TRACE(ver,"(%s,%lx,%lx,%p)\n", |
| filename,(LONG)restype,(LONG)resid,off |
| ); |
| lzfd=LZOpenFile32A(filename,&ofs,OF_READ); |
| if (!lzfd) |
| return 0; |
| switch (read_xx_header(lzfd)) { |
| case 0: |
| res=0; |
| break; |
| case IMAGE_OS2_SIGNATURE: |
| res=find_ne_resource(lzfd,restype,resid,&resdata,&reslen,off); |
| break; |
| case IMAGE_NT_SIGNATURE: |
| res=find_pe_resource(lzfd,(LPWSTR)restype,(LPWSTR)resid,&resdata,&reslen,off); |
| break; |
| } |
| if (!res) { |
| LZClose32(lzfd); |
| return 0; |
| } |
| if (resdata) |
| free(resdata); |
| LZClose32(lzfd); |
| return reslen; |
| } |
| |
| /* GetFileResource [VER.3] */ |
| DWORD WINAPI GetFileResource(LPCSTR filename,SEGPTR restype,SEGPTR resid, |
| DWORD off,DWORD datalen,LPVOID data ) |
| { |
| HFILE32 lzfd; |
| OFSTRUCT ofs; |
| BYTE *resdata=NULL; |
| int res=0; |
| int reslen=datalen; |
| |
| TRACE(ver,"(%s,%lx,%lx,%ld,%ld,%p)\n", |
| filename,(LONG)restype,(LONG)resid,off,datalen,data |
| ); |
| |
| lzfd=LZOpenFile32A(filename,&ofs,OF_READ); |
| if (lzfd==0) |
| return 0; |
| if (!off) { |
| switch (read_xx_header(lzfd)) { |
| case 0: res=0; |
| break; |
| case IMAGE_OS2_SIGNATURE: |
| res= find_ne_resource(lzfd,restype,resid,&resdata,&reslen,&off); |
| break; |
| case IMAGE_NT_SIGNATURE: |
| res= find_pe_resource(lzfd,(LPWSTR)restype,(LPWSTR)resid,&resdata,&reslen,&off); |
| break; |
| } |
| LZClose32(lzfd); |
| if (!res) |
| return 0; |
| if (reslen>datalen) reslen = datalen; |
| memcpy(data,resdata,reslen); |
| free(resdata); |
| return reslen; |
| } |
| LZSeek32(lzfd,off,SEEK_SET); |
| reslen = LZRead32(lzfd,data,datalen); |
| LZClose32(lzfd); |
| return reslen; |
| } |
| |
| /* GetFileVersionInfoSize [VER.6] */ |
| DWORD WINAPI GetFileVersionInfoSize16(LPCSTR filename,LPDWORD handle) |
| { |
| DWORD len,ret,isuni=0; |
| BYTE buf[144]; |
| VS_FIXEDFILEINFO *vffi; |
| |
| TRACE(ver,"(%s,%p)\n",filename,handle); |
| len=GetFileResourceSize(filename,VS_FILE_INFO,VS_VERSION_INFO,handle); |
| if (!len) |
| return 0; |
| ret=GetFileResource( |
| filename,VS_FILE_INFO,VS_VERSION_INFO,*handle,sizeof(buf),buf |
| ); |
| if (!ret) |
| return 0; |
| |
| vffi=(VS_FIXEDFILEINFO*)(buf+0x14); |
| if (vffi->dwSignature != VS_FFI_SIGNATURE) { |
| /* unicode resource */ |
| if (vffi->dwSignature == 0x004f0049) { |
| isuni = 1; |
| vffi = (VS_FIXEDFILEINFO*)(buf+0x28); |
| } else { |
| WARN(ver,"vffi->dwSignature is 0x%08lx, but not 0x%08lx!\n", |
| vffi->dwSignature,VS_FFI_SIGNATURE |
| ); |
| return 0; |
| } |
| } |
| if (*(WORD*)buf < len) |
| len = *(WORD*)buf; |
| |
| if(TRACE_ON(ver)) |
| print_vffi_debug(vffi); |
| |
| return len; |
| } |
| |
| /* GetFileVersionInfoSize32A [VERSION.1] */ |
| DWORD WINAPI GetFileVersionInfoSize32A(LPCSTR filename,LPDWORD handle) |
| { |
| TRACE(ver,"(%s,%p)\n",filename,handle); |
| return GetFileVersionInfoSize16(filename,handle); |
| } |
| |
| /* GetFileVersionInfoSize32W [VERSION.2] */ |
| DWORD WINAPI GetFileVersionInfoSize32W( LPCWSTR filename, LPDWORD handle ) |
| { |
| LPSTR xfn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename ); |
| DWORD ret = GetFileVersionInfoSize16( xfn, handle ); |
| HeapFree( GetProcessHeap(), 0, xfn ); |
| return ret; |
| } |
| |
| /* GetFileVersionInfo [VER.7] */ |
| DWORD WINAPI GetFileVersionInfo16(LPCSTR filename,DWORD handle,DWORD datasize, |
| LPVOID data) |
| { |
| TRACE(ver,"(%s,%ld,%ld,%p)\n", |
| filename,handle,datasize,data |
| ); |
| return GetFileResource( |
| filename,VS_FILE_INFO,VS_VERSION_INFO,handle,datasize,data |
| ); |
| } |
| |
| /* GetFileVersionInfoA [VERSION.0] */ |
| DWORD WINAPI GetFileVersionInfo32A(LPCSTR filename,DWORD handle, |
| DWORD datasize,LPVOID data) |
| { |
| return GetFileVersionInfo16(filename,handle,datasize,data); |
| } |
| |
| /* GetFileVersionInfoW [VERSION.3] */ |
| DWORD WINAPI GetFileVersionInfo32W( LPCWSTR filename, DWORD handle, |
| DWORD datasize, LPVOID data) |
| { |
| LPSTR fn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename ); |
| DWORD ret = GetFileVersionInfo16( fn, handle, datasize, data ); |
| HeapFree( GetProcessHeap(), 0, fn ); |
| return ret; |
| } |
| |
| /***************************************************************************** |
| * |
| * VerFindFile() [VER.8] |
| * Determines where to install a file based on whether it locates another |
| * version of the file in the system. The values VerFindFile returns are |
| * used in a subsequent call to the VerInstallFile function. |
| * |
| * Revision history: |
| * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu) |
| * Reimplementation of VerFindFile from original stub. |
| * |
| ****************************************************************************/ |
| |
| DWORD WINAPI VerFindFile16( |
| UINT16 flags, |
| LPCSTR lpszFilename, |
| LPCSTR lpszWinDir, |
| LPCSTR lpszAppDir, |
| LPSTR lpszCurDir, |
| UINT16 *lpuCurDirLen, |
| LPSTR lpszDestDir, |
| UINT16 *lpuDestDirLen ) |
| { |
| DWORD retval; |
| char curDir[256]; |
| char destDir[256]; |
| unsigned int curDirSizeReq; |
| unsigned int destDirSizeReq; |
| |
| retval = 0; |
| |
| /* Print out debugging information */ |
| TRACE(ver, "called with parameters:\n" |
| "\tflags = %x", flags); |
| if(flags & VFFF_ISSHAREDFILE) |
| TRACE(ver, " (VFFF_ISSHAREDFILE)\n"); |
| else |
| TRACE(ver, "\n"); |
| |
| ver_dstring("\tlpszFilename = ", lpszFilename, ""); |
| ver_dstring("\tlpszWinDir = ", lpszWinDir, ""); |
| ver_dstring("\tlpszAppDir = ", lpszAppDir, ""); |
| |
| TRACE(ver, "\tlpszCurDir = %p\n", lpszCurDir); |
| if(lpuCurDirLen) |
| TRACE(ver, "\tlpuCurDirLen = %p (%u)\n", |
| lpuCurDirLen, *lpuCurDirLen); |
| else |
| TRACE(ver, "\tlpuCurDirLen = (null)\n"); |
| |
| TRACE(ver, "\tlpszDestDir = %p\n", lpszDestDir); |
| if(lpuDestDirLen) |
| TRACE(ver, "\tlpuDestDirLen = %p (%u)\n", |
| lpuDestDirLen, *lpuDestDirLen); |
| |
| /* Figure out where the file should go; shared files default to the |
| system directory */ |
| |
| strcpy(curDir, ""); |
| strcpy(destDir, ""); |
| |
| if(flags & VFFF_ISSHAREDFILE) { |
| GetSystemDirectory32A(destDir, 256); |
| |
| /* Were we given a filename? If so, try to find the file. */ |
| if(lpszFilename) { |
| if(testFileExistence(destDir, lpszFilename)) { |
| strcpy(curDir, destDir); |
| |
| if(!testFileExclusiveExistence(destDir, lpszFilename)) |
| retval |= VFF_FILEINUSE; |
| } |
| else if(lpszAppDir && testFileExistence(lpszAppDir, |
| lpszFilename)) { |
| strcpy(curDir, lpszAppDir); |
| retval |= VFF_CURNEDEST; |
| |
| if(!testFileExclusiveExistence(lpszAppDir, lpszFilename)) |
| retval |= VFF_FILEINUSE; |
| } |
| } |
| } |
| else if(!(flags & VFFF_ISSHAREDFILE)) { /* not a shared file */ |
| if(lpszAppDir) { |
| char systemDir[256]; |
| GetSystemDirectory32A(systemDir, 256); |
| |
| strcpy(destDir, lpszAppDir); |
| |
| if(lpszFilename) { |
| if(testFileExistence(lpszAppDir, lpszFilename)) { |
| strcpy(curDir, lpszAppDir); |
| |
| if(!testFileExclusiveExistence(lpszAppDir, lpszFilename)) |
| retval |= VFF_FILEINUSE; |
| } |
| else if(testFileExistence(systemDir, lpszFilename)) { |
| strcpy(curDir, systemDir); |
| retval |= VFF_CURNEDEST; |
| |
| if(!testFileExclusiveExistence(systemDir, lpszFilename)) |
| retval |= VFF_FILEINUSE; |
| } |
| } |
| } |
| } |
| |
| curDirSizeReq = strlen(curDir) + 1; |
| destDirSizeReq = strlen(destDir) + 1; |
| |
| |
| |
| /* Make sure that the pointers to the size of the buffers are |
| valid; if not, do NOTHING with that buffer. If that pointer |
| is valid, then make sure that the buffer pointer is valid, too! */ |
| |
| if(lpuDestDirLen && lpszDestDir) { |
| if(*lpuDestDirLen < destDirSizeReq) { |
| retval |= VFF_BUFFTOOSMALL; |
| strncpy(lpszDestDir, destDir, *lpuDestDirLen - 1); |
| lpszDestDir[*lpuDestDirLen - 1] = '\0'; |
| } |
| else |
| strcpy(lpszDestDir, destDir); |
| |
| *lpuDestDirLen = destDirSizeReq; |
| } |
| |
| if(lpuCurDirLen && lpszCurDir) { |
| if(*lpuCurDirLen < curDirSizeReq) { |
| retval |= VFF_BUFFTOOSMALL; |
| strncpy(lpszCurDir, curDir, *lpuCurDirLen - 1); |
| lpszCurDir[*lpuCurDirLen - 1] = '\0'; |
| } |
| else |
| strcpy(lpszCurDir, curDir); |
| |
| *lpuCurDirLen = curDirSizeReq; |
| } |
| |
| TRACE(ver, "ret = %lu (%s%s%s)\n", retval, |
| (retval & VFF_CURNEDEST) ? "VFF_CURNEDEST " : "", |
| (retval & VFF_FILEINUSE) ? "VFF_FILEINUSE " : "", |
| (retval & VFF_BUFFTOOSMALL) ? "VFF_BUFFTOOSMALL " : ""); |
| |
| ver_dstring("\t(Exit) lpszCurDir = ", lpszCurDir, ""); |
| if(lpuCurDirLen) |
| TRACE(ver, "\t(Exit) lpuCurDirLen = %p (%u)\n", |
| lpuCurDirLen, *lpuCurDirLen); |
| else |
| TRACE(ver, "\t(Exit) lpuCurDirLen = (null)\n"); |
| |
| ver_dstring("\t(Exit) lpszDestDir = ", lpszDestDir, ""); |
| if(lpuDestDirLen) |
| TRACE(ver, "\t(Exit) lpuDestDirLen = %p (%u)\n", |
| lpuDestDirLen, *lpuDestDirLen); |
| |
| return retval; |
| } |
| |
| /* VerFindFileA [VERSION.5] */ |
| DWORD WINAPI VerFindFile32A( |
| UINT32 flags,LPCSTR filename,LPCSTR windir,LPCSTR appdir, |
| LPSTR curdir,UINT32 *pcurdirlen,LPSTR destdir,UINT32 *pdestdirlen ) |
| { |
| UINT16 curdirlen, destdirlen; |
| DWORD ret; |
| |
| curdirlen = (UINT16)*pcurdirlen; |
| destdirlen= (UINT16)*pdestdirlen; |
| |
| ret = VerFindFile16(flags,filename,windir,appdir, |
| curdir,&curdirlen,destdir,&destdirlen); |
| *pcurdirlen = curdirlen; |
| *pdestdirlen = destdirlen; |
| return ret; |
| } |
| |
| /* VerFindFileW [VERSION.6] */ |
| DWORD WINAPI VerFindFile32W( |
| UINT32 flags,LPCWSTR filename,LPCWSTR windir,LPCWSTR appdir, |
| LPWSTR curdir,UINT32 *pcurdirlen,LPWSTR destdir,UINT32 *pdestdirlen ) |
| { |
| UINT16 curdirlen, destdirlen; |
| LPSTR wfn,wwd,wad,wdd,wcd; |
| DWORD ret; |
| |
| wfn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename ); |
| wwd = HEAP_strdupWtoA( GetProcessHeap(), 0, windir ); |
| wad = HEAP_strdupWtoA( GetProcessHeap(), 0, appdir ); |
| wcd = HeapAlloc( GetProcessHeap(), 0, *pcurdirlen ); |
| wdd = HeapAlloc( GetProcessHeap(), 0, *pdestdirlen ); |
| ret = VerFindFile16(flags,wfn,wwd,wad,wcd,&curdirlen,wdd,&destdirlen); |
| lstrcpynAtoW(curdir,wcd,*pcurdirlen); |
| lstrcpynAtoW(destdir,wdd,*pdestdirlen); |
| *pcurdirlen = strlen(wcd); |
| *pdestdirlen = strlen(wdd); |
| HeapFree( GetProcessHeap(), 0, wfn ); |
| HeapFree( GetProcessHeap(), 0, wwd ); |
| HeapFree( GetProcessHeap(), 0, wad ); |
| HeapFree( GetProcessHeap(), 0, wcd ); |
| HeapFree( GetProcessHeap(), 0, wdd ); |
| return ret; |
| } |
| |
| /* VerInstallFile [VER.9] */ |
| DWORD WINAPI VerInstallFile16( |
| UINT16 flags,LPCSTR srcfilename,LPCSTR destfilename,LPCSTR srcdir, |
| LPCSTR destdir,LPCSTR curdir,LPSTR tmpfile,UINT16 *tmpfilelen ) |
| { |
| UINT32 filelen; |
| DWORD ret= VerInstallFile32A(flags,srcfilename,destfilename,srcdir, |
| destdir,curdir,tmpfile,&filelen); |
| |
| *tmpfilelen = filelen; |
| return ret; |
| } |
| |
| static LPBYTE |
| _fetch_versioninfo(LPSTR fn,VS_FIXEDFILEINFO **vffi) { |
| DWORD alloclen; |
| LPBYTE buf; |
| DWORD ret; |
| |
| alloclen = 1000; |
| buf= xmalloc(alloclen); |
| while (1) { |
| ret = GetFileVersionInfo32A(fn,0,alloclen,buf); |
| if (!ret) { |
| free(buf); |
| return 0; |
| } |
| if (alloclen<*(WORD*)buf) { |
| free(buf); |
| alloclen = *(WORD*)buf; |
| buf = xmalloc(alloclen); |
| } else { |
| *vffi = (VS_FIXEDFILEINFO*)(buf+0x14); |
| if ((*vffi)->dwSignature == 0x004f0049) /* hack to detect unicode */ |
| *vffi = (VS_FIXEDFILEINFO*)(buf+0x28); |
| if ((*vffi)->dwSignature != VS_FFI_SIGNATURE) |
| WARN(ver,"Bad VS_FIXEDFILEINFO signature 0x%08lx\n",(*vffi)->dwSignature); |
| return buf; |
| } |
| } |
| } |
| |
| static DWORD |
| _error2vif(DWORD error) { |
| switch (error) { |
| case ERROR_ACCESS_DENIED: |
| return VIF_ACCESSVIOLATION; |
| case ERROR_SHARING_VIOLATION: |
| return VIF_SHARINGVIOLATION; |
| default: |
| return 0; |
| } |
| } |
| |
| |
| /****************************************************************************** |
| * VerInstallFile32A [VERSION.7] |
| */ |
| DWORD WINAPI VerInstallFile32A( |
| UINT32 flags,LPCSTR srcfilename,LPCSTR destfilename,LPCSTR srcdir, |
| LPCSTR destdir,LPCSTR curdir,LPSTR tmpfile,UINT32 *tmpfilelen ) |
| { |
| LPCSTR pdest; |
| char destfn[260],tmpfn[260],srcfn[260]; |
| HFILE32 hfsrc,hfdst; |
| DWORD attr,ret,xret,tmplast; |
| LPBYTE buf1,buf2; |
| OFSTRUCT ofs; |
| |
| TRACE(ver,"(%x,%s,%s,%s,%s,%s,%p,%d)\n", |
| flags,srcfilename,destfilename,srcdir,destdir,curdir,tmpfile,*tmpfilelen |
| ); |
| xret = 0; |
| sprintf(srcfn,"%s\\%s",srcdir,srcfilename); |
| if (!destdir || !*destdir) pdest = srcdir; |
| else pdest = destdir; |
| sprintf(destfn,"%s\\%s",pdest,destfilename); |
| hfsrc=LZOpenFile32A(srcfn,&ofs,OF_READ); |
| if (hfsrc==HFILE_ERROR32) |
| return VIF_CANNOTREADSRC; |
| sprintf(tmpfn,"%s\\%s",pdest,destfilename); |
| tmplast=strlen(pdest)+1; |
| attr = GetFileAttributes32A(tmpfn); |
| if (attr!=-1) { |
| if (attr & FILE_ATTRIBUTE_READONLY) { |
| LZClose32(hfsrc); |
| return VIF_WRITEPROT; |
| } |
| /* FIXME: check if file currently in use and return VIF_FILEINUSE */ |
| } |
| attr = -1; |
| if (flags & VIFF_FORCEINSTALL) { |
| if (tmpfile[0]) { |
| sprintf(tmpfn,"%s\\%s",pdest,tmpfile); |
| tmplast = strlen(pdest)+1; |
| attr = GetFileAttributes32A(tmpfn); |
| /* if it exists, it has been copied by the call before. |
| * we jump over the copy part... |
| */ |
| } |
| } |
| if (attr == -1) { |
| char *s; |
| |
| GetTempFileName32A(pdest,"ver",0,tmpfn); /* should not fail ... */ |
| s=strrchr(tmpfn,'\\'); |
| if (s) |
| tmplast = s-tmpfn; |
| else |
| tmplast = 0; |
| hfdst = OpenFile32(tmpfn,&ofs,OF_CREATE); |
| if (hfdst == HFILE_ERROR32) { |
| LZClose32(hfsrc); |
| return VIF_CANNOTCREATE; /* | translated dos error */ |
| } |
| ret = LZCopy32(hfsrc,hfdst); |
| _lclose32(hfdst); |
| if (((long) ret) < 0) { |
| /* translate LZ errors into VIF_xxx */ |
| switch (ret) { |
| case LZERROR_BADINHANDLE: |
| case LZERROR_READ: |
| case LZERROR_BADVALUE: |
| case LZERROR_UNKNOWNALG: |
| ret = VIF_CANNOTREADSRC; |
| break; |
| case LZERROR_BADOUTHANDLE: |
| case LZERROR_WRITE: |
| ret = VIF_OUTOFMEMORY; /* FIXME: correct? */ |
| break; |
| case LZERROR_GLOBALLOC: |
| case LZERROR_GLOBLOCK: |
| ret = VIF_OUTOFSPACE; |
| break; |
| default: /* unknown error, should not happen */ |
| ret = 0; |
| break; |
| } |
| if (ret) { |
| LZClose32(hfsrc); |
| return ret; |
| } |
| } |
| } |
| xret = 0; |
| if (!(flags & VIFF_FORCEINSTALL)) { |
| VS_FIXEDFILEINFO *destvffi,*tmpvffi; |
| buf1 = _fetch_versioninfo(destfn,&destvffi); |
| if (buf1) { |
| buf2 = _fetch_versioninfo(tmpfn,&tmpvffi); |
| if (buf2) { |
| char *tbuf1,*tbuf2; |
| UINT32 len1,len2; |
| |
| len1=len2=40; |
| |
| /* compare file versions */ |
| if ((destvffi->dwFileVersionMS > tmpvffi->dwFileVersionMS)|| |
| ((destvffi->dwFileVersionMS==tmpvffi->dwFileVersionMS)&& |
| (destvffi->dwFileVersionLS > tmpvffi->dwFileVersionLS) |
| ) |
| ) |
| xret |= VIF_MISMATCH|VIF_SRCOLD; |
| /* compare filetypes and filesubtypes */ |
| if ((destvffi->dwFileType!=tmpvffi->dwFileType) || |
| (destvffi->dwFileSubtype!=tmpvffi->dwFileSubtype) |
| ) |
| xret |= VIF_MISMATCH|VIF_DIFFTYPE; |
| if (VerQueryValue32A(buf1,"\\VarFileInfo\\Translation",(LPVOID*)&tbuf1,&len1) && |
| VerQueryValue32A(buf2,"\\VarFileInfo\\Translation",(LPVOID*)&tbuf2,&len2) |
| ) { |
| /* irgendwas mit tbuf1 und tbuf2 machen |
| * generiert DIFFLANG|MISMATCH |
| */ |
| } |
| free(buf2); |
| } else |
| xret=VIF_MISMATCH|VIF_SRCOLD; |
| free(buf1); |
| } |
| } |
| if (xret) { |
| if (*tmpfilelen<strlen(tmpfn+tmplast)) { |
| xret|=VIF_BUFTOSMALL; |
| DeleteFile32A(tmpfn); |
| } else { |
| strcpy(tmpfile,tmpfn+tmplast); |
| *tmpfilelen = strlen(tmpfn+tmplast)+1; |
| xret|=VIF_TEMPFILE; |
| } |
| } else { |
| if (-1!=GetFileAttributes32A(destfn)) |
| if (!DeleteFile32A(destfn)) { |
| xret|=_error2vif(GetLastError())|VIF_CANNOTDELETE; |
| DeleteFile32A(tmpfn); |
| LZClose32(hfsrc); |
| return xret; |
| } |
| if ((!(flags & VIFF_DONTDELETEOLD)) && |
| curdir && |
| *curdir && |
| lstrcmpi32A(curdir,pdest) |
| ) { |
| char curfn[260]; |
| |
| sprintf(curfn,"%s\\%s",curdir,destfilename); |
| if (-1!=GetFileAttributes32A(curfn)) { |
| /* FIXME: check if in use ... if it is, VIF_CANNOTDELETECUR */ |
| if (!DeleteFile32A(curfn)) |
| xret|=_error2vif(GetLastError())|VIF_CANNOTDELETECUR; |
| } |
| } |
| if (!MoveFile32A(tmpfn,destfn)) { |
| xret|=_error2vif(GetLastError())|VIF_CANNOTRENAME; |
| DeleteFile32A(tmpfn); |
| } |
| } |
| LZClose32(hfsrc); |
| return xret; |
| } |
| |
| |
| /* VerInstallFileW [VERSION.8] */ |
| DWORD WINAPI VerInstallFile32W( |
| UINT32 flags,LPCWSTR srcfilename,LPCWSTR destfilename,LPCWSTR srcdir, |
| LPCWSTR destdir,LPCWSTR curdir,LPWSTR tmpfile,UINT32 *tmpfilelen ) |
| { |
| LPSTR wsrcf,wsrcd,wdestf,wdestd,wtmpf,wcurd; |
| DWORD ret; |
| |
| wsrcf = HEAP_strdupWtoA( GetProcessHeap(), 0, srcfilename ); |
| wsrcd = HEAP_strdupWtoA( GetProcessHeap(), 0, srcdir ); |
| wdestf = HEAP_strdupWtoA( GetProcessHeap(), 0, destfilename ); |
| wdestd = HEAP_strdupWtoA( GetProcessHeap(), 0, destdir ); |
| wtmpf = HEAP_strdupWtoA( GetProcessHeap(), 0, tmpfile ); |
| wcurd = HEAP_strdupWtoA( GetProcessHeap(), 0, curdir ); |
| ret = VerInstallFile32A(flags,wsrcf,wdestf,wsrcd,wdestd,wcurd,wtmpf,tmpfilelen); |
| if (!ret) |
| lstrcpynAtoW(tmpfile,wtmpf,*tmpfilelen); |
| HeapFree( GetProcessHeap(), 0, wsrcf ); |
| HeapFree( GetProcessHeap(), 0, wsrcd ); |
| HeapFree( GetProcessHeap(), 0, wdestf ); |
| HeapFree( GetProcessHeap(), 0, wdestd ); |
| HeapFree( GetProcessHeap(), 0, wtmpf ); |
| if (wcurd) |
| HeapFree( GetProcessHeap(), 0, wcurd ); |
| return ret; |
| } |
| |
| |
| struct dbA { |
| WORD nextoff; |
| WORD datalen; |
| /* in memory structure... */ |
| char name[1]; /* padded to dword alignment */ |
| /* .... |
| char data[datalen]; padded to dword alignment |
| BYTE subdirdata[]; until nextoff |
| */ |
| }; |
| |
| #define DATA_OFFSET_A(db) ((4+(strlen((db)->name)+4))&~3) |
| |
| struct dbW { |
| WORD nextoff; |
| WORD datalen; |
| WORD btext; /* type of data */ |
| /* in memory structure... */ |
| WCHAR name[1]; /* padded to dword alignment */ |
| /* .... |
| WCHAR data[datalen]; padded to dword alignment |
| BYTE subdirdata[]; until nextoff |
| */ |
| }; |
| |
| /* WORD nextoffset; |
| * WORD datalength; |
| * WORD btype; |
| * WCHAR szKey[]; (zero terminated) |
| * PADDING (round up to nearest 32bit boundary) |
| */ |
| #define DATA_OFFSET_W(db) ((2+2+2+((lstrlen32W((db)->name)+1)*2+3))&~3) |
| |
| /* this one used for Win16 resources, which are always in ASCII format */ |
| static BYTE* |
| _find_dataA(BYTE *block,LPCSTR str, int buff_remain) { |
| char *nextslash; |
| int substrlen, inc_size; |
| struct dbA *db; |
| |
| while (*str && *str=='\\') |
| str++; |
| if (NULL!=(nextslash=strchr(str,'\\'))) |
| substrlen=nextslash-str; |
| else |
| substrlen=strlen(str); |
| if (nextslash!=NULL) { |
| while (*nextslash && *nextslash=='\\') |
| nextslash++; |
| if (!*nextslash) |
| nextslash=NULL; |
| } else if (*str == 0) |
| return NULL; |
| |
| |
| while (1) { |
| db=(struct dbA*)block; |
| TRACE(ver,"db=%p,db->nextoff=%d,db->datalen=%d,db->name=%s\n", |
| db,db->nextoff,db->datalen,db->name |
| ); |
| if ((!db->nextoff) || (buff_remain<=0)) /* no more entries ? */ |
| return NULL; |
| |
| TRACE(ver,"comparing with %s\n",db->name); |
| if (!lstrncmpi32A(db->name,str,substrlen)) { |
| if (nextslash) { |
| inc_size=DATA_OFFSET_A(db)+((db->datalen+3)&~3); |
| return _find_dataA(block+inc_size,nextslash, |
| db->nextoff-inc_size); |
| } else |
| return block; |
| } |
| inc_size = ((db->nextoff+3)&~3); |
| block += inc_size; |
| buff_remain -= inc_size; |
| } |
| } |
| |
| /* this one used for Win32 resources, which are always in UNICODE format */ |
| extern LPWSTR __cdecl CRTDLL_wcschr(LPCWSTR str,WCHAR xchar); |
| static BYTE* |
| _find_dataW(BYTE *block,LPCWSTR str, int buff_remain) { |
| LPWSTR nextslash; |
| int substrlen, inc_size; |
| struct dbW *db; |
| |
| |
| while (*str && *str=='\\') |
| str++; |
| if (NULL!=(nextslash=CRTDLL_wcschr(str,'\\'))) |
| substrlen=nextslash-str; |
| else |
| substrlen=lstrlen32W(str); |
| if (nextslash!=NULL) { |
| while (*nextslash && *nextslash=='\\') |
| nextslash++; |
| if (!*nextslash) |
| nextslash=NULL; |
| } else if (*str == 0) |
| return NULL; |
| |
| |
| while (1) { |
| char *xs,*vs; |
| db=(struct dbW*)block; |
| xs= HEAP_strdupWtoA(GetProcessHeap(),0,db->name); |
| if (db->datalen) { |
| if (db->btext) |
| vs = HEAP_strdupWtoA(GetProcessHeap(),0,(WCHAR*)((block+DATA_OFFSET_W(db)))); |
| else |
| vs = HEAP_strdupA(GetProcessHeap(),0,"not a string"); |
| } else |
| vs = HEAP_strdupA(GetProcessHeap(),0,"no data"); |
| |
| TRACE(ver,"db->nextoff=%d,db->name=%s,db->data=\"%s\"\n", |
| db->nextoff,xs,vs |
| ); |
| HeapFree(GetProcessHeap(),0,vs); |
| HeapFree(GetProcessHeap(),0,xs); |
| if ((!db->nextoff) || (buff_remain<=0)) /* no more entries ? */ |
| return NULL; |
| |
| if (!lstrncmpi32W(db->name,str,substrlen)) { |
| if (nextslash) { |
| /* DATA_OFFSET_W(db) (padded to 32bit already) |
| * DATA[datalength] |
| * PADDING (round up to nearest 32bit boundary) |
| * --> next level structs |
| */ |
| inc_size=DATA_OFFSET_W(db)+((db->datalen+3)&~3); |
| return _find_dataW( block+inc_size ,nextslash, |
| db->nextoff-inc_size); |
| } else |
| return block; |
| } |
| /* skip over this block, round up to nearest 32bit boundary */ |
| inc_size = ((db->nextoff+3)&~3); |
| block += inc_size; |
| buff_remain -= inc_size; |
| } |
| } |
| |
| /* VerQueryValue [VER.11] */ |
| /* take care, 'buffer' is NOT a SEGPTR, it just points to one */ |
| DWORD WINAPI VerQueryValue16(SEGPTR segblock,LPCSTR subblock,SEGPTR *buffer, |
| UINT16 *buflen) |
| { |
| LPSTR s; |
| BYTE *block=PTR_SEG_TO_LIN(segblock),*b; |
| |
| TRACE(ver,"(%p,%s,%p,%d)\n", |
| block,subblock,buffer,*buflen |
| ); |
| |
| s=(char*)xmalloc(strlen("VS_VERSION_INFO\\")+strlen(subblock)+1); |
| strcpy(s,"VS_VERSION_INFO\\");strcat(s,subblock); |
| /* check for UNICODE version */ |
| if ( (*(DWORD*)(block+0x14) != VS_FFI_SIGNATURE) && |
| (*(DWORD*)(block+0x28) == VS_FFI_SIGNATURE) |
| ) { |
| struct dbW *db; |
| LPWSTR wstr; |
| LPSTR xs; |
| |
| wstr = HEAP_strdupAtoW(GetProcessHeap(),0,s); |
| b=_find_dataW(block,wstr,*(WORD*)block); |
| HeapFree(GetProcessHeap(),0,wstr); |
| if (!b) { |
| WARN(ver,"key %s not found in versionresource.\n",s); |
| *buflen=0; |
| free (s); |
| return 0; |
| } |
| db=(struct dbW*)b; |
| b = b+DATA_OFFSET_W(db); |
| *buflen = db->datalen; |
| if (db->btext) { |
| xs = HEAP_strdupWtoA(GetProcessHeap(),0,(WCHAR*)b); |
| TRACE(ver,"->%s\n",xs); |
| HeapFree(GetProcessHeap(),0,xs); |
| } else |
| TRACE(ver,"->%p\n",b); |
| } else { |
| struct dbA *db; |
| b=_find_dataA(block,s,*(WORD*)block); |
| if (!b) { |
| WARN(ver,"key %s not found in versionresource.\n",s); |
| *buflen=0; |
| free (s); |
| return 0; |
| } |
| db=(struct dbA*)b; |
| b = b+DATA_OFFSET_A(db); |
| *buflen = db->datalen; |
| /* the string is only printable, if it is below \\StringFileInfo*/ |
| if (!lstrncmpi32A("VS_VERSION_INFO\\StringFileInfo\\",s,strlen("VS_VERSION_INFO\\StringFileInfo\\"))) |
| TRACE(ver," -> %s=%s\n",subblock,b); |
| else |
| TRACE(ver," -> %s=%p\n",subblock,b); |
| } |
| *buffer = (b-block)+segblock; |
| free(s); |
| return 1; |
| } |
| |
| DWORD WINAPI VerQueryValue32A(LPVOID vblock,LPCSTR subblock, |
| LPVOID *vbuffer,UINT32 *buflen) |
| { |
| BYTE *b,*block=(LPBYTE)vblock,**buffer=(LPBYTE*)vbuffer; |
| LPSTR s; |
| |
| TRACE(ver,"(%p,%s,%p,%d)\n", |
| block,subblock,buffer,*buflen |
| ); |
| |
| s=(char*)xmalloc(strlen("VS_VERSION_INFO\\")+strlen(subblock)+1); |
| strcpy(s,"VS_VERSION_INFO\\");strcat(s,subblock); |
| |
| /* check for UNICODE version */ |
| if ( (*(DWORD*)(block+0x14) != VS_FFI_SIGNATURE) && |
| (*(DWORD*)(block+0x28) == VS_FFI_SIGNATURE) |
| ) { |
| LPWSTR wstr; |
| LPSTR xs; |
| struct dbW *db; |
| |
| wstr = HEAP_strdupAtoW(GetProcessHeap(),0,s); |
| b=_find_dataW(block,wstr,*(WORD*)block); |
| HeapFree(GetProcessHeap(),0,wstr); |
| if (!b) { |
| WARN(ver,"key %s not found in versionresource.\n",s); |
| *buflen=0; |
| free (s); |
| return 0; |
| } |
| db = (struct dbW*)b; |
| *buflen = db->datalen; |
| b = b+DATA_OFFSET_W(db); |
| if (db->btext) { |
| xs = HEAP_strdupWtoA(GetProcessHeap(),0,(WCHAR*)b); |
| TRACE(ver,"->%s\n",xs); |
| HeapFree(GetProcessHeap(),0,xs); |
| } else |
| TRACE(ver,"->%p\n",b); |
| /* This is a leak. */ |
| b = HEAP_strdupWtoA(GetProcessHeap(),0,(WCHAR*)b); |
| } else { |
| struct dbA *db; |
| b=_find_dataA(block,s,*(WORD*)block); |
| if (!b) { |
| WARN(ver,"key %s not found in versionresource.\n",subblock); |
| *buflen=0; |
| free (s); |
| return 0; |
| } |
| db=(struct dbA*)b; |
| *buflen = db->datalen; |
| b = b+DATA_OFFSET_A(db); |
| |
| /* the string is only printable, if it is below \\StringFileInfo*/ |
| if (!lstrncmpi32A("VS_VERSION_INFO\\StringFileInfo\\",s,strlen("VS_VERSION_INFO\\StringFileInfo\\"))) |
| TRACE(ver," -> %s=%s\n",subblock,b); |
| else |
| TRACE(ver," -> %s=%p\n",subblock,b); |
| } |
| *buffer = b; |
| free(s); |
| return 1; |
| } |
| |
| DWORD WINAPI VerQueryValue32W(LPVOID vblock,LPCWSTR subblock,LPVOID *vbuffer, |
| UINT32 *buflen) |
| { |
| LPSTR sb; |
| DWORD ret; |
| |
| sb = HEAP_strdupWtoA( GetProcessHeap(), 0, subblock ); |
| ret = VerQueryValue32A(vblock,sb,vbuffer,buflen); |
| HeapFree( GetProcessHeap(), 0, sb ); |
| return 1; |
| } |
| /* 20 GETFILEVERSIONINFORAW */ |