tiny_impdef.c - converted to LF line-endings (and slight cleanup)
[tinycc/miki.git] / tiny_impdef.c
blob040c53acc7df3ce83bb4ed422ff59e0c296d678d
1 /* -------------------------------------------------------------- */
2 /*
3 * tiny_impdef creates an export definition file (.def) from a dll
4 * on MS-Windows. Usage: tiny_impdef library.dll [-o outputfile]"
5 *
6 * Copyright (c) 2005,2007 grischka
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #define WIN32_LEAN_AND_MEAN
24 #include <windows.h>
25 #include <stdio.h>
27 /* Offset to PE file signature */
28 #define NTSIGNATURE(a) ((LPVOID)((BYTE *)a + \
29 ((PIMAGE_DOS_HEADER)a)->e_lfanew))
31 /* MS-OS header identifies the NT PEFile signature dword;
32 the PEFILE header exists just after that dword. */
33 #define PEFHDROFFSET(a) ((LPVOID)((BYTE *)a + \
34 ((PIMAGE_DOS_HEADER)a)->e_lfanew + \
35 SIZE_OF_NT_SIGNATURE))
37 /* PE optional header is immediately after PEFile header. */
38 #define OPTHDROFFSET(a) ((LPVOID)((BYTE *)a + \
39 ((PIMAGE_DOS_HEADER)a)->e_lfanew + \
40 SIZE_OF_NT_SIGNATURE + \
41 sizeof (IMAGE_FILE_HEADER)))
43 /* Section headers are immediately after PE optional header. */
44 #define SECHDROFFSET(a) ((LPVOID)((BYTE *)a + \
45 ((PIMAGE_DOS_HEADER)a)->e_lfanew + \
46 SIZE_OF_NT_SIGNATURE + \
47 sizeof (IMAGE_FILE_HEADER) + \
48 sizeof (IMAGE_OPTIONAL_HEADER)))
51 #define SIZE_OF_NT_SIGNATURE 4
53 /* -------------------------------------------------------------- */
55 int WINAPI NumOfSections (
56 LPVOID lpFile)
58 /* Number of sections is indicated in file header. */
59 return (int)
60 ((PIMAGE_FILE_HEADER)
61 PEFHDROFFSET(lpFile))->NumberOfSections;
65 /* -------------------------------------------------------------- */
67 LPVOID WINAPI ImageDirectoryOffset (
68 LPVOID lpFile,
69 DWORD dwIMAGE_DIRECTORY)
71 PIMAGE_OPTIONAL_HEADER poh;
72 PIMAGE_SECTION_HEADER psh;
73 int nSections = NumOfSections (lpFile);
74 int i = 0;
75 LPVOID VAImageDir;
77 /* Retrieve offsets to optional and section headers. */
78 poh = (PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET (lpFile);
79 psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET (lpFile);
81 /* Must be 0 thru (NumberOfRvaAndSizes-1). */
82 if (dwIMAGE_DIRECTORY >= poh->NumberOfRvaAndSizes)
83 return NULL;
85 /* Locate image directory's relative virtual address. */
86 VAImageDir = (LPVOID)poh->DataDirectory[dwIMAGE_DIRECTORY].VirtualAddress;
88 /* Locate section containing image directory. */
89 while (i++<nSections)
91 if (psh->VirtualAddress <= (DWORD)VAImageDir
92 && psh->VirtualAddress + psh->SizeOfRawData > (DWORD)VAImageDir)
93 break;
94 psh++;
97 if (i > nSections)
98 return NULL;
100 /* Return image import directory offset. */
101 return (LPVOID)(((int)lpFile +
102 (int)VAImageDir - psh->VirtualAddress) +
103 (int)psh->PointerToRawData);
106 /* -------------------------------------------------------------- */
108 BOOL WINAPI GetSectionHdrByName (
109 LPVOID lpFile,
110 IMAGE_SECTION_HEADER *sh,
111 char *szSection)
113 PIMAGE_SECTION_HEADER psh;
114 int nSections = NumOfSections (lpFile);
115 int i;
117 if ((psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET (lpFile)) != NULL)
119 /* find the section by name */
120 for (i=0; i<nSections; i++)
122 if (!strcmp (psh->Name, szSection))
124 /* copy data to header */
125 memcpy ((LPVOID)sh, (LPVOID)psh, sizeof (IMAGE_SECTION_HEADER));
126 return TRUE;
128 else
129 psh++;
132 return FALSE;
135 /* -------------------------------------------------------------- */
137 BOOL WINAPI GetSectionHdrByAddress (
138 LPVOID lpFile,
139 IMAGE_SECTION_HEADER *sh,
140 DWORD addr)
142 PIMAGE_SECTION_HEADER psh;
143 int nSections = NumOfSections (lpFile);
144 int i;
146 if ((psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET (lpFile)) != NULL)
148 /* find the section by name */
149 for (i=0; i<nSections; i++)
151 if (addr >= psh->VirtualAddress
152 && addr < psh->VirtualAddress + psh->SizeOfRawData)
154 /* copy data to header */
155 memcpy ((LPVOID)sh, (LPVOID)psh, sizeof (IMAGE_SECTION_HEADER));
156 return TRUE;
158 else
159 psh++;
162 return FALSE;
165 /* -------------------------------------------------------------- */
167 int WINAPI GetExportFunctionNames (
168 LPVOID lpFile,
169 HANDLE hHeap,
170 char **pszFunctions)
172 IMAGE_SECTION_HEADER sh;
173 PIMAGE_EXPORT_DIRECTORY ped;
174 int *pNames, *pCnt;
175 char *pSrc, *pDest;
176 int i, nCnt;
177 DWORD VAImageDir;
178 PIMAGE_OPTIONAL_HEADER poh;
179 char *pOffset;
181 /* Get section header and pointer to data directory
182 for .edata section. */
183 if (NULL == (ped = (PIMAGE_EXPORT_DIRECTORY)
184 ImageDirectoryOffset (lpFile, IMAGE_DIRECTORY_ENTRY_EXPORT)))
185 return 0;
187 poh = (PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET (lpFile);
188 VAImageDir = poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
190 if (FALSE == GetSectionHdrByAddress (lpFile, &sh, VAImageDir))
191 return 0;
193 pOffset = (char *)lpFile + (sh.PointerToRawData - sh.VirtualAddress);
195 pNames = (int *)(pOffset + (DWORD)ped->AddressOfNames);
197 /* Figure out how much memory to allocate for all strings. */
198 nCnt = 1;
199 for (i=0, pCnt = pNames; i<(int)ped->NumberOfNames; i++)
201 pSrc = (pOffset + *pCnt++);
202 if (pSrc)
203 nCnt += strlen(pSrc)+1;
206 /* Allocate memory off heap for function names. */
207 pDest = *pszFunctions = HeapAlloc (hHeap, HEAP_ZERO_MEMORY, nCnt);
209 /* Copy all strings to buffer. */
210 for (i=0, pCnt = pNames; i<(int)ped->NumberOfNames; i++)
212 pSrc = (pOffset + *pCnt++);
213 if (pSrc) {
214 strcpy(pDest, pSrc);
215 pDest += strlen(pSrc)+1;
218 *pDest = 0;
220 return ped->NumberOfNames;
223 /* -------------------------------------------------------------- */
224 /* extract the basename of a file */
226 static char *file_basename(const char *name)
228 const char *p = strchr(name, 0);
229 while (p > name
230 && p[-1] != '/'
231 && p[-1] != '\\'
233 --p;
234 return (char*)p;
237 /* -------------------------------------------------------------- */
239 int main(int argc, char **argv)
241 HANDLE hHeap;
242 HANDLE hFile;
243 HANDLE hMapObject;
244 VOID *pMem;
246 int nCnt, ret, n;
247 char *pNames;
248 char infile[MAX_PATH];
249 char buffer[MAX_PATH];
250 char outfile[MAX_PATH];
251 FILE *op;
252 char *p;
254 hHeap = NULL;
255 hFile = NULL;
256 hMapObject = NULL;
257 pMem = NULL;
258 infile[0] = 0;
259 outfile[0] = 0;
260 ret = 1;
262 for (n = 1; n < argc; ++n)
264 const char *a = argv[n];
265 if ('-' == a[0]) {
266 if (0 == strcmp(a, "-o")) {
267 if (++n == argc)
268 goto usage;
269 strcpy(outfile, argv[n]);
271 else
272 goto usage;
274 } else if (0 == infile[0])
275 strcpy(infile, a);
276 else
277 goto usage;
280 if (0 == infile[0])
282 usage:
283 fprintf(stderr,
284 "tiny_impdef creates an export definition file (.def) from a dll\n"
285 "Usage: tiny_impdef library.dll [-o outputfile]\n"
287 goto the_end;
290 if (SearchPath(NULL, infile, ".dll", sizeof buffer, buffer, NULL))
291 strcpy(infile, buffer);
293 if (0 == outfile[0])
295 char *p;
296 strcpy(outfile, file_basename(infile));
297 p = strrchr(outfile, '.');
298 if (NULL == p)
299 p = strchr(outfile, 0);
300 strcpy(p, ".def");
303 hFile = CreateFile(
304 infile,
305 GENERIC_READ,
306 FILE_SHARE_READ,
307 NULL,
308 OPEN_EXISTING,
310 NULL
313 if (hFile == INVALID_HANDLE_VALUE)
315 fprintf(stderr, "No such file: %s\n", infile);
316 goto the_end;
320 hMapObject = CreateFileMapping(
321 hFile,
322 NULL,
323 PAGE_READONLY,
324 0, 0,
325 NULL
328 if (NULL == hMapObject)
330 fprintf(stderr, "Could not create file mapping: %s\n", infile);
331 goto the_end;
334 pMem = MapViewOfFile(
335 hMapObject, // object to map view of
336 FILE_MAP_READ, // read access
337 0, // high offset: map from
338 0, // low offset: beginning
339 0); // default: map entire file
341 if (NULL == pMem)
343 fprintf(stderr, "Could not map view of file: %s\n", infile);
344 goto the_end;
347 if (0 != strncmp(NTSIGNATURE(pMem), "PE", 2))
349 fprintf(stderr, "Not a PE file: %s\n", infile);
350 goto the_end;
354 hHeap = GetProcessHeap();
355 nCnt = GetExportFunctionNames(pMem, hHeap, &pNames);
356 if (0 == nCnt) {
357 fprintf(stderr, "Could not get exported function names: %s\n", infile);
358 goto the_end;
361 printf("--> %s\n", infile);
363 op = fopen(outfile, "w");
364 if (NULL == op)
366 fprintf(stderr, "Could not create file: %s\n", outfile);
367 goto the_end;
370 printf("<-- %s\n", outfile);
372 fprintf(op, "LIBRARY %s\n\nEXPORTS\n", file_basename(infile));
373 for (n = 0, p = pNames; n < nCnt; ++n)
375 fprintf(op, "%s\n", p);
376 while (*p++);
378 ret = 0;
380 the_end:
381 if (pMem)
382 UnmapViewOfFile(pMem);
384 if (hMapObject)
385 CloseHandle(hMapObject);
387 if (hFile)
388 CloseHandle(hFile);
390 return ret;
393 /* -------------------------------------------------------------- */