Sync EDKII BaseTools to BaseTools project r1903.
[efi/edk2/.git] / edk2 / BaseTools / Source / C / EfiLdrImage / EfiLdrImage.c
1 /** @file\r
2 \r
3 Copyright 2006 - 2010, Intel Corporation                                                         \r
4 All rights reserved. This program and the accompanying materials                          \r
5 are licensed and made available under the terms and conditions of the BSD License         \r
6 which accompanies this distribution.  The full text of the license may be found at        \r
7 http://opensource.org/licenses/bsd-license.php                                            \r
8 \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
11 \r
12 Module Name:\r
13 \r
14   efildrimage.c\r
15 \r
16 Abstract:\r
17 \r
18   Creates and EFILDR image.\r
19   This tool combines several PE Image files together using following format denoted as EBNF:\r
20   FILE := EFILDR_HEADER\r
21           EFILDR_IMAGE +\r
22           <PeImageFileContent> +\r
23   The order of EFILDR_IMAGE is same as the order of placing PeImageFileContent.\r
24 \r
25 Revision History\r
26 \r
27 **/\r
28 \r
29 \r
30 #include <stdio.h>\r
31 #include <stdlib.h>\r
32 #include <string.h>\r
33 #include "ParseInf.h"\r
34 #include "CommonLib.h"\r
35 #include "EfiUtilityMsgs.h"\r
36 \r
37 #define MAX_PE_IMAGES                  63\r
38 #define FILE_TYPE_FIXED_LOADER         0\r
39 #define FILE_TYPE_RELOCATABLE_PE_IMAGE 1\r
40 \r
41 typedef struct {\r
42   UINT32 CheckSum;\r
43   UINT32 Offset;\r
44   UINT32 Length;\r
45   UINT8  FileName[52];\r
46 } EFILDR_IMAGE;\r
47 \r
48 typedef struct {          \r
49   UINT32       Signature;     \r
50   UINT32       HeaderCheckSum;\r
51   UINT32       FileLength;\r
52   UINT32       NumberOfImages;\r
53 } EFILDR_HEADER;\r
54 \r
55 //\r
56 // Utility Name\r
57 //\r
58 #define UTILITY_NAME  "EfiLdrImage"\r
59 \r
60 //\r
61 // Utility version information\r
62 //\r
63 #define UTILITY_MAJOR_VERSION 0\r
64 #define UTILITY_MINOR_VERSION 1\r
65 \r
66 void\r
67 Version (\r
68   void\r
69   )\r
70 /*++\r
71 \r
72 Routine Description:\r
73 \r
74   Displays the standard utility information to SDTOUT\r
75 \r
76 Arguments:\r
77 \r
78   None\r
79 \r
80 Returns:\r
81 \r
82   None\r
83 \r
84 --*/\r
85 {\r
86   printf ("%s v%d.%d -Utility to break a file into two pieces at the request offset.\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION);\r
87   printf ("Copyright (c) 1999-2010 Intel Corporation. All rights reserved.\n");\r
88 }\r
89 \r
90 VOID\r
91 Usage (\r
92   VOID\r
93   )\r
94 {\r
95   printf ("Usage: EfiLdrImage -o OutImage LoaderImage PeImage1 PeImage2 ... PeImageN\n");\r
96   exit (1);\r
97 }\r
98 \r
99 EFI_STATUS\r
100 CountVerboseLevel (\r
101   IN CONST CHAR8* VerboseLevelString,\r
102   IN CONST UINT64 Length,\r
103   OUT UINT64 *ReturnValue\r
104 )\r
105 {\r
106   UINT64 i = 0;\r
107   for (;i < Length; ++i) {\r
108     if (VerboseLevelString[i] != 'v' && VerboseLevelString[i] != 'V') {\r
109       return EFI_ABORTED;\r
110     }\r
111     ++(*ReturnValue);\r
112   }\r
113   \r
114   return EFI_SUCCESS;\r
115 }\r
116 \r
117 UINT64\r
118 FCopyFile (\r
119   FILE    *in,\r
120   FILE    *out\r
121   )\r
122 /*++\r
123 Routine Description:\r
124   Write all the content of input file to output file.\r
125 \r
126 Arguments:\r
127   in  - input file pointer\r
128   out - output file pointer\r
129 \r
130 Return:\r
131   UINT64 : file size of input file\r
132 --*/\r
133 {\r
134   UINT32          filesize, offset, length;\r
135   CHAR8           Buffer[8*1024];\r
136 \r
137   fseek (in, 0, SEEK_END);\r
138   filesize = ftell(in);\r
139 \r
140   fseek (in, 0, SEEK_SET);\r
141 \r
142   offset = 0;\r
143   while (offset < filesize)  {\r
144     length = sizeof(Buffer);\r
145     if (filesize-offset < length) {\r
146       length = filesize-offset;\r
147     }\r
148 \r
149     fread (Buffer, length, 1, in);\r
150     fwrite (Buffer, length, 1, out);\r
151     offset += length;\r
152   }\r
153 \r
154   return filesize;\r
155 }\r
156 \r
157 \r
158 int\r
159 main (\r
160   int argc,\r
161   char *argv[]\r
162   )\r
163 /*++\r
164 \r
165 Routine Description:\r
166 \r
167 \r
168 Arguments:\r
169 \r
170 \r
171 Returns:\r
172 \r
173 \r
174 --*/\r
175 {\r
176   UINT64         i;\r
177   UINT64         filesize;\r
178   FILE          *fpIn, *fpOut;\r
179   EFILDR_HEADER EfiLdrHeader;\r
180   EFILDR_IMAGE  EfiLdrImage[MAX_PE_IMAGES];\r
181   CHAR8* OutputFileName = NULL;\r
182   CHAR8* InputFileNames[MAX_PE_IMAGES + 1];\r
183   UINT8 InputFileCount = 0;\r
184   BOOLEAN QuietFlag = FALSE;\r
185   UINT64        DebugLevel = 0;\r
186   UINT64        VerboseLevel = 0;\r
187   EFI_STATUS Status = EFI_SUCCESS;\r
188   \r
189   SetUtilityName (UTILITY_NAME);\r
190 \r
191   if (argc == 1) {\r
192     Usage();\r
193     return STATUS_ERROR;\r
194   }\r
195   \r
196   argc --;\r
197   argv ++;\r
198 \r
199   if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) {\r
200     Usage();\r
201     return STATUS_SUCCESS;    \r
202   }\r
203 \r
204   if (stricmp (argv[0], "--version") == 0) {\r
205     Version();\r
206     return STATUS_SUCCESS;    \r
207   }\r
208 \r
209   while (argc > 0) {\r
210    \r
211     if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--output") == 0)) {\r
212       OutputFileName = argv[1];\r
213       if (OutputFileName == NULL) {\r
214         Error (NULL, 0, 1003, "Invalid option value", "Output file can't be null");\r
215         return STATUS_ERROR;\r
216       }\r
217       argc -= 2;\r
218       argv += 2;\r
219       continue; \r
220     }\r
221     \r
222     if ((stricmp (argv[0], "-q") == 0) || (stricmp (argv[0], "--quiet") == 0)) {\r
223       QuietFlag = TRUE;\r
224       argc --;\r
225       argv ++;\r
226       continue; \r
227     }\r
228     \r
229     if ((strlen(argv[0]) >= 2 && argv[0][0] == '-' && (argv[0][1] == 'v' || argv[0][1] == 'V')) || (stricmp (argv[0], "--verbose") == 0)) {\r
230       VerboseLevel = 1;\r
231       if (strlen(argv[0]) > 2) {\r
232         Status = CountVerboseLevel (&argv[0][2], strlen(argv[0]) - 2, &VerboseLevel);\r
233         if (EFI_ERROR (Status)) {\r
234           Error (NULL, 0, 1003, "Invalid option value", argv[0]);\r
235           return STATUS_ERROR;        \r
236         }\r
237       }\r
238       \r
239       argc --;\r
240       argv ++;\r
241       continue; \r
242     }\r
243     \r
244     if ((stricmp (argv[0], "-d") == 0) || (stricmp (argv[0], "--debug") == 0)) {\r
245       Status = AsciiStringToUint64 (argv[1], FALSE, &DebugLevel);\r
246       if (EFI_ERROR (Status)) {\r
247         Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);\r
248         return STATUS_ERROR;        \r
249       }\r
250       argc -= 2;\r
251       argv += 2;\r
252       continue; \r
253     }\r
254     //\r
255     // Don't recognize the parameter, should be regarded as the input file name.\r
256     //\r
257     InputFileNames[InputFileCount] = argv[0];\r
258     InputFileCount++;\r
259     argc--;\r
260     argv++;\r
261   }\r
262 \r
263   if (InputFileCount == 0) {\r
264     Error (NULL, 0, 1001, "Missing option", "No input file");\r
265     return STATUS_ERROR;\r
266   }\r
267   //\r
268   // Open output file for write\r
269   //\r
270   if (OutputFileName == NULL) {\r
271     Error (NULL, 0, 1001, "Missing option", "No output file");\r
272     return STATUS_ERROR;\r
273   }\r
274 \r
275   fpOut = fopen(OutputFileName, "w+b");\r
276   if (!fpOut) {\r
277     Error (NULL, 0, 0001, "Could not open output file", OutputFileName);\r
278     return STATUS_ERROR;\r
279   }\r
280 \r
281   memset (&EfiLdrHeader, 0, sizeof (EfiLdrHeader));\r
282   memset (&EfiLdrImage, 0, sizeof (EFILDR_IMAGE) * (InputFileCount));\r
283 \r
284   memcpy (&EfiLdrHeader.Signature, "EFIL", 4);\r
285   EfiLdrHeader.FileLength = sizeof(EFILDR_HEADER) + sizeof(EFILDR_IMAGE)*(InputFileCount);\r
286 \r
287   //\r
288   // Skip the file header first\r
289   //\r
290   fseek (fpOut, EfiLdrHeader.FileLength, SEEK_SET);\r
291 \r
292   //\r
293   // copy all the input files to the output file\r
294   //\r
295   for(i=0;i<InputFileCount;i++) {\r
296     //\r
297     // Copy the content of PeImage file to output file\r
298     //\r
299     fpIn = fopen (InputFileNames[i], "rb");\r
300     if (!fpIn) {\r
301       Error (NULL, 0, 0001, "Could not open input file", InputFileNames[i]);\r
302       fclose (fpOut);\r
303       return STATUS_ERROR;\r
304     }\r
305     filesize = FCopyFile (fpIn, fpOut);\r
306     fclose(fpIn);\r
307 \r
308     //\r
309     //  And in the same time update the EfiLdrHeader and EfiLdrImage array\r
310     //\r
311     EfiLdrImage[i].Offset = EfiLdrHeader.FileLength;\r
312     EfiLdrImage[i].Length = (UINT32) filesize;\r
313     strncpy ((CHAR8*) EfiLdrImage[i].FileName, InputFileNames[i], sizeof (EfiLdrImage[i].FileName) - 1);\r
314     EfiLdrHeader.FileLength += (UINT32) filesize;\r
315     EfiLdrHeader.NumberOfImages++;\r
316   }\r
317 \r
318   //\r
319   // Write the image header to the output file finally\r
320   //\r
321   fseek (fpOut, 0, SEEK_SET);\r
322   fwrite (&EfiLdrHeader, sizeof(EFILDR_HEADER)        , 1, fpOut);\r
323   fwrite (&EfiLdrImage , sizeof(EFILDR_IMAGE)*(InputFileCount), 1, fpOut);\r
324 \r
325   fclose (fpOut);\r
326   printf ("Created %s\n", OutputFileName);\r
327   return 0;\r
328 }\r
329 \r