|  | /* | 
|  | This Software is provided under the Zope Public License (ZPL) Version 2.1. | 
|  |  | 
|  | Copyright (c) 2009, 2010 by the mingw-w64 project | 
|  |  | 
|  | Written by Kai Tietz. | 
|  |  | 
|  | This license has been certified as open source. It has also been designated | 
|  | as GPL compatible by the Free Software Foundation (FSF). | 
|  |  | 
|  | Redistribution and use in source and binary forms, with or without | 
|  | modification, are permitted provided that the following conditions are met: | 
|  |  | 
|  | 1. Redistributions in source code must retain the accompanying copyright | 
|  | notice, this list of conditions, and the following disclaimer. | 
|  | 2. Redistributions in binary form must reproduce the accompanying | 
|  | copyright notice, this list of conditions, and the following disclaimer | 
|  | in the documentation and/or other materials provided with the | 
|  | distribution. | 
|  | 3. Names of the copyright holders must not be used to endorse or promote | 
|  | products derived from this software without prior written permission | 
|  | from the copyright holders. | 
|  | 4. The right to distribute this software or to use it for any purpose does | 
|  | not give you the right to use Servicemarks (sm) or Trademarks (tm) of | 
|  | the copyright holders.  Use of them is covered by separate agreement | 
|  | with the copyright holders. | 
|  | 5. If any files are modified, you must cause the modified files to carry | 
|  | prominent notices stating that you changed the files and the date of | 
|  | any change. | 
|  |  | 
|  | Disclaimer | 
|  |  | 
|  | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED | 
|  | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | 
|  | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO | 
|  | EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, | 
|  | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
|  | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, | 
|  | OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | 
|  | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | 
|  | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | 
|  | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
|  | */ | 
|  |  | 
|  | #define _CRT_SECURE_NO_WARNINGS | 
|  | #include "genidl_cfg.h" | 
|  |  | 
|  | #include "genidl_readpe.h" | 
|  |  | 
|  | static int32_t readResourceDirectory (FILE *fp, unsigned char **dta, size_t *length, size_t *resRVA); | 
|  |  | 
|  | static void walk_res_dir (sImgResourceDirectory *resDir, unsigned char *base,uint32_t level, uint32_t resourceType, int32_t beTypelib, int32_t *noRes,uint32_t *zOff, uint32_t *zSize); | 
|  |  | 
|  | int32_t | 
|  | genidl_pe_typelib_resource_count (FILE *fp) | 
|  | { | 
|  | int32_t cnt = 0x2000; | 
|  | uint32_t zOff = 0,zSize = 0; | 
|  | size_t resRVA = 0; | 
|  | unsigned char *dta = NULL; | 
|  | size_t length = 0; | 
|  | if (!readResourceDirectory (fp, &dta, &length,&resRVA)) | 
|  | return 0; | 
|  | if (!length || !dta) | 
|  | return 0; | 
|  | zOff = zSize = 0; | 
|  | walk_res_dir ((sImgResourceDirectory *) dta, dta,0, 0, 0, &cnt,&zOff,&zSize); | 
|  | free (dta); | 
|  | return 0x2000 - cnt; | 
|  | } | 
|  |  | 
|  | int32_t | 
|  | genidl_pe_typelib_resource_read (FILE *fp, int32_t noRes, unsigned char **pDta, size_t *szDta) | 
|  | { | 
|  | uint32_t zOff,zSize; | 
|  | unsigned char *dta = NULL; | 
|  | size_t length = 0; | 
|  | size_t resRVA = 0; | 
|  | if (!readResourceDirectory (fp, &dta, &length, &resRVA)) | 
|  | return 0; | 
|  | if (!length || !dta) | 
|  | return 0; | 
|  | zOff = zSize = 0; | 
|  | walk_res_dir ((sImgResourceDirectory *) dta, dta,0, 0, 0, &noRes,&zOff,&zSize); | 
|  | if (zOff != 0) | 
|  | { | 
|  | pDta[0] = (unsigned char *) malloc (zSize + 1); | 
|  | szDta[0] = zSize; | 
|  |  | 
|  | memcpy (pDta[0], dta + zOff - resRVA , zSize); | 
|  | free (dta); | 
|  | return 1; | 
|  | } | 
|  | free (dta); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static void get_res_name_by_id (uint32_t id, unsigned char *resourceBase, char *buffer, uint32_t cBytes); | 
|  | static void walk_res_entry (sImgResourceDirectoryEntry *resDirEntry, unsigned char *resourceBase, uint32_t level, int32_t beTypelib, int32_t *noRes,uint32_t *zOff,uint32_t *zSize); | 
|  |  | 
|  | static void | 
|  | walk_res_dir (sImgResourceDirectory *resDir, unsigned char *base,uint32_t level, uint32_t resourceType, int32_t beTypelib, int32_t *noRes,uint32_t *zOff,uint32_t *zSize) | 
|  | { | 
|  | sImgResourceDirectoryEntry *resDirEntry; | 
|  | char szType[64]; | 
|  | uint32_t i; | 
|  | uint32_t mloop = 0; | 
|  |  | 
|  | if (resourceType & GENIDL_IMG_RESNAME_IS_STR) | 
|  | { | 
|  | get_res_name_by_id (resourceType, base,szType, sizeof(szType)); | 
|  | } | 
|  | else | 
|  | sprintf(szType, "%X", resourceType); | 
|  | if (!strcmp (szType,"TYPELIB")) | 
|  | beTypelib = 1; | 
|  |  | 
|  | resDirEntry = (sImgResourceDirectoryEntry *) (resDir + 1); | 
|  |  | 
|  | mloop = resDir->NumberOfNamedEntries + resDir->NumberOfIdEntries; | 
|  |  | 
|  | for (i=0; i < mloop; i++, resDirEntry++) | 
|  | { | 
|  | walk_res_entry (resDirEntry, base, level + 1, beTypelib, noRes,zOff,zSize); | 
|  | if (zOff[0] != 0) | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (!strcmp (szType,"TYPELIB")) | 
|  | beTypelib = 0; | 
|  | } | 
|  |  | 
|  | static void | 
|  | walk_res_entry (sImgResourceDirectoryEntry *resDirEntry, unsigned char *resourceBase, uint32_t level, int32_t beTypelib,int32_t *noRes,uint32_t *zOff,uint32_t *zSize) | 
|  | { | 
|  | sImgResourceDataEntry *pResDataEntry; | 
|  | if (resDirEntry->OffsetToData & GENIDL_IMG_RESDATA_IS_DIR) { | 
|  | walk_res_dir ((sImgResourceDirectory *) ((resDirEntry->OffsetToData & 0x7FFFFFFF) + resourceBase), | 
|  | resourceBase, level, resDirEntry->Name, beTypelib, noRes,zOff,zSize); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (!beTypelib) | 
|  | return; | 
|  | if (noRes[0] != 0) | 
|  | { | 
|  | noRes[0] -= 1; | 
|  | return; | 
|  | } | 
|  | pResDataEntry = (sImgResourceDataEntry *) | 
|  | (resourceBase + resDirEntry->OffsetToData); | 
|  | zOff[0] = pResDataEntry->OffsetToData; /* RVA!!! */ | 
|  | zSize[0] = pResDataEntry->Size; | 
|  | } | 
|  |  | 
|  | static void | 
|  | get_res_name_by_id (uint32_t id, unsigned char *resourceBase, char *buffer, uint32_t cBytes) | 
|  | { | 
|  | sImgResourceDirStringWC *prdsu; | 
|  |  | 
|  | if ( !(id & GENIDL_IMG_RESNAME_IS_STR) ) | 
|  | { | 
|  | sprintf (buffer, "%X", id); | 
|  | return; | 
|  | } | 
|  |  | 
|  | id &= 0x7FFFFFFF; | 
|  | prdsu = (sImgResourceDirStringWC *) (resourceBase + id); | 
|  |  | 
|  | #ifdef _WIN32 | 
|  | WideCharToMultiByte(CP_ACP, 0, prdsu->NameString, prdsu->Length, buffer, cBytes, 0, 0); | 
|  | buffer[min(cBytes - 1, prdsu->Length)] = 0;  /* Null terminate it!!! */ | 
|  | #else | 
|  | { | 
|  | uint32_t mi = cBytes - 1; | 
|  | uint32_t i; | 
|  | if (mi > prdsu->Length) | 
|  | mi = prdsu->Length; | 
|  | for (i = 0; i < mi; i++) | 
|  | { | 
|  | uint16_t ch = prdsu->NameString[i]; | 
|  | if (!ch) | 
|  | break; | 
|  | if (ch >= 128) | 
|  | ch = '?'; | 
|  | buffer[i] = (char) (ch & 0xff); | 
|  | } | 
|  | buffer[i] = 0; | 
|  | } | 
|  | #endif | 
|  | } | 
|  |  | 
|  | static int32_t | 
|  | readResourceDirectory (FILE *fp, unsigned char **dta, size_t *length, size_t *resRVA) | 
|  | { | 
|  | long pe_header; | 
|  | int32_t be64; | 
|  | uImgHeader hdr; | 
|  | uint32_t res_size = 0; | 
|  | uint32_t sect_count; | 
|  | sImgSectionHdr sec; | 
|  |  | 
|  | pe_header = genidl_ispe (fp, &be64); | 
|  | *dta = NULL; length[0]=0; | 
|  | if (!pe_header) | 
|  | return 0; | 
|  | fseek (fp, pe_header, SEEK_SET); | 
|  | if (be64) | 
|  | { | 
|  | fread (&hdr.hdr64, 1, sizeof (sImgNtHeaders64), fp); | 
|  | res_size = hdr.hdr64.OptionalHeader.DataDirectory[2].size; | 
|  | sect_count = hdr.hdr64.FileHeader.NumberOfSections; | 
|  | } | 
|  | else | 
|  | { | 
|  | fread (&hdr.hdr32, 1, sizeof (sImgNtHeaders32), fp); | 
|  | res_size = hdr.hdr32.OptionalHeader.DataDirectory[2].size; | 
|  | sect_count = hdr.hdr32.FileHeader.NumberOfSections; | 
|  | } | 
|  | if (!res_size) | 
|  | return 1; | 
|  | while (sect_count > 0) | 
|  | { | 
|  | fread (&sec, 1, sizeof (sImgSectionHdr),fp); | 
|  | if (!strcmp ((char *) sec.Name, ".rsrc")) | 
|  | { | 
|  | fseek (fp, (int32_t) sec.PointerToRawData, SEEK_SET); | 
|  | resRVA[0] = sec.VirtualAddress; | 
|  | dta[0] = (unsigned char *) malloc (res_size); | 
|  | fread (dta[0], 1, res_size, fp); | 
|  | length[0] = res_size; | 
|  | return 1; | 
|  | } | 
|  | sect_count--; | 
|  | } | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | int32_t | 
|  | genidl_ispe (FILE *fp, int32_t *be64) | 
|  | { | 
|  | sDosHeader hdr; | 
|  | uImgHeader img; | 
|  |  | 
|  | *be64 = 0; | 
|  | fseek(fp, 0, SEEK_SET); | 
|  | if (fread (&hdr, 1, sizeof (hdr), fp) !=  sizeof (hdr)) | 
|  | return 0; | 
|  | if (hdr.magic != 0x5a4d) | 
|  | return 0; | 
|  | if (hdr.lfanew == 0) | 
|  | return 0; | 
|  | fseek (fp, (int32_t) hdr.lfanew, SEEK_SET); | 
|  | if (fread (&img, 1, sizeof (img), fp) != sizeof (img)) | 
|  | return 0; | 
|  | if (img.hdr32.Signature != 0x4550) | 
|  | return 0; | 
|  | if (img.hdr32.FileHeader.SizeOfOptionalHeader == IMG_SIZEOF_NT_OPTIONAL32_HEADER) | 
|  | *be64 = 0; | 
|  | else if (img.hdr32.FileHeader.SizeOfOptionalHeader == IMG_SIZEOF_NT_OPTIONAL64_HEADER) | 
|  | *be64 = 1; | 
|  | else | 
|  | return 0; | 
|  | return (int32_t) hdr.lfanew; | 
|  | } |