2 Main file for Comp shell Debug1 function.
4 (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "UefiShellDebug1CommandsLib.h"
12 STATIC CONST SHELL_PARAM_ITEM ParamList
[] = {
25 // Buffer type, for reading both file operands in chunks.
28 UINT8
*Data
; // dynamically allocated buffer
29 UINTN Allocated
; // the allocated size of Data
30 UINTN Next
; // next position in Data to fetch a byte at
31 UINTN Left
; // number of bytes left in Data for fetching at Next
35 Function to print differnt point data.
37 @param[in] FileName File name.
38 @param[in] FileTag File tag name.
39 @param[in] Buffer Data buffer to be printed.
40 @param[in] BufferSize Size of the data to be printed.
41 @param[in] Address Address of the differnt point.
42 @param[in] DifferentBytes Total size of the buffer.
47 CONST CHAR16
*FileName
,
57 ShellPrintEx (-1, -1, L
"%s: %s\r\n %08x:", FileTag
, FileName
, Address
);
60 // Print data in hex-format.
62 for (Index
= 0; Index
< BufferSize
; Index
++) {
63 ShellPrintEx (-1, -1, L
" %02x", Buffer
[Index
]);
66 if (BufferSize
< DifferentBytes
) {
67 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_COMP_END_OF_FILE
), gShellDebug1HiiHandle
);
70 ShellPrintEx (-1, -1, L
" *");
73 // Print data in char-format.
75 for (Index
= 0; Index
< BufferSize
; Index
++) {
76 if ((Buffer
[Index
] >= 0x20) && (Buffer
[Index
] <= 0x7E)) {
77 ShellPrintEx (-1, -1, L
"%c", Buffer
[Index
]);
80 // Print dots for control characters
82 ShellPrintEx (-1, -1, L
".");
86 ShellPrintEx (-1, -1, L
"*\r\n");
90 Initialize a FILE_BUFFER.
92 @param[out] FileBuffer The FILE_BUFFER to initialize. On return, the caller
93 is responsible for checking FileBuffer->Data: if
94 FileBuffer->Data is NULL on output, then memory
100 OUT FILE_BUFFER
*FileBuffer
103 FileBuffer
->Allocated
= PcdGet32 (PcdShellFileOperationSize
);
104 FileBuffer
->Data
= AllocatePool (FileBuffer
->Allocated
);
105 FileBuffer
->Left
= 0;
109 Uninitialize a FILE_BUFFER.
111 @param[in,out] FileBuffer The FILE_BUFFER to uninitialize. The caller is
112 responsible for making sure FileBuffer was first
113 initialized with FileBufferInit(), successfully or
119 IN OUT FILE_BUFFER
*FileBuffer
122 SHELL_FREE_NON_NULL (FileBuffer
->Data
);
126 Read a byte from a SHELL_FILE_HANDLE, buffered with a FILE_BUFFER.
128 @param[in] FileHandle The SHELL_FILE_HANDLE to replenish FileBuffer
131 @param[in,out] FileBuffer The FILE_BUFFER to read a byte from. If FileBuffer
132 is empty on entry, then FileBuffer is refilled
133 from FileHandle, before outputting a byte from
134 FileBuffer to Byte. The caller is responsible for
135 ensuring that FileBuffer was successfully
136 initialized with FileBufferInit().
138 @param[out] BytesRead On successful return, BytesRead is set to 1 if the
139 next byte from FileBuffer has been stored to Byte.
140 On successful return, BytesRead is set to 0 if
141 FileBuffer is empty, and FileHandle is at EOF.
142 When an error is returned, BytesRead is not set.
144 @param[out] Byte On output, the next byte from FileBuffer. Only set
145 if (a) EFI_SUCCESS is returned and (b) BytesRead
146 is set to 1 on output.
148 @retval EFI_SUCCESS BytesRead has been set to 0 or 1. In the latter case,
149 Byte has been set as well.
151 @return Error codes propagated from
152 gEfiShellProtocol->ReadFile().
157 IN SHELL_FILE_HANDLE FileHandle
,
158 IN OUT FILE_BUFFER
*FileBuffer
,
159 OUT UINTN
*BytesRead
,
166 if (FileBuffer
->Left
== 0) {
167 ReadSize
= FileBuffer
->Allocated
;
168 Status
= gEfiShellProtocol
->ReadFile (
173 if (EFI_ERROR (Status
)) {
182 FileBuffer
->Next
= 0;
183 FileBuffer
->Left
= ReadSize
;
187 *Byte
= FileBuffer
->Data
[FileBuffer
->Next
];
195 Function for 'comp' command.
197 @param[in] ImageHandle Handle to the Image (NULL if Internal).
198 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
202 ShellCommandRunComp (
203 IN EFI_HANDLE ImageHandle
,
204 IN EFI_SYSTEM_TABLE
*SystemTable
209 CHAR16
*ProblemParam
;
212 CONST CHAR16
*TempParam
;
213 SHELL_STATUS ShellStatus
;
214 SHELL_FILE_HANDLE FileHandle1
;
215 SHELL_FILE_HANDLE FileHandle2
;
218 UINT64 DifferentBytes
;
219 UINT64 DifferentCount
;
220 UINT8 DiffPointNumber
;
221 UINT8 OneByteFromFile1
;
222 UINT8 OneByteFromFile2
;
223 UINT8
*DataFromFile1
;
224 UINT8
*DataFromFile2
;
225 FILE_BUFFER FileBuffer1
;
226 FILE_BUFFER FileBuffer2
;
227 UINTN InsertPosition1
;
228 UINTN InsertPosition2
;
229 UINTN DataSizeFromFile1
;
230 UINTN DataSizeFromFile2
;
233 UINTN DiffPointAddress
;
234 READ_STATUS ReadStatus
;
236 ShellStatus
= SHELL_SUCCESS
;
237 Status
= EFI_SUCCESS
;
242 DataFromFile1
= NULL
;
243 DataFromFile2
= NULL
;
244 ReadStatus
= OutOfDiffPoint
;
251 DiffPointAddress
= 0;
254 // initialize the shell lib (we must be in non-auto-init...)
256 Status
= ShellInitialize ();
257 ASSERT_EFI_ERROR (Status
);
259 Status
= CommandInit ();
260 ASSERT_EFI_ERROR (Status
);
263 // parse the command line
265 Status
= ShellCommandLineParse (ParamList
, &Package
, &ProblemParam
, TRUE
);
266 if (EFI_ERROR (Status
)) {
267 if ((Status
== EFI_VOLUME_CORRUPTED
) && (ProblemParam
!= NULL
)) {
268 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellDebug1HiiHandle
, L
"comp", ProblemParam
);
269 FreePool (ProblemParam
);
270 ShellStatus
= SHELL_INVALID_PARAMETER
;
275 if (ShellCommandLineGetCount (Package
) > 3) {
276 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_MANY
), gShellDebug1HiiHandle
, L
"comp");
277 ShellStatus
= SHELL_INVALID_PARAMETER
;
278 } else if (ShellCommandLineGetCount (Package
) < 3) {
279 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_FEW
), gShellDebug1HiiHandle
, L
"comp");
280 ShellStatus
= SHELL_INVALID_PARAMETER
;
282 TempParam
= ShellCommandLineGetRawValue (Package
, 1);
283 ASSERT (TempParam
!= NULL
);
284 FileName1
= ShellFindFilePath (TempParam
);
285 if (FileName1
== NULL
) {
286 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_FILE_FIND_FAIL
), gShellDebug1HiiHandle
, L
"comp", TempParam
);
287 ShellStatus
= SHELL_NOT_FOUND
;
289 Status
= ShellOpenFileByName (FileName1
, &FileHandle1
, EFI_FILE_MODE_READ
, 0);
290 if (EFI_ERROR (Status
)) {
291 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL
), gShellDebug1HiiHandle
, L
"comp", TempParam
);
292 ShellStatus
= SHELL_NOT_FOUND
;
296 TempParam
= ShellCommandLineGetRawValue (Package
, 2);
297 ASSERT (TempParam
!= NULL
);
298 FileName2
= ShellFindFilePath (TempParam
);
299 if (FileName2
== NULL
) {
300 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_FILE_FIND_FAIL
), gShellDebug1HiiHandle
, L
"comp", TempParam
);
301 ShellStatus
= SHELL_NOT_FOUND
;
303 Status
= ShellOpenFileByName (FileName2
, &FileHandle2
, EFI_FILE_MODE_READ
, 0);
304 if (EFI_ERROR (Status
)) {
305 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL
), gShellDebug1HiiHandle
, L
"comp", TempParam
);
306 ShellStatus
= SHELL_NOT_FOUND
;
310 if (ShellStatus
== SHELL_SUCCESS
) {
311 Status
= gEfiShellProtocol
->GetFileSize (FileHandle1
, &Size1
);
312 ASSERT_EFI_ERROR (Status
);
313 Status
= gEfiShellProtocol
->GetFileSize (FileHandle2
, &Size2
);
314 ASSERT_EFI_ERROR (Status
);
316 if (ShellCommandLineGetFlag (Package
, L
"-n")) {
317 TempParam
= ShellCommandLineGetValue (Package
, L
"-n");
318 if (TempParam
== NULL
) {
319 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_NO_VALUE
), gShellDebug1HiiHandle
, L
"comp", L
"-n");
320 ShellStatus
= SHELL_INVALID_PARAMETER
;
322 if (gUnicodeCollation
->StriColl (gUnicodeCollation
, (CHAR16
*)TempParam
, L
"all") == 0) {
323 DifferentCount
= MAX_UINTN
;
325 Status
= ShellConvertStringToUint64 (TempParam
, &DifferentCount
, FALSE
, TRUE
);
326 if (EFI_ERROR (Status
) || (DifferentCount
== 0)) {
327 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM_VAL
), gShellDebug1HiiHandle
, L
"comp", TempParam
, L
"-n");
328 ShellStatus
= SHELL_INVALID_PARAMETER
;
334 if (ShellCommandLineGetFlag (Package
, L
"-s")) {
335 TempParam
= ShellCommandLineGetValue (Package
, L
"-s");
336 if (TempParam
== NULL
) {
337 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_NO_VALUE
), gShellDebug1HiiHandle
, L
"comp", L
"-s");
338 ShellStatus
= SHELL_INVALID_PARAMETER
;
340 Status
= ShellConvertStringToUint64 (TempParam
, &DifferentBytes
, FALSE
, TRUE
);
341 if (EFI_ERROR (Status
) || (DifferentBytes
== 0)) {
342 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM_VAL
), gShellDebug1HiiHandle
, L
"comp", TempParam
, L
"-s");
343 ShellStatus
= SHELL_INVALID_PARAMETER
;
345 if (DifferentBytes
> MAX (Size1
, Size2
)) {
346 DifferentBytes
= MAX (Size1
, Size2
);
353 if (ShellStatus
== SHELL_SUCCESS
) {
354 DataFromFile1
= AllocateZeroPool ((UINTN
)DifferentBytes
);
355 DataFromFile2
= AllocateZeroPool ((UINTN
)DifferentBytes
);
356 FileBufferInit (&FileBuffer1
);
357 FileBufferInit (&FileBuffer2
);
358 if ((DataFromFile1
== NULL
) || (DataFromFile2
== NULL
) ||
359 (FileBuffer1
.Data
== NULL
) || (FileBuffer2
.Data
== NULL
))
361 ShellStatus
= SHELL_OUT_OF_RESOURCES
;
362 SHELL_FREE_NON_NULL (DataFromFile1
);
363 SHELL_FREE_NON_NULL (DataFromFile2
);
364 FileBufferUninit (&FileBuffer1
);
365 FileBufferUninit (&FileBuffer2
);
369 if (ShellStatus
== SHELL_SUCCESS
) {
370 while (DiffPointNumber
< DifferentCount
) {
371 DataSizeFromFile1
= 1;
372 DataSizeFromFile2
= 1;
373 OneByteFromFile1
= 0;
374 OneByteFromFile2
= 0;
375 Status
= FileBufferReadByte (
381 ASSERT_EFI_ERROR (Status
);
382 Status
= FileBufferReadByte (
388 ASSERT_EFI_ERROR (Status
);
393 // 1.When end of file and no chars in DataFromFile buffer, then break while.
394 // 2.If no more char in File1 or File2, The ReadStatus is InPrevDiffPoint forever.
395 // So the previous different point is the last one, then break the while block.
397 if (((DataSizeFromFile1
== 0) && (InsertPosition1
== 0) && (DataSizeFromFile2
== 0) && (InsertPosition2
== 0)) ||
398 ((ReadStatus
== InPrevDiffPoint
) && ((DataSizeFromFile1
== 0) || (DataSizeFromFile2
== 0)))
404 if (ReadStatus
== OutOfDiffPoint
) {
405 if (OneByteFromFile1
!= OneByteFromFile2
) {
406 ReadStatus
= InDiffPoint
;
407 DiffPointAddress
= TempAddress
;
408 if (DataSizeFromFile1
== 1) {
409 DataFromFile1
[InsertPosition1
++] = OneByteFromFile1
;
412 if (DataSizeFromFile2
== 1) {
413 DataFromFile2
[InsertPosition2
++] = OneByteFromFile2
;
416 } else if (ReadStatus
== InDiffPoint
) {
417 if (DataSizeFromFile1
== 1) {
418 DataFromFile1
[InsertPosition1
++] = OneByteFromFile1
;
421 if (DataSizeFromFile2
== 1) {
422 DataFromFile2
[InsertPosition2
++] = OneByteFromFile2
;
424 } else if (ReadStatus
== InPrevDiffPoint
) {
425 if (OneByteFromFile1
== OneByteFromFile2
) {
426 ReadStatus
= OutOfDiffPoint
;
431 // ReadStatus should be always equal InDiffPoint.
433 if ((InsertPosition1
== DifferentBytes
) ||
434 (InsertPosition2
== DifferentBytes
) ||
435 ((DataSizeFromFile1
== 0) && (DataSizeFromFile2
== 0))
438 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_COMP_DIFFERENCE_POINT
), gShellDebug1HiiHandle
, ++DiffPointNumber
);
439 PrintDifferentPoint (FileName1
, L
"File1", DataFromFile1
, InsertPosition1
, DiffPointAddress
, DifferentBytes
);
440 PrintDifferentPoint (FileName2
, L
"File2", DataFromFile2
, InsertPosition2
, DiffPointAddress
, DifferentBytes
);
443 // One of two buffuers is empty, it means this is the last different point.
445 if ((InsertPosition1
== 0) || (InsertPosition2
== 0)) {
449 for (Index
= 1; Index
< InsertPosition1
&& Index
< InsertPosition2
; Index
++) {
450 if (DataFromFile1
[Index
] == DataFromFile2
[Index
]) {
451 ReadStatus
= OutOfDiffPoint
;
456 if (ReadStatus
== OutOfDiffPoint
) {
458 // Try to find a new different point in the rest of DataFromFile.
460 for ( ; Index
< MAX (InsertPosition1
, InsertPosition2
); Index
++) {
461 if (DataFromFile1
[Index
] != DataFromFile2
[Index
]) {
462 ReadStatus
= InDiffPoint
;
463 DiffPointAddress
+= Index
;
469 // Doesn't find a new different point, still in the same different point.
471 ReadStatus
= InPrevDiffPoint
;
474 CopyMem (DataFromFile1
, DataFromFile1
+ Index
, InsertPosition1
- Index
);
475 CopyMem (DataFromFile2
, DataFromFile2
+ Index
, InsertPosition2
- Index
);
477 SetMem (DataFromFile1
+ InsertPosition1
- Index
, (UINTN
)DifferentBytes
- InsertPosition1
+ Index
, 0);
478 SetMem (DataFromFile2
+ InsertPosition2
- Index
, (UINTN
)DifferentBytes
- InsertPosition2
+ Index
, 0);
480 InsertPosition1
-= Index
;
481 InsertPosition2
-= Index
;
485 SHELL_FREE_NON_NULL (DataFromFile1
);
486 SHELL_FREE_NON_NULL (DataFromFile2
);
487 FileBufferUninit (&FileBuffer1
);
488 FileBufferUninit (&FileBuffer2
);
490 if (DiffPointNumber
== 0) {
491 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_COMP_FOOTER_PASS
), gShellDebug1HiiHandle
);
493 ShellStatus
= SHELL_NOT_EQUAL
;
494 ShellPrintHiiEx (-1, -1, NULL
, STRING_TOKEN (STR_COMP_FOOTER_FAIL
), gShellDebug1HiiHandle
);
499 ShellCommandLineFreeVarList (Package
);
502 SHELL_FREE_NON_NULL (FileName1
);
503 SHELL_FREE_NON_NULL (FileName2
);
505 if (FileHandle1
!= NULL
) {
506 gEfiShellProtocol
->CloseFile (FileHandle1
);
509 if (FileHandle2
!= NULL
) {
510 gEfiShellProtocol
->CloseFile (FileHandle2
);
513 return (ShellStatus
);