Commit | Line | Data |
---|---|---|
52302d4d LG |
1 | ## @file |
2 | # Patch value into the binary file. | |
3 | # | |
40d841f6 LG |
4 | # Copyright (c) 2010, Intel Corporation. All rights reserved.<BR> |
5 | # This program and the accompanying materials | |
52302d4d LG |
6 | # are licensed and made available under the terms and conditions of the BSD License |
7 | # which accompanies this distribution. The full text of the license may be found at | |
8 | # http://opensource.org/licenses/bsd-license.php | |
9 | # | |
10 | # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
11 | # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
12 | # | |
13 | ||
14 | ## | |
15 | # Import Modules | |
16 | # | |
17 | import os | |
18 | import sys | |
19 | import re | |
20 | ||
21 | from optparse import OptionParser | |
22 | from optparse import make_option | |
23 | from Common.BuildToolError import * | |
24 | import Common.EdkLogger as EdkLogger | |
b36d134f | 25 | from Common.BuildVersion import gBUILD_VERSION |
52302d4d LG |
26 | import array |
27 | ||
28 | # Version and Copyright | |
b36d134f | 29 | __version_number__ = ("0.10" + " " + gBUILD_VERSION) |
52302d4d LG |
30 | __version__ = "%prog Version " + __version_number__ |
31 | __copyright__ = "Copyright (c) 2010, Intel Corporation. All rights reserved." | |
32 | ||
33 | ## PatchBinaryFile method | |
34 | # | |
35 | # This method mainly patches the data into binary file. | |
36 | # | |
37 | # @param FileName File path of the binary file | |
38 | # @param ValueOffset Offset value | |
39 | # @param TypeName DataType Name | |
40 | # @param Value Value String | |
41 | # @param MaxSize MaxSize value | |
42 | # | |
43 | # @retval 0 File is updated successfully. | |
44 | # @retval not 0 File is updated failed. | |
45 | # | |
46 | def PatchBinaryFile(FileName, ValueOffset, TypeName, ValueString, MaxSize=0): | |
47 | # | |
48 | # Length of Binary File | |
49 | # | |
50 | FileHandle = open (FileName, 'rb') | |
51 | FileHandle.seek (0, 2) | |
52 | FileLength = FileHandle.tell() | |
53 | FileHandle.close() | |
54 | # | |
55 | # Unify string to upper string | |
56 | # | |
57 | TypeName = TypeName.upper() | |
58 | # | |
59 | # Get PCD value data length | |
60 | # | |
61 | ValueLength = 0 | |
62 | if TypeName == 'BOOLEAN': | |
63 | ValueLength = 1 | |
64 | elif TypeName == 'UINT8': | |
65 | ValueLength = 1 | |
66 | elif TypeName == 'UINT16': | |
67 | ValueLength = 2 | |
68 | elif TypeName == 'UINT32': | |
69 | ValueLength = 4 | |
70 | elif TypeName == 'UINT64': | |
71 | ValueLength = 8 | |
72 | elif TypeName == 'VOID*': | |
73 | if MaxSize == 0: | |
74 | return OPTION_MISSING, "PcdMaxSize is not specified for VOID* type PCD." | |
75 | ValueLength = MaxSize | |
76 | else: | |
77 | return PARAMETER_INVALID, "PCD type %s is not valid." %(CommandOptions.PcdTypeName) | |
78 | # | |
79 | # Check PcdValue is in the input binary file. | |
80 | # | |
81 | if ValueOffset + ValueLength > FileLength: | |
82 | return PARAMETER_INVALID, "PcdOffset + PcdMaxSize(DataType) is larger than the input file size." | |
83 | # | |
84 | # Read binary file into array | |
85 | # | |
86 | FileHandle = open (FileName, 'rb') | |
87 | ByteArray = array.array('B') | |
88 | ByteArray.fromfile(FileHandle, FileLength) | |
89 | FileHandle.close() | |
90 | OrigByteList = ByteArray.tolist() | |
91 | ByteList = ByteArray.tolist() | |
92 | # | |
93 | # Clear the data in file | |
94 | # | |
95 | for Index in range(ValueLength): | |
96 | ByteList[ValueOffset + Index] = 0 | |
97 | # | |
98 | # Patch value into offset | |
99 | # | |
100 | ValueString = ValueString.upper() | |
101 | ValueNumber = 0 | |
102 | if TypeName == 'BOOLEAN': | |
103 | # | |
104 | # Get PCD value for BOOLEAN data type | |
105 | # | |
106 | try: | |
107 | if ValueString == 'TRUE': | |
108 | ValueNumber = 1 | |
109 | elif ValueString == 'FALSE': | |
110 | ValueNumber = 0 | |
111 | elif ValueString.startswith('0X'): | |
112 | ValueNumber = int (Value, 16) | |
113 | else: | |
114 | ValueNumber = int (Value) | |
115 | if ValueNumber != 0: | |
116 | ValueNumber = 1 | |
117 | except: | |
118 | return PARAMETER_INVALID, "PCD Value %s is not valid dec or hex string." %(ValueString) | |
119 | # | |
120 | # Set PCD value into binary data | |
121 | # | |
122 | ByteList[ValueOffset] = ValueNumber | |
123 | elif TypeName in ['UINT8', 'UINT16', 'UINT32', 'UINT64']: | |
124 | # | |
125 | # Get PCD value for UINT* data type | |
126 | # | |
127 | try: | |
128 | if ValueString.startswith('0X'): | |
129 | ValueNumber = int (ValueString, 16) | |
130 | else: | |
131 | ValueNumber = int (ValueString) | |
132 | except: | |
133 | return PARAMETER_INVALID, "PCD Value %s is not valid dec or hex string." %(ValueString) | |
134 | # | |
135 | # Set PCD value into binary data | |
136 | # | |
137 | for Index in range(ValueLength): | |
138 | ByteList[ValueOffset + Index] = ValueNumber % 0x100 | |
139 | ValueNumber = ValueNumber / 0x100 | |
140 | elif TypeName == 'VOID*': | |
141 | if ValueString.startswith("L "): | |
142 | # | |
143 | # Patch Unicode String | |
144 | # | |
145 | Index = 0 | |
146 | for ByteString in ValueString[2:]: | |
147 | # | |
148 | # Reserve zero as unicode tail | |
149 | # | |
150 | if Index + 2 >= ValueLength: | |
151 | break | |
152 | # | |
153 | # Set string value one by one | |
154 | # | |
155 | ByteList[ValueOffset + Index] = ord(ByteString) | |
156 | Index = Index + 2 | |
157 | elif ValueString.startswith("{") and ValueString.endswith("}"): | |
158 | # | |
159 | # Patch {0x1, 0x2, ...} byte by byte | |
160 | # | |
161 | ValueList = ValueString[1 : len(ValueString) - 1].split(', ') | |
162 | Index = 0 | |
163 | try: | |
164 | for ByteString in ValueList: | |
165 | if ByteString.upper().startswith('0X'): | |
166 | ByteValue = int(ByteString, 16) | |
167 | else: | |
168 | ByteValue = int(ByteString) | |
169 | ByteList[ValueOffset + Index] = ByteValue % 0x100 | |
170 | Index = Index + 1 | |
171 | if Index >= ValueLength: | |
172 | break | |
173 | except: | |
174 | return PARAMETER_INVALID, "PCD Value %s is not valid dec or hex string array." %(ValueString) | |
175 | else: | |
176 | # | |
177 | # Patch ascii string | |
178 | # | |
179 | Index = 0 | |
180 | for ByteString in ValueString: | |
181 | # | |
182 | # Reserve zero as string tail | |
183 | # | |
184 | if Index + 1 >= ValueLength: | |
185 | break | |
186 | # | |
187 | # Set string value one by one | |
188 | # | |
189 | ByteList[ValueOffset + Index] = ord(ByteString) | |
190 | Index = Index + 1 | |
191 | # | |
192 | # Update new data into input file. | |
193 | # | |
194 | if ByteList != OrigByteList: | |
195 | ByteArray = array.array('B') | |
196 | ByteArray.fromlist(ByteList) | |
197 | FileHandle = open (FileName, 'wb') | |
198 | ByteArray.tofile(FileHandle) | |
199 | FileHandle.close() | |
200 | return 0, "Patch Value into File %s successfully." %(FileName) | |
201 | ||
202 | ## Parse command line options | |
203 | # | |
204 | # Using standard Python module optparse to parse command line option of this tool. | |
205 | # | |
206 | # @retval Options A optparse.Values object containing the parsed options | |
207 | # @retval InputFile Path of file to be trimmed | |
208 | # | |
209 | def Options(): | |
210 | OptionList = [ | |
211 | make_option("-f", "--offset", dest="PcdOffset", action="store", type="int", | |
212 | help="Start offset to the image is used to store PCD value."), | |
213 | make_option("-u", "--value", dest="PcdValue", action="store", | |
214 | help="PCD value will be updated into the image."), | |
215 | make_option("-t", "--type", dest="PcdTypeName", action="store", | |
216 | help="The name of PCD data type may be one of VOID*,BOOLEAN, UINT8, UINT16, UINT32, UINT64."), | |
217 | make_option("-s", "--maxsize", dest="PcdMaxSize", action="store", type="int", | |
218 | help="Max size of data buffer is taken by PCD value.It must be set when PCD type is VOID*."), | |
219 | make_option("-v", "--verbose", dest="LogLevel", action="store_const", const=EdkLogger.VERBOSE, | |
220 | help="Run verbosely"), | |
221 | make_option("-d", "--debug", dest="LogLevel", type="int", | |
222 | help="Run with debug information"), | |
223 | make_option("-q", "--quiet", dest="LogLevel", action="store_const", const=EdkLogger.QUIET, | |
224 | help="Run quietly"), | |
225 | make_option("-?", action="help", help="show this help message and exit"), | |
226 | ] | |
227 | ||
228 | # use clearer usage to override default usage message | |
229 | UsageString = "%prog -f Offset -u Value -t Type [-s MaxSize] <input_file>" | |
230 | ||
231 | Parser = OptionParser(description=__copyright__, version=__version__, option_list=OptionList, usage=UsageString) | |
232 | Parser.set_defaults(LogLevel=EdkLogger.INFO) | |
233 | ||
234 | Options, Args = Parser.parse_args() | |
235 | ||
236 | # error check | |
237 | if len(Args) == 0: | |
238 | EdkLogger.error("PatchPcdValue", PARAMETER_INVALID, ExtraData=Parser.get_usage()) | |
239 | ||
240 | InputFile = Args[len(Args) - 1] | |
241 | return Options, InputFile | |
242 | ||
243 | ## Entrance method | |
244 | # | |
245 | # This method mainly dispatch specific methods per the command line options. | |
246 | # If no error found, return zero value so the caller of this tool can know | |
247 | # if it's executed successfully or not. | |
248 | # | |
249 | # @retval 0 Tool was successful | |
250 | # @retval 1 Tool failed | |
251 | # | |
252 | def Main(): | |
253 | try: | |
254 | # | |
255 | # Check input parameter | |
256 | # | |
257 | EdkLogger.Initialize() | |
258 | CommandOptions, InputFile = Options() | |
259 | if CommandOptions.LogLevel < EdkLogger.DEBUG_9: | |
260 | EdkLogger.SetLevel(CommandOptions.LogLevel + 1) | |
261 | else: | |
262 | EdkLogger.SetLevel(CommandOptions.LogLevel) | |
263 | if not os.path.exists (InputFile): | |
264 | EdkLogger.error("PatchPcdValue", FILE_NOT_FOUND, ExtraData=InputFile) | |
265 | return 1 | |
266 | if CommandOptions.PcdOffset == None or CommandOptions.PcdValue == None or CommandOptions.PcdTypeName == None: | |
267 | EdkLogger.error("PatchPcdValue", OPTION_MISSING, ExtraData="PcdOffset or PcdValue of PcdTypeName is not specified.") | |
268 | return 1 | |
269 | if CommandOptions.PcdTypeName.upper() not in ["BOOLEAN", "UINT8", "UINT16", "UINT32", "UINT64", "VOID*"]: | |
270 | EdkLogger.error("PatchPcdValue", PARAMETER_INVALID, ExtraData="PCD type %s is not valid." %(CommandOptions.PcdTypeName)) | |
271 | return 1 | |
272 | if CommandOptions.PcdTypeName.upper() == "VOID*" and CommandOptions.PcdMaxSize == None: | |
273 | EdkLogger.error("PatchPcdValue", OPTION_MISSING, ExtraData="PcdMaxSize is not specified for VOID* type PCD.") | |
274 | return 1 | |
275 | # | |
276 | # Patch value into binary image. | |
277 | # | |
278 | ReturnValue, ErrorInfo = PatchBinaryFile (InputFile, CommandOptions.PcdOffset, CommandOptions.PcdTypeName, CommandOptions.PcdValue, CommandOptions.PcdMaxSize) | |
279 | if ReturnValue != 0: | |
280 | EdkLogger.error("PatchPcdValue", ReturnValue, ExtraData=ErrorInfo) | |
281 | return 1 | |
282 | return 0 | |
283 | except: | |
284 | return 1 | |
285 | ||
286 | if __name__ == '__main__': | |
287 | r = Main() | |
288 | sys.exit(r) |