2 # Patch value into the binary file.
4 # Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
5 # SPDX-License-Identifier: BSD-2-Clause-Patent
11 import Common
.LongFilePathOs
as os
12 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
15 from optparse
import OptionParser
16 from optparse
import make_option
17 from Common
.BuildToolError
import *
18 import Common
.EdkLogger
as EdkLogger
19 from Common
.BuildVersion
import gBUILD_VERSION
21 from Common
.DataType
import *
23 # Version and Copyright
24 __version_number__
= ("0.10" + " " + gBUILD_VERSION
)
25 __version__
= "%prog Version " + __version_number__
26 __copyright__
= "Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved."
28 ## PatchBinaryFile method
30 # This method mainly patches the data into binary file.
32 # @param FileName File path of the binary file
33 # @param ValueOffset Offset value
34 # @param TypeName DataType Name
35 # @param Value Value String
36 # @param MaxSize MaxSize value
38 # @retval 0 File is updated successfully.
39 # @retval not 0 File is updated failed.
41 def PatchBinaryFile(FileName
, ValueOffset
, TypeName
, ValueString
, MaxSize
=0):
43 # Length of Binary File
45 FileHandle
= open(FileName
, 'rb')
46 FileHandle
.seek (0, 2)
47 FileLength
= FileHandle
.tell()
50 # Unify string to upper string
52 TypeName
= TypeName
.upper()
54 # Get PCD value data length
57 if TypeName
== 'BOOLEAN':
59 elif TypeName
== TAB_UINT8
:
61 elif TypeName
== TAB_UINT16
:
63 elif TypeName
== TAB_UINT32
:
65 elif TypeName
== TAB_UINT64
:
67 elif TypeName
== TAB_VOID
:
69 return OPTION_MISSING
, "PcdMaxSize is not specified for VOID* type PCD."
70 ValueLength
= int(MaxSize
)
72 return PARAMETER_INVALID
, "PCD type %s is not valid." % (CommandOptions
.PcdTypeName
)
74 # Check PcdValue is in the input binary file.
76 if ValueOffset
+ ValueLength
> FileLength
:
77 return PARAMETER_INVALID
, "PcdOffset + PcdMaxSize(DataType) is larger than the input file size."
79 # Read binary file into array
81 FileHandle
= open(FileName
, 'rb')
82 ByteArray
= array
.array('B')
83 ByteArray
.fromfile(FileHandle
, FileLength
)
85 OrigByteList
= ByteArray
.tolist()
86 ByteList
= ByteArray
.tolist()
88 # Clear the data in file
90 for Index
in range(ValueLength
):
91 ByteList
[ValueOffset
+ Index
] = 0
93 # Patch value into offset
95 SavedStr
= ValueString
96 ValueString
= ValueString
.upper()
98 if TypeName
== 'BOOLEAN':
100 # Get PCD value for BOOLEAN data type
103 if ValueString
== 'TRUE':
105 elif ValueString
== 'FALSE':
107 ValueNumber
= int (ValueString
, 0)
111 return PARAMETER_INVALID
, "PCD Value %s is not valid dec or hex string." % (ValueString
)
113 # Set PCD value into binary data
115 ByteList
[ValueOffset
] = ValueNumber
116 elif TypeName
in TAB_PCD_CLEAN_NUMERIC_TYPES
:
118 # Get PCD value for UINT* data type
121 ValueNumber
= int (ValueString
, 0)
123 return PARAMETER_INVALID
, "PCD Value %s is not valid dec or hex string." % (ValueString
)
125 # Set PCD value into binary data
127 for Index
in range(ValueLength
):
128 ByteList
[ValueOffset
+ Index
] = ValueNumber
% 0x100
129 ValueNumber
= ValueNumber
// 0x100
130 elif TypeName
== TAB_VOID
:
131 ValueString
= SavedStr
132 if ValueString
.startswith('L"'):
134 # Patch Unicode String
137 for ByteString
in ValueString
[2:-1]:
139 # Reserve zero as unicode tail
141 if Index
+ 2 >= ValueLength
:
144 # Set string value one by one/ 0x100
146 ByteList
[ValueOffset
+ Index
] = ord(ByteString
)
148 elif ValueString
.startswith("{") and ValueString
.endswith("}"):
150 # Patch {0x1, 0x2, ...} byte by byte
152 ValueList
= ValueString
[1 : len(ValueString
) - 1].split(',')
155 for ByteString
in ValueList
:
156 ByteString
= ByteString
.strip()
157 if ByteString
.upper().startswith('0X'):
158 ByteValue
= int(ByteString
, 16)
160 ByteValue
= int(ByteString
)
161 ByteList
[ValueOffset
+ Index
] = ByteValue
% 0x100
163 if Index
>= ValueLength
:
166 return PARAMETER_INVALID
, "PCD Value %s is not valid dec or hex string array." % (ValueString
)
172 for ByteString
in ValueString
[1:-1]:
174 # Reserve zero as string tail
176 if Index
+ 1 >= ValueLength
:
179 # Set string value one by one
181 ByteList
[ValueOffset
+ Index
] = ord(ByteString
)
184 # Update new data into input file.
186 if ByteList
!= OrigByteList
:
187 ByteArray
= array
.array('B')
188 ByteArray
.fromlist(ByteList
)
189 FileHandle
= open(FileName
, 'wb')
190 ByteArray
.tofile(FileHandle
)
192 return 0, "Patch Value into File %s successfully." % (FileName
)
194 ## Parse command line options
196 # Using standard Python module optparse to parse command line option of this tool.
198 # @retval Options A optparse.Values object containing the parsed options
199 # @retval InputFile Path of file to be trimmed
203 make_option("-f", "--offset", dest
="PcdOffset", action
="store", type="int",
204 help="Start offset to the image is used to store PCD value."),
205 make_option("-u", "--value", dest
="PcdValue", action
="store",
206 help="PCD value will be updated into the image."),
207 make_option("-t", "--type", dest
="PcdTypeName", action
="store",
208 help="The name of PCD data type may be one of VOID*,BOOLEAN, UINT8, UINT16, UINT32, UINT64."),
209 make_option("-s", "--maxsize", dest
="PcdMaxSize", action
="store", type="int",
210 help="Max size of data buffer is taken by PCD value.It must be set when PCD type is VOID*."),
211 make_option("-v", "--verbose", dest
="LogLevel", action
="store_const", const
=EdkLogger
.VERBOSE
,
212 help="Run verbosely"),
213 make_option("-d", "--debug", dest
="LogLevel", type="int",
214 help="Run with debug information"),
215 make_option("-q", "--quiet", dest
="LogLevel", action
="store_const", const
=EdkLogger
.QUIET
,
217 make_option("-?", action
="help", help="show this help message and exit"),
220 # use clearer usage to override default usage message
221 UsageString
= "%prog -f Offset -u Value -t Type [-s MaxSize] <input_file>"
223 Parser
= OptionParser(description
=__copyright__
, version
=__version__
, option_list
=OptionList
, usage
=UsageString
)
224 Parser
.set_defaults(LogLevel
=EdkLogger
.INFO
)
226 Options
, Args
= Parser
.parse_args()
230 EdkLogger
.error("PatchPcdValue", PARAMETER_INVALID
, ExtraData
=Parser
.get_usage())
232 InputFile
= Args
[len(Args
) - 1]
233 return Options
, InputFile
237 # This method mainly dispatch specific methods per the command line options.
238 # If no error found, return zero value so the caller of this tool can know
239 # if it's executed successfully or not.
241 # @retval 0 Tool was successful
242 # @retval 1 Tool failed
247 # Check input parameter
249 EdkLogger
.Initialize()
250 CommandOptions
, InputFile
= Options()
251 if CommandOptions
.LogLevel
< EdkLogger
.DEBUG_9
:
252 EdkLogger
.SetLevel(CommandOptions
.LogLevel
+ 1)
254 EdkLogger
.SetLevel(CommandOptions
.LogLevel
)
255 if not os
.path
.exists (InputFile
):
256 EdkLogger
.error("PatchPcdValue", FILE_NOT_FOUND
, ExtraData
=InputFile
)
258 if CommandOptions
.PcdOffset
is None or CommandOptions
.PcdValue
is None or CommandOptions
.PcdTypeName
is None:
259 EdkLogger
.error("PatchPcdValue", OPTION_MISSING
, ExtraData
="PcdOffset or PcdValue of PcdTypeName is not specified.")
261 if CommandOptions
.PcdTypeName
.upper() not in TAB_PCD_NUMERIC_TYPES_VOID
:
262 EdkLogger
.error("PatchPcdValue", PARAMETER_INVALID
, ExtraData
="PCD type %s is not valid." % (CommandOptions
.PcdTypeName
))
264 if CommandOptions
.PcdTypeName
.upper() == TAB_VOID
and CommandOptions
.PcdMaxSize
is None:
265 EdkLogger
.error("PatchPcdValue", OPTION_MISSING
, ExtraData
="PcdMaxSize is not specified for VOID* type PCD.")
268 # Patch value into binary image.
270 ReturnValue
, ErrorInfo
= PatchBinaryFile (InputFile
, CommandOptions
.PcdOffset
, CommandOptions
.PcdTypeName
, CommandOptions
.PcdValue
, CommandOptions
.PcdMaxSize
)
272 EdkLogger
.error("PatchPcdValue", ReturnValue
, ExtraData
=ErrorInfo
)
278 if __name__
== '__main__':