2 # Patch value into the binary file.
4 # Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
5 # This program and the accompanying materials
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
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.
17 import Common
.LongFilePathOs
as os
18 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
22 from optparse
import OptionParser
23 from optparse
import make_option
24 from Common
.BuildToolError
import *
25 import Common
.EdkLogger
as EdkLogger
26 from Common
.BuildVersion
import gBUILD_VERSION
28 from Common
.DataType
import *
30 # Version and Copyright
31 __version_number__
= ("0.10" + " " + gBUILD_VERSION
)
32 __version__
= "%prog Version " + __version_number__
33 __copyright__
= "Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved."
35 ## PatchBinaryFile method
37 # This method mainly patches the data into binary file.
39 # @param FileName File path of the binary file
40 # @param ValueOffset Offset value
41 # @param TypeName DataType Name
42 # @param Value Value String
43 # @param MaxSize MaxSize value
45 # @retval 0 File is updated successfully.
46 # @retval not 0 File is updated failed.
48 def PatchBinaryFile(FileName
, ValueOffset
, TypeName
, ValueString
, MaxSize
=0):
50 # Length of Binary File
52 FileHandle
= open(FileName
, 'rb')
53 FileHandle
.seek (0, 2)
54 FileLength
= FileHandle
.tell()
57 # Unify string to upper string
59 TypeName
= TypeName
.upper()
61 # Get PCD value data length
64 if TypeName
== 'BOOLEAN':
66 elif TypeName
== TAB_UINT8
:
68 elif TypeName
== TAB_UINT16
:
70 elif TypeName
== TAB_UINT32
:
72 elif TypeName
== TAB_UINT64
:
74 elif TypeName
== TAB_VOID
:
76 return OPTION_MISSING
, "PcdMaxSize is not specified for VOID* type PCD."
77 ValueLength
= int(MaxSize
)
79 return PARAMETER_INVALID
, "PCD type %s is not valid." % (CommandOptions
.PcdTypeName
)
81 # Check PcdValue is in the input binary file.
83 if ValueOffset
+ ValueLength
> FileLength
:
84 return PARAMETER_INVALID
, "PcdOffset + PcdMaxSize(DataType) is larger than the input file size."
86 # Read binary file into array
88 FileHandle
= open(FileName
, 'rb')
89 ByteArray
= array
.array('B')
90 ByteArray
.fromfile(FileHandle
, FileLength
)
92 OrigByteList
= ByteArray
.tolist()
93 ByteList
= ByteArray
.tolist()
95 # Clear the data in file
97 for Index
in range(ValueLength
):
98 ByteList
[ValueOffset
+ Index
] = 0
100 # Patch value into offset
102 SavedStr
= ValueString
103 ValueString
= ValueString
.upper()
105 if TypeName
== 'BOOLEAN':
107 # Get PCD value for BOOLEAN data type
110 if ValueString
== 'TRUE':
112 elif ValueString
== 'FALSE':
114 ValueNumber
= int (ValueString
, 0)
118 return PARAMETER_INVALID
, "PCD Value %s is not valid dec or hex string." % (ValueString
)
120 # Set PCD value into binary data
122 ByteList
[ValueOffset
] = ValueNumber
123 elif TypeName
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
125 # Get PCD value for UINT* data type
128 ValueNumber
= int (ValueString
, 0)
130 return PARAMETER_INVALID
, "PCD Value %s is not valid dec or hex string." % (ValueString
)
132 # Set PCD value into binary data
134 for Index
in range(ValueLength
):
135 ByteList
[ValueOffset
+ Index
] = ValueNumber
% 0x100
136 ValueNumber
= ValueNumber
/ 0x100
137 elif TypeName
== TAB_VOID
:
138 ValueString
= SavedStr
139 if ValueString
.startswith('L"'):
141 # Patch Unicode String
144 for ByteString
in ValueString
[2:-1]:
146 # Reserve zero as unicode tail
148 if Index
+ 2 >= ValueLength
:
151 # Set string value one by one
153 ByteList
[ValueOffset
+ Index
] = ord(ByteString
)
155 elif ValueString
.startswith("{") and ValueString
.endswith("}"):
157 # Patch {0x1, 0x2, ...} byte by byte
159 ValueList
= ValueString
[1 : len(ValueString
) - 1].split(',')
162 for ByteString
in ValueList
:
163 ByteString
= ByteString
.strip()
164 if ByteString
.upper().startswith('0X'):
165 ByteValue
= int(ByteString
, 16)
167 ByteValue
= int(ByteString
)
168 ByteList
[ValueOffset
+ Index
] = ByteValue
% 0x100
170 if Index
>= ValueLength
:
173 return PARAMETER_INVALID
, "PCD Value %s is not valid dec or hex string array." % (ValueString
)
179 for ByteString
in ValueString
[1:-1]:
181 # Reserve zero as string tail
183 if Index
+ 1 >= ValueLength
:
186 # Set string value one by one
188 ByteList
[ValueOffset
+ Index
] = ord(ByteString
)
191 # Update new data into input file.
193 if ByteList
!= OrigByteList
:
194 ByteArray
= array
.array('B')
195 ByteArray
.fromlist(ByteList
)
196 FileHandle
= open(FileName
, 'wb')
197 ByteArray
.tofile(FileHandle
)
199 return 0, "Patch Value into File %s successfully." % (FileName
)
201 ## Parse command line options
203 # Using standard Python module optparse to parse command line option of this tool.
205 # @retval Options A optparse.Values object containing the parsed options
206 # @retval InputFile Path of file to be trimmed
210 make_option("-f", "--offset", dest
="PcdOffset", action
="store", type="int",
211 help="Start offset to the image is used to store PCD value."),
212 make_option("-u", "--value", dest
="PcdValue", action
="store",
213 help="PCD value will be updated into the image."),
214 make_option("-t", "--type", dest
="PcdTypeName", action
="store",
215 help="The name of PCD data type may be one of VOID*,BOOLEAN, UINT8, UINT16, UINT32, UINT64."),
216 make_option("-s", "--maxsize", dest
="PcdMaxSize", action
="store", type="int",
217 help="Max size of data buffer is taken by PCD value.It must be set when PCD type is VOID*."),
218 make_option("-v", "--verbose", dest
="LogLevel", action
="store_const", const
=EdkLogger
.VERBOSE
,
219 help="Run verbosely"),
220 make_option("-d", "--debug", dest
="LogLevel", type="int",
221 help="Run with debug information"),
222 make_option("-q", "--quiet", dest
="LogLevel", action
="store_const", const
=EdkLogger
.QUIET
,
224 make_option("-?", action
="help", help="show this help message and exit"),
227 # use clearer usage to override default usage message
228 UsageString
= "%prog -f Offset -u Value -t Type [-s MaxSize] <input_file>"
230 Parser
= OptionParser(description
=__copyright__
, version
=__version__
, option_list
=OptionList
, usage
=UsageString
)
231 Parser
.set_defaults(LogLevel
=EdkLogger
.INFO
)
233 Options
, Args
= Parser
.parse_args()
237 EdkLogger
.error("PatchPcdValue", PARAMETER_INVALID
, ExtraData
=Parser
.get_usage())
239 InputFile
= Args
[len(Args
) - 1]
240 return Options
, InputFile
244 # This method mainly dispatch specific methods per the command line options.
245 # If no error found, return zero value so the caller of this tool can know
246 # if it's executed successfully or not.
248 # @retval 0 Tool was successful
249 # @retval 1 Tool failed
254 # Check input parameter
256 EdkLogger
.Initialize()
257 CommandOptions
, InputFile
= Options()
258 if CommandOptions
.LogLevel
< EdkLogger
.DEBUG_9
:
259 EdkLogger
.SetLevel(CommandOptions
.LogLevel
+ 1)
261 EdkLogger
.SetLevel(CommandOptions
.LogLevel
)
262 if not os
.path
.exists (InputFile
):
263 EdkLogger
.error("PatchPcdValue", FILE_NOT_FOUND
, ExtraData
=InputFile
)
265 if CommandOptions
.PcdOffset
is None or CommandOptions
.PcdValue
is None or CommandOptions
.PcdTypeName
is None:
266 EdkLogger
.error("PatchPcdValue", OPTION_MISSING
, ExtraData
="PcdOffset or PcdValue of PcdTypeName is not specified.")
268 if CommandOptions
.PcdTypeName
.upper() not in TAB_PCD_NUMERIC_TYPES_VOID
:
269 EdkLogger
.error("PatchPcdValue", PARAMETER_INVALID
, ExtraData
="PCD type %s is not valid." % (CommandOptions
.PcdTypeName
))
271 if CommandOptions
.PcdTypeName
.upper() == TAB_VOID
and CommandOptions
.PcdMaxSize
is None:
272 EdkLogger
.error("PatchPcdValue", OPTION_MISSING
, ExtraData
="PcdMaxSize is not specified for VOID* type PCD.")
275 # Patch value into binary image.
277 ReturnValue
, ErrorInfo
= PatchBinaryFile (InputFile
, CommandOptions
.PcdOffset
, CommandOptions
.PcdTypeName
, CommandOptions
.PcdValue
, CommandOptions
.PcdMaxSize
)
279 EdkLogger
.error("PatchPcdValue", ReturnValue
, ExtraData
=ErrorInfo
)
285 if __name__
== '__main__':