1 /** @file 2 Defines HBufferImage - the view of the file that is visible at any point, 3 as well as the event handlers for editing the file 4 5 Copyright (c) 2005 - 2014, Intel Corporation. All rights reserved. <BR> 6 This program and the accompanying materials 7 are licensed and made available under the terms and conditions of the BSD License 8 which accompanies this distribution. The full text of the license may be found at 9 http://opensource.org/licenses/bsd-license.php 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14 **/ 15 16 #include "HexEditor.h" 17 18 extern EFI_HANDLE HImageHandleBackup; 19 20 extern HEFI_EDITOR_FILE_IMAGE HFileImage; 21 extern HEFI_EDITOR_DISK_IMAGE HDiskImage; 22 extern HEFI_EDITOR_MEM_IMAGE HMemImage; 23 24 extern HEFI_EDITOR_FILE_IMAGE HFileImageBackupVar; 25 extern HEFI_EDITOR_DISK_IMAGE HDiskImageBackupVar; 26 extern HEFI_EDITOR_MEM_IMAGE HMemImageBackupVar; 27 28 extern BOOLEAN HEditorMouseAction; 29 30 extern HEFI_EDITOR_GLOBAL_EDITOR HMainEditor; 31 extern HEFI_EDITOR_GLOBAL_EDITOR HMainEditorBackupVar; 32 33 HEFI_EDITOR_BUFFER_IMAGE HBufferImage; 34 HEFI_EDITOR_BUFFER_IMAGE HBufferImageBackupVar; 35 36 // 37 // for basic initialization of HBufferImage 38 // 39 HEFI_EDITOR_BUFFER_IMAGE HBufferImageConst = { 40 NULL, 41 NULL, 42 0, 43 NULL, 44 { 45 0, 46 0 47 }, 48 { 49 0, 50 0 51 }, 52 { 53 0, 54 0 55 }, 56 0, 57 TRUE, 58 FALSE, 59 FileTypeNone, 60 NULL, 61 NULL, 62 NULL 63 }; 64 65 // 66 // the whole edit area needs to be refreshed 67 // 68 BOOLEAN HBufferImageNeedRefresh; 69 70 // 71 // only the current line in edit area needs to be refresh 72 // 73 BOOLEAN HBufferImageOnlyLineNeedRefresh; 74 75 BOOLEAN HBufferImageMouseNeedRefresh; 76 77 /** 78 Initialization function for HBufferImage 79 80 @retval EFI_SUCCESS The operation was successful. 81 @retval EFI_LOAD_ERROR A load error occured. 82 **/ 83 EFI_STATUS 84 HBufferImageInit ( 85 VOID 86 ) 87 { 88 EFI_STATUS Status; 89 90 // 91 // basically initialize the HBufferImage 92 // 93 CopyMem (&HBufferImage, &HBufferImageConst, sizeof (HBufferImage)); 94 95 // 96 // INIT listhead 97 // 98 HBufferImage.ListHead = AllocateZeroPool (sizeof (LIST_ENTRY)); 99 if (HBufferImage.ListHead == NULL) { 100 return EFI_LOAD_ERROR; 101 } 102 103 InitializeListHead (HBufferImage.ListHead); 104 105 HBufferImage.DisplayPosition.Row = 2; 106 HBufferImage.DisplayPosition.Column = 10; 107 HBufferImage.MousePosition.Row = 2; 108 HBufferImage.MousePosition.Column = 10; 109 110 HBufferImage.FileImage = &HFileImage; 111 HBufferImage.DiskImage = &HDiskImage; 112 HBufferImage.MemImage = &HMemImage; 113 114 HBufferImageNeedRefresh = FALSE; 115 HBufferImageOnlyLineNeedRefresh = FALSE; 116 HBufferImageMouseNeedRefresh = FALSE; 117 118 HBufferImageBackupVar.FileImage = &HFileImageBackupVar; 119 HBufferImageBackupVar.DiskImage = &HDiskImageBackupVar; 120 HBufferImageBackupVar.MemImage = &HMemImageBackupVar; 121 122 Status = HFileImageInit (); 123 if (EFI_ERROR (Status)) { 124 return EFI_LOAD_ERROR; 125 } 126 127 Status = HDiskImageInit (); 128 if (EFI_ERROR (Status)) { 129 return EFI_LOAD_ERROR; 130 } 131 132 Status = HMemImageInit (); 133 if (EFI_ERROR (Status)) { 134 return EFI_LOAD_ERROR; 135 } 136 137 return EFI_SUCCESS; 138 } 139 140 /** 141 Backup function for HBufferImage. Only a few fields need to be backup. 142 This is for making the file buffer refresh as few as possible. 143 144 @retval EFI_SUCCESS The operation was successful. 145 **/ 146 EFI_STATUS 147 HBufferImageBackup ( 148 VOID 149 ) 150 { 151 HBufferImageBackupVar.MousePosition = HBufferImage.MousePosition; 152 153 HBufferImageBackupVar.BufferPosition = HBufferImage.BufferPosition; 154 155 HBufferImageBackupVar.Modified = HBufferImage.Modified; 156 157 HBufferImageBackupVar.BufferType = HBufferImage.BufferType; 158 HBufferImageBackupVar.LowVisibleRow = HBufferImage.LowVisibleRow; 159 HBufferImageBackupVar.HighBits = HBufferImage.HighBits; 160 161 // 162 // three kinds of buffer supported 163 // file buffer 164 // disk buffer 165 // memory buffer 166 // 167 switch (HBufferImage.BufferType) { 168 case FileTypeFileBuffer: 169 HFileImageBackup (); 170 break; 171 172 case FileTypeDiskBuffer: 173 HDiskImageBackup (); 174 break; 175 176 case FileTypeMemBuffer: 177 HMemImageBackup (); 178 break; 179 180 default: 181 break; 182 } 183 184 return EFI_SUCCESS; 185 } 186 187 /** 188 Free all the lines in HBufferImage. 189 Fields affected: 190 Lines 191 CurrentLine 192 NumLines 193 ListHead 194 195 @retval EFI_SUCCESS The operation was successful. 196 **/ 197 EFI_STATUS 198 HBufferImageFreeLines ( 199 VOID 200 ) 201 { 202 HFreeLines (HBufferImage.ListHead, HBufferImage.Lines); 203 204 HBufferImage.Lines = NULL; 205 HBufferImage.CurrentLine = NULL; 206 HBufferImage.NumLines = 0; 207 208 return EFI_SUCCESS; 209 } 210 211 /** 212 Cleanup function for HBufferImage 213 214 @retval EFI_SUCCESS The operation was successful. 215 **/ 216 EFI_STATUS 217 HBufferImageCleanup ( 218 VOID 219 ) 220 { 221 EFI_STATUS Status; 222 223 // 224 // free all the lines 225 // 226 Status = HBufferImageFreeLines (); 227 228 SHELL_FREE_NON_NULL (HBufferImage.ListHead); 229 HBufferImage.ListHead = NULL; 230 231 HFileImageCleanup (); 232 HDiskImageCleanup (); 233 234 return Status; 235 236 } 237 238 /** 239 Print Line on Row 240 241 @param[in] Line The lline to print. 242 @param[in] Row The row on screen ( begin from 1 ). 243 @param[in] FRow The FRow. 244 @param[in] Orig The original color. 245 @param[in] New The color to print with. 246 247 @retval EFI_SUCCESS The operation was successful. 248 **/ 249 EFI_STATUS 250 HBufferImagePrintLine ( 251 IN HEFI_EDITOR_LINE *Line, 252 IN UINTN Row, 253 IN UINTN FRow, 254 IN HEFI_EDITOR_COLOR_UNION Orig, 255 IN HEFI_EDITOR_COLOR_UNION New 256 257 ) 258 { 259 260 UINTN Index; 261 UINTN Pos; 262 BOOLEAN Selected; 263 BOOLEAN BeNewColor; 264 UINTN RowStart; 265 UINTN RowEnd; 266 UINTN ColStart; 267 UINTN ColEnd; 268 269 // 270 // variable initialization 271 // 272 ColStart = 0; 273 ColEnd = 0; 274 Selected = FALSE; 275 276 // 277 // print the selected area in opposite color 278 // 279 if (HMainEditor.SelectStart != 0 && HMainEditor.SelectEnd != 0) { 280 RowStart = (HMainEditor.SelectStart - 1) / 0x10 + 1; 281 RowEnd = (HMainEditor.SelectEnd - 1) / 0x10 + 1; 282 283 ColStart = (HMainEditor.SelectStart - 1) % 0x10 + 1; 284 ColEnd = (HMainEditor.SelectEnd - 1) % 0x10 + 1; 285 286 if (FRow >= RowStart && FRow <= RowEnd) { 287 Selected = TRUE; 288 } 289 290 if (FRow > RowStart) { 291 ColStart = 1; 292 } 293 294 if (FRow < RowEnd) { 295 ColEnd = 0x10; 296 } 297 298 } 299 300 if (!HEditorMouseAction) { 301 ShellPrintEx ( 302 0, 303 (INT32)Row - 1, 304 L"%8X ", 305 ((INT32)Row - 2 + HBufferImage.LowVisibleRow - 1) * 0x10 306 ); 307 308 } 309 310 for (Index = 0; Index < 0x08 && Index < Line->Size; Index++) { 311 312 BeNewColor = FALSE; 313 314 if (Selected) { 315 if (Index + 1 >= ColStart && Index + 1 <= ColEnd) { 316 BeNewColor = TRUE; 317 } 318 } 319 320 if (BeNewColor) { 321 gST->ConOut->SetAttribute (gST->ConOut, New.Data & 0x7F); 322 } else { 323 gST->ConOut->SetAttribute (gST->ConOut, Orig.Data & 0x7F); 324 } 325 326 Pos = 10 + (Index * 3); 327 if (Line->Buffer[Index] < 0x10) { 328 ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"0"); 329 Pos++; 330 } 331 332 if (Index < 0x07) { 333 ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"%x ", Line->Buffer[Index]); 334 } else { 335 ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"%x ", Line->Buffer[Index]); 336 } 337 338 } 339 340 gST->ConOut->SetAttribute (gST->ConOut, Orig.Data & 0x7F); 341 while (Index < 0x08) { 342 Pos = 10 + (Index * 3); 343 ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L" "); 344 Index++; 345 } 346 347 while (Index < 0x10 && Index < Line->Size) { 348 349 BeNewColor = FALSE; 350 351 if (Selected) { 352 if (Index + 1 >= ColStart && Index + 1 <= ColEnd) { 353 BeNewColor = TRUE; 354 } 355 } 356 357 if (BeNewColor) { 358 gST->ConOut->SetAttribute (gST->ConOut, New.Data & 0x7F); 359 } else { 360 gST->ConOut->SetAttribute (gST->ConOut, Orig.Data & 0x7F); 361 } 362 363 Pos = 10 + (Index * 3) + 1; 364 if (Line->Buffer[Index] < 0x10) { 365 ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"0"); 366 Pos++; 367 } 368 369 ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"%x ", Line->Buffer[Index]); 370 Index++; 371 } 372 373 gST->ConOut->SetAttribute (gST->ConOut, Orig.Data & 0x7F); 374 while (Index < 0x10) { 375 Pos = 10 + (Index * 3) + 1; 376 ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L" "); 377 Index++; 378 } 379 // 380 // restore the original color 381 // 382 gST->ConOut->SetAttribute (gST->ConOut, Orig.Data & 0x7F); 383 384 // 385 // PRINT the buffer content 386 // 387 if (!HEditorMouseAction) { 388 for (Index = 0; Index < 0x10 && Index < Line->Size; Index++) { 389 Pos = ASCII_POSITION + Index; 390 391 // 392 // learned from shelle.h -- IsValidChar 393 // 394 if (Line->Buffer[Index] >= L' ') { 395 ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"%c", (CHAR16) Line->Buffer[Index]); 396 } else { 397 ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L"%c", '.'); 398 } 399 } 400 401 while (Index < 0x10) { 402 Pos = ASCII_POSITION + Index; 403 ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L" "); 404 Index++; 405 } 406 } 407 // 408 // restore the abundant blank in hex edit area to original color 409 // 410 if (Selected) { 411 if (ColEnd <= 7) { 412 Pos = 10 + (ColEnd - 1) * 3 + 2; 413 ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L" "); 414 } else if (ColEnd == 8) { 415 Pos = 10 + (ColEnd - 1) * 3 + 2; 416 ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L" "); 417 } else { 418 Pos = 10 + (ColEnd - 1) * 3 + 3; 419 ShellPrintEx ((INT32)Pos - 1, (INT32)Row - 1, L" "); 420 } 421 } 422 423 return EFI_SUCCESS; 424 } 425 426 /** 427 Function to decide if a column number is stored in the high bits. 428 429 @param[in] Column The column to examine. 430 @param[out] FCol The actual column number. 431 432 @retval TRUE The actual column was in high bits and is now in FCol. 433 @retval FALSE There was not a column number in the high bits. 434 **/ 435 BOOLEAN 436 HBufferImageIsAtHighBits ( 437 IN UINTN Column, 438 OUT UINTN *FCol 439 ) 440 { 441 Column -= 10; 442 443 // 444 // NOW AFTER THE SUB, Column start from 0 445 // 23 AND 24 ARE BOTH BLANK 446 // 447 if (Column == 24) { 448 *FCol = 0; 449 return FALSE; 450 } 451 452 if (Column > 24) { 453 Column--; 454 } 455 456 *FCol = (Column / 3) + 1; 457 458 if (Column % 3 == 0) { 459 return TRUE; 460 } 461 462 if ((Column % 3 == 2)) { 463 *FCol = 0; 464 } 465 466 return FALSE; 467 } 468 469 /** 470 Decide if a point is in the already selected area. 471 472 @param[in] MouseRow The row of the point to test. 473 @param[in] MouseCol The col of the point to test. 474 475 @retval TRUE The point is in the selected area. 476 @retval FALSE The point is not in the selected area. 477 **/ 478 BOOLEAN 479 HBufferImageIsInSelectedArea ( 480 IN UINTN MouseRow, 481 IN UINTN MouseCol 482 ) 483 { 484 UINTN FRow; 485 UINTN RowStart; 486 UINTN RowEnd; 487 UINTN ColStart; 488 UINTN ColEnd; 489 UINTN MouseColStart; 490 UINTN MouseColEnd; 491 492 // 493 // judge mouse position whether is in selected area 494 // 495 // 496 // not select 497 // 498 if (HMainEditor.SelectStart == 0 || HMainEditor.SelectEnd == 0) { 499 return FALSE; 500 } 501 // 502 // calculate the select area 503 // 504 RowStart = (HMainEditor.SelectStart - 1) / 0x10 + 1; 505 RowEnd = (HMainEditor.SelectEnd - 1) / 0x10 + 1; 506 507 ColStart = (HMainEditor.SelectStart - 1) % 0x10 + 1; 508 ColEnd = (HMainEditor.SelectEnd - 1) % 0x10 + 1; 509 510 FRow = HBufferImage.LowVisibleRow + MouseRow - 2; 511 if (FRow < RowStart || FRow > RowEnd) { 512 return FALSE; 513 } 514 515 if (FRow > RowStart) { 516 ColStart = 1; 517 } 518 519 if (FRow < RowEnd) { 520 ColEnd = 0x10; 521 } 522 523 MouseColStart = 10 + (ColStart - 1) * 3; 524 if (ColStart > 8) { 525 MouseColStart++; 526 } 527 528 MouseColEnd = 10 + (ColEnd - 1) * 3 + 1; 529 if (ColEnd > 8) { 530 MouseColEnd++; 531 } 532 533 if (MouseCol < MouseColStart || MouseCol > MouseColEnd) { 534 return FALSE; 535 } 536 537 return TRUE; 538 } 539 540 /** 541 Set mouse position according to HBufferImage.MousePosition. 542 543 @retval EFI_SUCCESS The operation was successful. 544 **/ 545 EFI_STATUS 546 HBufferImageRestoreMousePosition ( 547 VOID 548 ) 549 { 550 HEFI_EDITOR_COLOR_UNION Orig; 551 HEFI_EDITOR_COLOR_UNION New; 552 UINTN FRow; 553 UINTN FColumn; 554 BOOLEAN HasCharacter; 555 HEFI_EDITOR_LINE *CurrentLine; 556 HEFI_EDITOR_LINE *Line; 557 UINT8 Value; 558 BOOLEAN HighBits; 559 560 Line = NULL; 561 if (HMainEditor.MouseSupported) { 562 563 if (HBufferImageMouseNeedRefresh) { 564 565 HBufferImageMouseNeedRefresh = FALSE; 566 567 // 568 // if mouse position not moved and only mouse action 569 // so do not need to refresh mouse position 570 // 571 if (( 572 HBufferImage.MousePosition.Row == HBufferImageBackupVar.MousePosition.Row && 573 HBufferImage.MousePosition.Column == HBufferImageBackupVar.MousePosition.Column 574 ) && 575 HEditorMouseAction 576 ) { 577 return EFI_SUCCESS; 578 } 579 // 580 // backup the old screen attributes 581 // 582 Orig = HMainEditor.ColorAttributes; 583 New.Data = 0; 584 New.Colors.Foreground = Orig.Colors.Background & 0xF; 585 New.Colors.Background = Orig.Colors.Foreground & 0x7; 586 587 // 588 // if in selected area, 589 // so do not need to refresh mouse 590 // 591 if (!HBufferImageIsInSelectedArea ( 592 HBufferImageBackupVar.MousePosition.Row, 593 HBufferImageBackupVar.MousePosition.Column 594 )) { 595 gST->ConOut->SetAttribute (gST->ConOut, Orig.Data); 596 } else { 597 gST->ConOut->SetAttribute (gST->ConOut, New.Data & 0x7F); 598 } 599 // 600 // clear the old mouse position 601 // 602 FRow = HBufferImage.LowVisibleRow + HBufferImageBackupVar.MousePosition.Row - 2; 603 604 HighBits = HBufferImageIsAtHighBits ( 605 HBufferImageBackupVar.MousePosition.Column, 606 &FColumn 607 ); 608 609 HasCharacter = TRUE; 610 if (FRow > HBufferImage.NumLines || FColumn == 0) { 611 HasCharacter = FALSE; 612 } else { 613 CurrentLine = HBufferImage.CurrentLine; 614 Line = HMoveLine (FRow - HBufferImage.BufferPosition.Row); 615 616 if (Line == NULL || FColumn > Line->Size) { 617 HasCharacter = FALSE; 618 } 619 620 HBufferImage.CurrentLine = CurrentLine; 621 } 622 623 ShellPrintEx ( 624 (INT32)HBufferImageBackupVar.MousePosition.Column - 1, 625 (INT32)HBufferImageBackupVar.MousePosition.Row - 1, 626 L" " 627 ); 628 629 if (HasCharacter) { 630 if (HighBits) { 631 Value = (UINT8) (Line->Buffer[FColumn - 1] & 0xf0); 632 Value = (UINT8) (Value >> 4); 633 } else { 634 Value = (UINT8) (Line->Buffer[FColumn - 1] & 0xf); 635 } 636 637 ShellPrintEx ( 638 (INT32)HBufferImageBackupVar.MousePosition.Column - 1, 639 (INT32)HBufferImageBackupVar.MousePosition.Row - 1, 640 L"%x", 641 Value 642 ); 643 } 644 645 if (!HBufferImageIsInSelectedArea ( 646 HBufferImage.MousePosition.Row, 647 HBufferImage.MousePosition.Column 648 )) { 649 gST->ConOut->SetAttribute (gST->ConOut, New.Data & 0x7F); 650 } else { 651 gST->ConOut->SetAttribute (gST->ConOut, Orig.Data); 652 } 653 // 654 // clear the old mouse position 655 // 656 FRow = HBufferImage.LowVisibleRow + HBufferImage.MousePosition.Row - 2; 657 658 HighBits = HBufferImageIsAtHighBits ( 659 HBufferImage.MousePosition.Column, 660 &FColumn 661 ); 662 663 HasCharacter = TRUE; 664 if (FRow > HBufferImage.NumLines || FColumn == 0) { 665 HasCharacter = FALSE; 666 } else { 667 CurrentLine = HBufferImage.CurrentLine; 668 Line = HMoveLine (FRow - HBufferImage.BufferPosition.Row); 669 670 if (Line == NULL || FColumn > Line->Size) { 671 HasCharacter = FALSE; 672 } 673 674 HBufferImage.CurrentLine = CurrentLine; 675 } 676 677 ShellPrintEx ( 678 (INT32)HBufferImage.MousePosition.Column - 1, 679 (INT32)HBufferImage.MousePosition.Row - 1, 680 L" " 681 ); 682 683 if (HasCharacter) { 684 if (HighBits) { 685 Value = (UINT8) (Line->Buffer[FColumn - 1] & 0xf0); 686 Value = (UINT8) (Value >> 4); 687 } else { 688 Value = (UINT8) (Line->Buffer[FColumn - 1] & 0xf); 689 } 690 691 ShellPrintEx ( 692 (INT32)HBufferImage.MousePosition.Column - 1, 693 (INT32)HBufferImage.MousePosition.Row - 1, 694 L"%x", 695 Value 696 ); 697 } 698 // 699 // end of HasCharacter 700 // 701 gST->ConOut->SetAttribute (gST->ConOut, Orig.Data); 702 } 703 // 704 // end of MouseNeedRefresh 705 // 706 } 707 // 708 // end of MouseSupported 709 // 710 return EFI_SUCCESS; 711 } 712 713 /** 714 Set cursor position according to HBufferImage.DisplayPosition. 715 716 @retval EFI_SUCCESS The operation was successful. 717 **/ 718 EFI_STATUS 719 HBufferImageRestorePosition ( 720 VOID 721 ) 722 { 723 // 724 // set cursor position 725 // 726 gST->ConOut->SetCursorPosition ( 727 gST->ConOut, 728 HBufferImage.DisplayPosition.Column - 1, 729 HBufferImage.DisplayPosition.Row - 1 730 ); 731 732 return EFI_SUCCESS; 733 } 734 735 /** 736 Refresh function for HBufferImage. 737 738 @retval EFI_SUCCESS The operation was successful. 739 @retval EFI_LOAD_ERROR A Load error occured. 740 741 **/ 742 EFI_STATUS 743 HBufferImageRefresh ( 744 VOID 745 ) 746 { 747 LIST_ENTRY *Link; 748 HEFI_EDITOR_LINE *Line; 749 UINTN Row; 750 HEFI_EDITOR_COLOR_UNION Orig; 751 HEFI_EDITOR_COLOR_UNION New; 752 753 UINTN StartRow; 754 UINTN EndRow; 755 UINTN FStartRow; 756 UINTN Tmp; 757 758 Orig = HMainEditor.ColorAttributes; 759 New.Data = 0; 760 New.Colors.Foreground = Orig.Colors.Background; 761 New.Colors.Background = Orig.Colors.Foreground; 762 763 // 764 // if it's the first time after editor launch, so should refresh 765 // 766 if (HEditorFirst == FALSE) { 767 // 768 // no definite required refresh 769 // and file position displayed on screen has not been changed 770 // 771 if (!HBufferImageNeedRefresh && 772 !HBufferImageOnlyLineNeedRefresh && 773 HBufferImageBackupVar.LowVisibleRow == HBufferImage.LowVisibleRow 774 ) { 775 HBufferImageRestoreMousePosition (); 776 HBufferImageRestorePosition (); 777 return EFI_SUCCESS; 778 } 779 } 780 781 gST->ConOut->EnableCursor (gST->ConOut, FALSE); 782 783 // 784 // only need to refresh current line 785 // 786 if (HBufferImageOnlyLineNeedRefresh && HBufferImageBackupVar.LowVisibleRow == HBufferImage.LowVisibleRow) { 787 788 HBufferImagePrintLine ( 789 HBufferImage.CurrentLine, 790 HBufferImage.DisplayPosition.Row, 791 HBufferImage.BufferPosition.Row, 792 Orig, 793 New 794 ); 795 } else { 796 // 797 // the whole edit area need refresh 798 // 799 if (HEditorMouseAction && HMainEditor.SelectStart != 0 && HMainEditor.SelectEnd != 0) { 800 if (HMainEditor.SelectStart != HMainEditorBackupVar.SelectStart) { 801 if (HMainEditor.SelectStart >= HMainEditorBackupVar.SelectStart && HMainEditorBackupVar.SelectStart != 0) { 802 StartRow = (HMainEditorBackupVar.SelectStart - 1) / 0x10 + 1; 803 } else { 804 StartRow = (HMainEditor.SelectStart - 1) / 0x10 + 1; 805 } 806 } else { 807 StartRow = (HMainEditor.SelectStart - 1) / 0x10 + 1; 808 } 809 810 if (HMainEditor.SelectEnd <= HMainEditorBackupVar.SelectEnd) { 811 EndRow = (HMainEditorBackupVar.SelectEnd - 1) / 0x10 + 1; 812 } else { 813 EndRow = (HMainEditor.SelectEnd - 1) / 0x10 + 1; 814 } 815 // 816 // swap 817 // 818 if (StartRow > EndRow) { 819 Tmp = StartRow; 820 StartRow = EndRow; 821 EndRow = Tmp; 822 } 823 824 FStartRow = StartRow; 825 826 StartRow = 2 + StartRow - HBufferImage.LowVisibleRow; 827 EndRow = 2 + EndRow - HBufferImage.LowVisibleRow; 828 829 } else { 830 // 831 // not mouse selection actions 832 // 833 FStartRow = HBufferImage.LowVisibleRow; 834 StartRow = 2; 835 EndRow = (HMainEditor.ScreenSize.Row - 1); 836 } 837 // 838 // no line 839 // 840 if (HBufferImage.Lines == NULL) { 841 HBufferImageRestoreMousePosition (); 842 HBufferImageRestorePosition (); 843 gST->ConOut->EnableCursor (gST->ConOut, TRUE); 844 return EFI_SUCCESS; 845 } 846 // 847 // get the first line that will be displayed 848 // 849 Line = HMoveLine (FStartRow - HBufferImage.BufferPosition.Row); 850 if (Line == NULL) { 851 gST->ConOut->EnableCursor (gST->ConOut, TRUE); 852 return EFI_LOAD_ERROR; 853 } 854 855 Link = &(Line->Link); 856 Row = StartRow; 857 do { 858 Line = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); 859 860 // 861 // print line at row 862 // 863 HBufferImagePrintLine ( 864 Line, 865 Row, 866 HBufferImage.LowVisibleRow + Row - 2, 867 Orig, 868 New 869 ); 870 871 Link = Link->ForwardLink; 872 Row++; 873 } while (Link != HBufferImage.ListHead && Row <= EndRow); 874 875 while (Row <= EndRow) { 876 EditorClearLine (Row, HMainEditor.ScreenSize.Column, HMainEditor.ScreenSize.Row); 877 Row++; 878 } 879 // 880 // while not file end and not screen full 881 // 882 } 883 884 HBufferImageRestoreMousePosition (); 885 HBufferImageRestorePosition (); 886 887 HBufferImageNeedRefresh = FALSE; 888 HBufferImageOnlyLineNeedRefresh = FALSE; 889 gST->ConOut->EnableCursor (gST->ConOut, TRUE); 890 891 return EFI_SUCCESS; 892 } 893 894 /** 895 Read an image into a buffer friom a source. 896 897 @param[in] FileName Pointer to the file name. OPTIONAL and ignored if not FileTypeFileBuffer. 898 @param[in] DiskName Pointer to the disk name. OPTIONAL and ignored if not FileTypeDiskBuffer. 899 @param[in] DiskOffset Offset into the disk. OPTIONAL and ignored if not FileTypeDiskBuffer. 900 @param[in] DiskSize Size of the disk buffer. OPTIONAL and ignored if not FileTypeDiskBuffer. 901 @param[in] MemOffset Offset into the Memory. OPTIONAL and ignored if not FileTypeMemBuffer. 902 @param[in] MemSize Size of the Memory buffer. OPTIONAL and ignored if not FileTypeMemBuffer. 903 @param[in] BufferType The type of buffer to save. IGNORED. 904 @param[in] Recover TRUE for recovermode, FALSE otherwise. 905 906 @return EFI_SUCCESS The operation was successful. 907 **/ 908 EFI_STATUS 909 HBufferImageRead ( 910 IN CONST CHAR16 *FileName, 911 IN CONST CHAR16 *DiskName, 912 IN UINTN DiskOffset, 913 IN UINTN DiskSize, 914 IN UINTN MemOffset, 915 IN UINTN MemSize, 916 IN EDIT_FILE_TYPE BufferType, 917 IN BOOLEAN Recover 918 ) 919 { 920 EFI_STATUS Status; 921 EDIT_FILE_TYPE BufferTypeBackup; 922 923 // 924 // variable initialization 925 // 926 Status = EFI_SUCCESS; 927 HBufferImage.BufferType = BufferType; 928 929 // 930 // three types of buffer supported 931 // file buffer 932 // disk buffer 933 // memory buffer 934 // 935 BufferTypeBackup = HBufferImage.BufferType; 936 937 switch (BufferType) { 938 case FileTypeFileBuffer: 939 Status = HFileImageRead (FileName, Recover); 940 break; 941 942 case FileTypeDiskBuffer: 943 Status = HDiskImageRead (DiskName, DiskOffset, DiskSize, Recover); 944 break; 945 946 case FileTypeMemBuffer: 947 Status = HMemImageRead (MemOffset, MemSize, Recover); 948 break; 949 950 default: 951 Status = EFI_NOT_FOUND; 952 break; 953 } 954 955 if (EFI_ERROR (Status)) { 956 HBufferImage.BufferType = BufferTypeBackup; 957 } 958 959 return Status; 960 } 961 962 /** 963 Save the current image. 964 965 @param[in] FileName Pointer to the file name. OPTIONAL and ignored if not FileTypeFileBuffer. 966 @param[in] DiskName Pointer to the disk name. OPTIONAL and ignored if not FileTypeDiskBuffer. 967 @param[in] DiskOffset Offset into the disk. OPTIONAL and ignored if not FileTypeDiskBuffer. 968 @param[in] DiskSize Size of the disk buffer. OPTIONAL and ignored if not FileTypeDiskBuffer. 969 @param[in] MemOffset Offset into the Memory. OPTIONAL and ignored if not FileTypeMemBuffer. 970 @param[in] MemSize Size of the Memory buffer. OPTIONAL and ignored if not FileTypeMemBuffer. 971 @param[in] BufferType The type of buffer to save. IGNORED. 972 973 @return EFI_SUCCESS The operation was successful. 974 **/ 975 EFI_STATUS 976 HBufferImageSave ( 977 IN CHAR16 *FileName, 978 IN CHAR16 *DiskName, 979 IN UINTN DiskOffset, 980 IN UINTN DiskSize, 981 IN UINTN MemOffset, 982 IN UINTN MemSize, 983 IN EDIT_FILE_TYPE BufferType 984 ) 985 { 986 EFI_STATUS Status; 987 EDIT_FILE_TYPE BufferTypeBackup; 988 989 // 990 // variable initialization 991 // 992 Status = EFI_SUCCESS; 993 BufferTypeBackup = HBufferImage.BufferType; 994 995 switch (HBufferImage.BufferType) { 996 // 997 // file buffer 998 // 999 case FileTypeFileBuffer: 1000 Status = HFileImageSave (FileName); 1001 break; 1002 1003 // 1004 // disk buffer 1005 // 1006 case FileTypeDiskBuffer: 1007 Status = HDiskImageSave (DiskName, DiskOffset, DiskSize); 1008 break; 1009 1010 // 1011 // memory buffer 1012 // 1013 case FileTypeMemBuffer: 1014 Status = HMemImageSave (MemOffset, MemSize); 1015 break; 1016 1017 default: 1018 Status = EFI_NOT_FOUND; 1019 break; 1020 } 1021 1022 if (EFI_ERROR (Status)) { 1023 HBufferImage.BufferType = BufferTypeBackup; 1024 } 1025 1026 return Status; 1027 } 1028 1029 /** 1030 Create a new line and append it to the line list. 1031 Fields affected: 1032 NumLines 1033 Lines 1034 1035 @retval NULL create line failed. 1036 @return the line created. 1037 1038 **/ 1039 HEFI_EDITOR_LINE * 1040 HBufferImageCreateLine ( 1041 VOID 1042 ) 1043 { 1044 HEFI_EDITOR_LINE *Line; 1045 1046 // 1047 // allocate for line structure 1048 // 1049 Line = AllocateZeroPool (sizeof (HEFI_EDITOR_LINE)); 1050 if (Line == NULL) { 1051 return NULL; 1052 } 1053 1054 Line->Signature = EFI_EDITOR_LINE_LIST; 1055 Line->Size = 0; 1056 1057 HBufferImage.NumLines++; 1058 1059 // 1060 // insert to line list 1061 // 1062 InsertTailList (HBufferImage.ListHead, &Line->Link); 1063 1064 if (HBufferImage.Lines == NULL) { 1065 HBufferImage.Lines = CR ( 1066 HBufferImage.ListHead->ForwardLink, 1067 HEFI_EDITOR_LINE, 1068 Link, 1069 EFI_EDITOR_LINE_LIST 1070 ); 1071 } 1072 1073 return Line; 1074 } 1075 1076 /** 1077 Free the current image. 1078 1079 @retval EFI_SUCCESS The operation was successful. 1080 **/ 1081 EFI_STATUS 1082 HBufferImageFree ( 1083 VOID 1084 ) 1085 { 1086 // 1087 // free all lines 1088 // 1089 HBufferImageFreeLines (); 1090 1091 return EFI_SUCCESS; 1092 } 1093 1094 /** 1095 change char to int value based on Hex. 1096 1097 @param[in] Char The input char. 1098 1099 @return The character's index value. 1100 @retval -1 The operation failed. 1101 **/ 1102 INTN 1103 HBufferImageCharToHex ( 1104 IN CHAR16 Char 1105 ) 1106 { 1107 // 1108 // change the character to hex 1109 // 1110 if (Char >= L'0' && Char <= L'9') { 1111 return (INTN) (Char - L'0'); 1112 } 1113 1114 if (Char >= L'a' && Char <= L'f') { 1115 return (INTN) (Char - L'a' + 10); 1116 } 1117 1118 if (Char >= L'A' && Char <= L'F') { 1119 return (INTN) (Char - L'A' + 10); 1120 } 1121 1122 return -1; 1123 } 1124 1125 /** 1126 Add character. 1127 1128 @param[in] Char -- input char. 1129 1130 @retval EFI_SUCCESS The operation was successful. 1131 @retval EFI_OUT_OF_RESOURCES A memory allocation failed. 1132 **/ 1133 EFI_STATUS 1134 HBufferImageAddChar ( 1135 IN CHAR16 Char 1136 ) 1137 { 1138 HEFI_EDITOR_LINE *Line; 1139 HEFI_EDITOR_LINE *NewLine; 1140 INTN Value; 1141 UINT8 Old; 1142 UINTN FRow; 1143 UINTN FCol; 1144 BOOLEAN High; 1145 1146 Value = HBufferImageCharToHex (Char); 1147 1148 // 1149 // invalid input 1150 // 1151 if (Value == -1) { 1152 return EFI_SUCCESS; 1153 } 1154 1155 Line = HBufferImage.CurrentLine; 1156 FRow = HBufferImage.BufferPosition.Row; 1157 FCol = HBufferImage.BufferPosition.Column; 1158 High = HBufferImage.HighBits; 1159 1160 // 1161 // only needs to refresh current line 1162 // 1163 HBufferImageOnlyLineNeedRefresh = TRUE; 1164 1165 // 1166 // not a full line and beyond the last character 1167 // 1168 if (FCol > Line->Size) { 1169 // 1170 // cursor always at high 4 bits 1171 // and always put input to the low 4 bits 1172 // 1173 Line->Buffer[Line->Size] = (UINT8) Value; 1174 Line->Size++; 1175 High = FALSE; 1176 } else { 1177 1178 Old = Line->Buffer[FCol - 1]; 1179 1180 // 1181 // always put the input to the low 4 bits 1182 // 1183 Old = (UINT8) (Old & 0x0f); 1184 Old = (UINT8) (Old << 4); 1185 Old = (UINT8) (Value + Old); 1186 Line->Buffer[FCol - 1] = Old; 1187 1188 // 1189 // at the low 4 bits of the last character of a full line 1190 // so if no next line, need to create a new line 1191 // 1192 if (!High && FCol == 0x10) { 1193 1194 HBufferImageOnlyLineNeedRefresh = FALSE; 1195 HBufferImageNeedRefresh = TRUE; 1196 1197 if (Line->Link.ForwardLink == HBufferImage.ListHead) { 1198 // 1199 // last line 1200 // 1201 // create a new line 1202 // 1203 NewLine = HBufferImageCreateLine (); 1204 if (NewLine == NULL) { 1205 return EFI_OUT_OF_RESOURCES; 1206 } 1207 // 1208 // end of NULL 1209 // 1210 } 1211 // 1212 // end of == ListHead 1213 // 1214 } 1215 // 1216 // end of == 0x10 1217 // 1218 // if already at end of this line, scroll it to the start of next line 1219 // 1220 if (FCol == 0x10 && !High) { 1221 // 1222 // definitely has next line 1223 // 1224 FRow++; 1225 FCol = 1; 1226 High = TRUE; 1227 } else { 1228 // 1229 // if not at end of this line, just move to next column 1230 // 1231 if (!High) { 1232 FCol++; 1233 } 1234 1235 if (High) { 1236 High = FALSE; 1237 } else { 1238 High = TRUE; 1239 } 1240 1241 } 1242 // 1243 // end of ==FALSE 1244 // 1245 } 1246 // 1247 // move cursor to right 1248 // 1249 HBufferImageMovePosition (FRow, FCol, High); 1250 1251 if (!HBufferImage.Modified) { 1252 HBufferImage.Modified = TRUE; 1253 } 1254 1255 return EFI_SUCCESS; 1256 } 1257 1258 /** 1259 Delete the previous character. 1260 1261 @retval EFI_SUCCESS The operationw as successful. 1262 **/ 1263 EFI_STATUS 1264 HBufferImageDoBackspace ( 1265 VOID 1266 ) 1267 { 1268 HEFI_EDITOR_LINE *Line; 1269 1270 UINTN FileColumn; 1271 UINTN FPos; 1272 BOOLEAN LastLine; 1273 1274 // 1275 // variable initialization 1276 // 1277 LastLine = FALSE; 1278 1279 // 1280 // already the first character 1281 // 1282 if (HBufferImage.BufferPosition.Row == 1 && HBufferImage.BufferPosition.Column == 1) { 1283 return EFI_SUCCESS; 1284 } 1285 1286 FPos = (HBufferImage.BufferPosition.Row - 1) * 0x10 + HBufferImage.BufferPosition.Column - 1; 1287 1288 FileColumn = HBufferImage.BufferPosition.Column; 1289 1290 Line = HBufferImage.CurrentLine; 1291 LastLine = FALSE; 1292 if (Line->Link.ForwardLink == HBufferImage.ListHead && FileColumn > 1) { 1293 LastLine = TRUE; 1294 } 1295 1296 HBufferImageDeleteCharacterFromBuffer (FPos - 1, 1, NULL); 1297 1298 // 1299 // if is the last line 1300 // then only this line need to be refreshed 1301 // 1302 if (LastLine) { 1303 HBufferImageNeedRefresh = FALSE; 1304 HBufferImageOnlyLineNeedRefresh = TRUE; 1305 } else { 1306 HBufferImageNeedRefresh = TRUE; 1307 HBufferImageOnlyLineNeedRefresh = FALSE; 1308 } 1309 1310 if (!HBufferImage.Modified) { 1311 HBufferImage.Modified = TRUE; 1312 } 1313 1314 return EFI_SUCCESS; 1315 } 1316 1317 /** 1318 ASCII key + Backspace + return. 1319 1320 @param[in] Char The input char. 1321 1322 @retval EFI_SUCCESS The operation was successful. 1323 @retval EFI_LOAD_ERROR A load error occured. 1324 @retval EFI_OUT_OF_RESOURCES A memory allocation failed. 1325 **/ 1326 EFI_STATUS 1327 HBufferImageDoCharInput ( 1328 IN CHAR16 Char 1329 ) 1330 { 1331 EFI_STATUS Status; 1332 1333 Status = EFI_SUCCESS; 1334 1335 switch (Char) { 1336 case 0: 1337 break; 1338 1339 case 0x08: 1340 Status = HBufferImageDoBackspace (); 1341 break; 1342 1343 case 0x09: 1344 case 0x0a: 1345 case 0x0d: 1346 // 1347 // Tabs, Returns are thought as nothing 1348 // 1349 break; 1350 1351 default: 1352 // 1353 // DEAL WITH ASCII CHAR, filter out thing like ctrl+f 1354 // 1355 if (Char > 127 || Char < 32) { 1356 Status = StatusBarSetStatusString (L"Unknown Command"); 1357 } else { 1358 Status = HBufferImageAddChar (Char); 1359 } 1360 1361 break; 1362 } 1363 1364 return Status; 1365 } 1366 1367 /** 1368 Check user specified FileRow is above current screen. 1369 1370 @param[in] FileRow Row of file position ( start from 1 ). 1371 1372 @retval TRUE It is above the current screen. 1373 @retval FALSE It is not above the current screen. 1374 1375 **/ 1376 BOOLEAN 1377 HAboveCurrentScreen ( 1378 IN UINTN FileRow 1379 ) 1380 { 1381 if (FileRow < HBufferImage.LowVisibleRow) { 1382 return TRUE; 1383 } 1384 1385 return FALSE; 1386 } 1387 1388 /** 1389 Check user specified FileRow is under current screen. 1390 1391 @param[in] FileRow Row of file position ( start from 1 ). 1392 1393 @retval TRUE It is under the current screen. 1394 @retval FALSE It is not under the current screen. 1395 1396 **/ 1397 BOOLEAN 1398 HUnderCurrentScreen ( 1399 IN UINTN FileRow 1400 ) 1401 { 1402 if (FileRow > HBufferImage.LowVisibleRow + (HMainEditor.ScreenSize.Row - 2) - 1) { 1403 return TRUE; 1404 } 1405 1406 return FALSE; 1407 } 1408 1409 /** 1410 According to cursor's file position, adjust screen display. 1411 1412 @param[in] NewFilePosRow Row of file position ( start from 1 ). 1413 @param[in] NewFilePosCol Column of file position ( start from 1 ). 1414 @param[in] HighBits Cursor will on high4 bits or low4 bits. 1415 **/ 1416 VOID 1417 HBufferImageMovePosition ( 1418 IN UINTN NewFilePosRow, 1419 IN UINTN NewFilePosCol, 1420 IN BOOLEAN HighBits 1421 ) 1422 { 1423 INTN RowGap; 1424 UINTN Abs; 1425 BOOLEAN Above; 1426 BOOLEAN Under; 1427 UINTN NewDisplayCol; 1428 1429 // 1430 // CALCULATE gap between current file position and new file position 1431 // 1432 RowGap = NewFilePosRow - HBufferImage.BufferPosition.Row; 1433 1434 Under = HUnderCurrentScreen (NewFilePosRow); 1435 Above = HAboveCurrentScreen (NewFilePosRow); 1436 1437 HBufferImage.HighBits = HighBits; 1438 1439 // 1440 // if is below current screen 1441 // 1442 if (Under) { 1443 // 1444 // display row will be unchanged 1445 // 1446 HBufferImage.BufferPosition.Row = NewFilePosRow; 1447 } else { 1448 if (Above) { 1449 // 1450 // has enough above line, so display row unchanged 1451 // not has enough above lines, so the first line is 1452 // at the first display line 1453 // 1454 if (NewFilePosRow < (HBufferImage.DisplayPosition.Row - 2 + 1)) { 1455 HBufferImage.DisplayPosition.Row = NewFilePosRow + 2 - 1; 1456 } 1457 1458 HBufferImage.BufferPosition.Row = NewFilePosRow; 1459 } else { 1460 // 1461 // in current screen 1462 // 1463 HBufferImage.BufferPosition.Row = NewFilePosRow; 1464 if (RowGap <= 0) { 1465 Abs = (UINTN)ABS(RowGap); 1466 HBufferImage.DisplayPosition.Row -= Abs; 1467 } else { 1468 HBufferImage.DisplayPosition.Row += RowGap; 1469 } 1470 1471 } 1472 } 1473 1474 HBufferImage.LowVisibleRow = HBufferImage.BufferPosition.Row - (HBufferImage.DisplayPosition.Row - 2); 1475 1476 // 1477 // always in current screen 1478 // 1479 HBufferImage.BufferPosition.Column = NewFilePosCol; 1480 1481 NewDisplayCol = 10 + (NewFilePosCol - 1) * 3; 1482 if (NewFilePosCol > 0x8) { 1483 NewDisplayCol++; 1484 } 1485 1486 if (!HighBits) { 1487 NewDisplayCol++; 1488 } 1489 1490 HBufferImage.DisplayPosition.Column = NewDisplayCol; 1491 1492 // 1493 // let CurrentLine point to correct line; 1494 // 1495 HBufferImage.CurrentLine = HMoveCurrentLine (RowGap); 1496 1497 } 1498 1499 /** 1500 Scroll cursor to right. 1501 1502 @retval EFI_SUCCESS The operation was successful. 1503 **/ 1504 EFI_STATUS 1505 HBufferImageScrollRight ( 1506 VOID 1507 ) 1508 { 1509 HEFI_EDITOR_LINE *Line; 1510 UINTN FRow; 1511 UINTN FCol; 1512 1513 // 1514 // scroll right will always move to the high4 bits of the next character 1515 // 1516 HBufferImageNeedRefresh = FALSE; 1517 HBufferImageOnlyLineNeedRefresh = FALSE; 1518 1519 Line = HBufferImage.CurrentLine; 1520 1521 FRow = HBufferImage.BufferPosition.Row; 1522 FCol = HBufferImage.BufferPosition.Column; 1523 1524 // 1525 // this line is not full and no next line 1526 // 1527 if (FCol > Line->Size) { 1528 return EFI_SUCCESS; 1529 } 1530 // 1531 // if already at end of this line, scroll it to the start of next line 1532 // 1533 if (FCol == 0x10) { 1534 // 1535 // has next line 1536 // 1537 if (Line->Link.ForwardLink != HBufferImage.ListHead) { 1538 FRow++; 1539 FCol = 1; 1540 1541 } else { 1542 return EFI_SUCCESS; 1543 } 1544 } else { 1545 // 1546 // if not at end of this line, just move to next column 1547 // 1548 FCol++; 1549 1550 } 1551 1552 HBufferImageMovePosition (FRow, FCol, TRUE); 1553 1554 return EFI_SUCCESS; 1555 } 1556 1557 /** 1558 Scroll cursor to left. 1559 1560 @retval EFI_SUCCESS The operation was successful. 1561 **/ 1562 EFI_STATUS 1563 HBufferImageScrollLeft ( 1564 VOID 1565 ) 1566 { 1567 1568 HEFI_EDITOR_LINE *Line; 1569 UINTN FRow; 1570 UINTN FCol; 1571 1572 HBufferImageNeedRefresh = FALSE; 1573 HBufferImageOnlyLineNeedRefresh = FALSE; 1574 1575 Line = HBufferImage.CurrentLine; 1576 1577 FRow = HBufferImage.BufferPosition.Row; 1578 FCol = HBufferImage.BufferPosition.Column; 1579 1580 // 1581 // if already at start of this line, so move to the end of previous line 1582 // 1583 if (FCol <= 1) { 1584 // 1585 // has previous line 1586 // 1587 if (Line->Link.BackLink != HBufferImage.ListHead) { 1588 FRow--; 1589 Line = CR (Line->Link.BackLink, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); 1590 FCol = Line->Size; 1591 } else { 1592 return EFI_SUCCESS; 1593 } 1594 } else { 1595 // 1596 // if not at start of this line, just move to previous column 1597 // 1598 FCol--; 1599 } 1600 1601 HBufferImageMovePosition (FRow, FCol, TRUE); 1602 1603 return EFI_SUCCESS; 1604 } 1605 1606 /** 1607 Scroll cursor to the next line 1608 1609 @retval EFI_SUCCESS The operation was successful. 1610 **/ 1611 EFI_STATUS 1612 HBufferImageScrollDown ( 1613 VOID 1614 ) 1615 { 1616 HEFI_EDITOR_LINE *Line; 1617 UINTN FRow; 1618 UINTN FCol; 1619 BOOLEAN HighBits; 1620 1621 Line = HBufferImage.CurrentLine; 1622 1623 FRow = HBufferImage.BufferPosition.Row; 1624 FCol = HBufferImage.BufferPosition.Column; 1625 HighBits = HBufferImage.HighBits; 1626 1627 // 1628 // has next line 1629 // 1630 if (Line->Link.ForwardLink != HBufferImage.ListHead) { 1631 FRow++; 1632 Line = CR (Line->Link.ForwardLink, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); 1633 1634 // 1635 // if the next line is not that long, so move to end of next line 1636 // 1637 if (FCol > Line->Size) { 1638 FCol = Line->Size + 1; 1639 HighBits = TRUE; 1640 } 1641 1642 } else { 1643 return EFI_SUCCESS; 1644 } 1645 1646 HBufferImageMovePosition (FRow, FCol, HighBits); 1647 1648 return EFI_SUCCESS; 1649 } 1650 1651 /** 1652 Scroll cursor to previous line 1653 1654 @retval EFI_SUCCESS The operation was successful. 1655 **/ 1656 EFI_STATUS 1657 HBufferImageScrollUp ( 1658 VOID 1659 ) 1660 { 1661 HEFI_EDITOR_LINE *Line; 1662 UINTN FRow; 1663 UINTN FCol; 1664 1665 Line = HBufferImage.CurrentLine; 1666 1667 FRow = HBufferImage.BufferPosition.Row; 1668 FCol = HBufferImage.BufferPosition.Column; 1669 1670 // 1671 // has previous line 1672 // 1673 if (Line->Link.BackLink != HBufferImage.ListHead) { 1674 FRow--; 1675 1676 } else { 1677 return EFI_SUCCESS; 1678 } 1679 1680 HBufferImageMovePosition (FRow, FCol, HBufferImage.HighBits); 1681 1682 return EFI_SUCCESS; 1683 } 1684 1685 /** 1686 Scroll cursor to next page 1687 1688 @retval EFI_SUCCESS The operation was successful. 1689 **/ 1690 EFI_STATUS 1691 HBufferImagePageDown ( 1692 VOID 1693 ) 1694 { 1695 HEFI_EDITOR_LINE *Line; 1696 UINTN FRow; 1697 UINTN FCol; 1698 UINTN Gap; 1699 BOOLEAN HighBits; 1700 1701 Line = HBufferImage.CurrentLine; 1702 1703 FRow = HBufferImage.BufferPosition.Row; 1704 FCol = HBufferImage.BufferPosition.Column; 1705 HighBits = HBufferImage.HighBits; 1706 1707 // 1708 // has next page 1709 // 1710 if (HBufferImage.NumLines >= FRow + (HMainEditor.ScreenSize.Row - 2)) { 1711 Gap = (HMainEditor.ScreenSize.Row - 2); 1712 } else { 1713 // 1714 // MOVE CURSOR TO LAST LINE 1715 // 1716 Gap = HBufferImage.NumLines - FRow; 1717 } 1718 // 1719 // get correct line 1720 // 1721 Line = HMoveLine (Gap); 1722 1723 // 1724 // if that line, is not that long, so move to the end of that line 1725 // 1726 if (Line != NULL && FCol > Line->Size) { 1727 FCol = Line->Size + 1; 1728 HighBits = TRUE; 1729 } 1730 1731 FRow += Gap; 1732 1733 HBufferImageMovePosition (FRow, FCol, HighBits); 1734 1735 return EFI_SUCCESS; 1736 } 1737 1738 /** 1739 Scroll cursor to previous page 1740 1741 @retval EFI_SUCCESS The operation was successful. 1742 **/ 1743 EFI_STATUS 1744 HBufferImagePageUp ( 1745 VOID 1746 ) 1747 { 1748 UINTN FRow; 1749 UINTN FCol; 1750 UINTN Gap; 1751 INTN Retreat; 1752 1753 FRow = HBufferImage.BufferPosition.Row; 1754 FCol = HBufferImage.BufferPosition.Column; 1755 1756 // 1757 // has previous page 1758 // 1759 if (FRow > (HMainEditor.ScreenSize.Row - 2)) { 1760 Gap = (HMainEditor.ScreenSize.Row - 2); 1761 } else { 1762 // 1763 // the first line of file will displayed on the first line of screen 1764 // 1765 Gap = FRow - 1; 1766 } 1767 1768 Retreat = Gap; 1769 Retreat = -Retreat; 1770 1771 FRow -= Gap; 1772 1773 HBufferImageMovePosition (FRow, FCol, HBufferImage.HighBits); 1774 1775 return EFI_SUCCESS; 1776 } 1777 1778 /** 1779 Scroll cursor to start of line 1780 1781 @retval EFI_SUCCESS The operation was successful. 1782 **/ 1783 EFI_STATUS 1784 HBufferImageHome ( 1785 VOID 1786 ) 1787 { 1788 UINTN FRow; 1789 UINTN FCol; 1790 BOOLEAN HighBits; 1791 1792 // 1793 // curosr will at the high bit 1794 // 1795 FRow = HBufferImage.BufferPosition.Row; 1796 FCol = 1; 1797 HighBits = TRUE; 1798 1799 // 1800 // move cursor position 1801 // 1802 HBufferImageMovePosition (FRow, FCol, HighBits); 1803 1804 return EFI_SUCCESS; 1805 } 1806 1807 /** 1808 Scroll cursor to end of line. 1809 1810 @retval EFI_SUCCESS Teh operation was successful. 1811 **/ 1812 EFI_STATUS 1813 HBufferImageEnd ( 1814 VOID 1815 ) 1816 { 1817 HEFI_EDITOR_LINE *Line; 1818 UINTN FRow; 1819 UINTN FCol; 1820 BOOLEAN HighBits; 1821 1822 // 1823 // need refresh mouse 1824 // 1825 HBufferImageMouseNeedRefresh = TRUE; 1826 1827 Line = HBufferImage.CurrentLine; 1828 1829 FRow = HBufferImage.BufferPosition.Row; 1830 1831 if (Line->Size == 0x10) { 1832 FCol = Line->Size; 1833 HighBits = FALSE; 1834 } else { 1835 FCol = Line->Size + 1; 1836 HighBits = TRUE; 1837 } 1838 // 1839 // move cursor position 1840 // 1841 HBufferImageMovePosition (FRow, FCol, HighBits); 1842 1843 return EFI_SUCCESS; 1844 } 1845 1846 /** 1847 Get the size of the open buffer. 1848 1849 @retval The size in bytes. 1850 **/ 1851 UINTN 1852 HBufferImageGetTotalSize ( 1853 VOID 1854 ) 1855 { 1856 UINTN Size; 1857 1858 HEFI_EDITOR_LINE *Line; 1859 1860 // 1861 // calculate the total size of whole line list's buffer 1862 // 1863 if (HBufferImage.Lines == NULL) { 1864 return 0; 1865 } 1866 1867 Line = CR ( 1868 HBufferImage.ListHead->BackLink, 1869 HEFI_EDITOR_LINE, 1870 Link, 1871 EFI_EDITOR_LINE_LIST 1872 ); 1873 // 1874 // one line at most 0x10 1875 // 1876 Size = 0x10 * (HBufferImage.NumLines - 1) + Line->Size; 1877 1878 return Size; 1879 } 1880 1881 /** 1882 Delete character from buffer. 1883 1884 @param[in] Pos Position, Pos starting from 0. 1885 @param[in] Count The Count of characters to delete. 1886 @param[out] DeleteBuffer The DeleteBuffer. 1887 1888 @retval EFI_SUCCESS Success 1889 **/ 1890 EFI_STATUS 1891 HBufferImageDeleteCharacterFromBuffer ( 1892 IN UINTN Pos, 1893 IN UINTN Count, 1894 OUT UINT8 *DeleteBuffer 1895 ) 1896 { 1897 UINTN Index; 1898 1899 VOID *Buffer; 1900 UINT8 *BufferPtr; 1901 UINTN Size; 1902 1903 HEFI_EDITOR_LINE *Line; 1904 LIST_ENTRY *Link; 1905 1906 UINTN OldFCol; 1907 UINTN OldFRow; 1908 UINTN OldPos; 1909 1910 UINTN NewPos; 1911 1912 EFI_STATUS Status; 1913 1914 Size = HBufferImageGetTotalSize (); 1915 1916 if (Size < Count) { 1917 return EFI_LOAD_ERROR; 1918 } 1919 1920 if (Size == 0) { 1921 return EFI_SUCCESS; 1922 } 1923 1924 // 1925 // relocate all the HBufferImage fields 1926 // 1927 OldFRow = HBufferImage.BufferPosition.Row; 1928 OldFCol = HBufferImage.BufferPosition.Column; 1929 OldPos = (OldFRow - 1) * 0x10 + OldFCol - 1; 1930 1931 if (Pos > 0) { 1932 // 1933 // has character before it, 1934 // so locate according to block's previous character 1935 // 1936 NewPos = Pos - 1; 1937 1938 } else { 1939 // 1940 // has no character before it, 1941 // so locate according to block's next character 1942 // 1943 NewPos = 0; 1944 } 1945 1946 HBufferImageMovePosition (NewPos / 0x10 + 1, NewPos % 0x10 + 1, TRUE); 1947 1948 Buffer = AllocateZeroPool (Size); 1949 if (Buffer == NULL) { 1950 return EFI_OUT_OF_RESOURCES; 1951 } 1952 1953 HBufferImageListToBuffer (Buffer, Size); 1954 1955 BufferPtr = (UINT8 *) Buffer; 1956 1957 // 1958 // pass deleted buffer out 1959 // 1960 if (DeleteBuffer != NULL) { 1961 for (Index = 0; Index < Count; Index++) { 1962 DeleteBuffer[Index] = BufferPtr[Pos + Index]; 1963 } 1964 } 1965 // 1966 // delete the part from Pos 1967 // 1968 for (Index = Pos; Index < Size - Count; Index++) { 1969 BufferPtr[Index] = BufferPtr[Index + Count]; 1970 } 1971 1972 Size -= Count; 1973 1974 HBufferImageFreeLines (); 1975 1976 Status = HBufferImageBufferToList (Buffer, Size); 1977 FreePool (Buffer); 1978 1979 if (EFI_ERROR (Status)) { 1980 return Status; 1981 } 1982 1983 Link = HMainEditor.BufferImage->ListHead->ForwardLink; 1984 for (Index = 0; Index < NewPos / 0x10; Index++) { 1985 Link = Link->ForwardLink; 1986 } 1987 1988 Line = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); 1989 HBufferImage.CurrentLine = Line; 1990 1991 // 1992 // if current cursor position if inside select area 1993 // then move it to the block's NEXT character 1994 // 1995 if (OldPos >= Pos && OldPos < (Pos + Count)) { 1996 NewPos = Pos; 1997 } else { 1998 if (OldPos < Pos) { 1999 NewPos = OldPos; 2000 } else { 2001 NewPos = OldPos - Count; 2002 } 2003 } 2004 2005 HBufferImageMovePosition (NewPos / 0x10 + 1, NewPos % 0x10 + 1, TRUE); 2006 2007 return EFI_SUCCESS; 2008 } 2009 2010 /** 2011 Add character to buffer, add before pos. 2012 2013 @param[in] Pos Position, Pos starting from 0. 2014 @param[in] Count Count of characters to add. 2015 @param[in] AddBuffer Add buffer. 2016 2017 @retval EFI_SUCCESS Success. 2018 **/ 2019 EFI_STATUS 2020 HBufferImageAddCharacterToBuffer ( 2021 IN UINTN Pos, 2022 IN UINTN Count, 2023 IN UINT8 *AddBuffer 2024 ) 2025 { 2026 INTN Index; 2027 2028 VOID *Buffer; 2029 UINT8 *BufferPtr; 2030 UINTN Size; 2031 2032 HEFI_EDITOR_LINE *Line; 2033 2034 LIST_ENTRY *Link; 2035 2036 UINTN OldFCol; 2037 UINTN OldFRow; 2038 UINTN OldPos; 2039 2040 UINTN NewPos; 2041 2042 Size = HBufferImageGetTotalSize (); 2043 2044 // 2045 // relocate all the HBufferImage fields 2046 // 2047 OldFRow = HBufferImage.BufferPosition.Row; 2048 OldFCol = HBufferImage.BufferPosition.Column; 2049 OldPos = (OldFRow - 1) * 0x10 + OldFCol - 1; 2050 2051 // 2052 // move cursor before Pos 2053 // 2054 if (Pos > 0) { 2055 NewPos = Pos - 1; 2056 } else { 2057 NewPos = 0; 2058 } 2059 2060 HBufferImageMovePosition (NewPos / 0x10 + 1, NewPos % 0x10 + 1, TRUE); 2061 2062 Buffer = AllocateZeroPool (Size + Count); 2063 if (Buffer == NULL) { 2064 return EFI_OUT_OF_RESOURCES; 2065 } 2066 2067 HBufferImageListToBuffer (Buffer, Size); 2068 2069 BufferPtr = (UINT8 *) Buffer; 2070 2071 // 2072 // get a place to add 2073 // 2074 for (Index = (INTN) (Size + Count - 1); Index >= (INTN) Pos; Index--) { 2075 BufferPtr[Index] = BufferPtr[Index - Count]; 2076 } 2077 // 2078 // add the buffer 2079 // 2080 for (Index = (INTN) 0; Index < (INTN) Count; Index++) { 2081 BufferPtr[Index + Pos] = AddBuffer[Index]; 2082 } 2083 2084 Size += Count; 2085 2086 HBufferImageFreeLines (); 2087 2088 HBufferImageBufferToList (Buffer, Size); 2089 2090 FreePool (Buffer); 2091 2092 Link = HMainEditor.BufferImage->ListHead->ForwardLink; 2093 for (Index = 0; Index < (INTN) NewPos / 0x10; Index++) { 2094 Link = Link->ForwardLink; 2095 } 2096 2097 Line = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); 2098 HBufferImage.CurrentLine = Line; 2099 2100 if (OldPos >= Pos) { 2101 NewPos = OldPos + Count; 2102 } else { 2103 NewPos = OldPos; 2104 } 2105 2106 HBufferImageMovePosition (NewPos / 0x10 + 1, NewPos % 0x10 + 1, TRUE); 2107 2108 return EFI_SUCCESS; 2109 } 2110 2111 /** 2112 Delete current character from line. 2113 2114 @retval EFI_SUCCESS The operationw as successful. 2115 **/ 2116 EFI_STATUS 2117 HBufferImageDoDelete ( 2118 VOID 2119 ) 2120 { 2121 2122 HEFI_EDITOR_LINE *Line; 2123 2124 BOOLEAN LastLine; 2125 UINTN FileColumn; 2126 UINTN FPos; 2127 2128 FPos = (HBufferImage.BufferPosition.Row - 1) * 0x10 + HBufferImage.BufferPosition.Column - 1; 2129 2130 FileColumn = HBufferImage.BufferPosition.Column; 2131 2132 Line = HBufferImage.CurrentLine; 2133 2134 // 2135 // if beyond the last character 2136 // 2137 if (FileColumn > Line->Size) { 2138 return EFI_SUCCESS; 2139 } 2140 2141 LastLine = FALSE; 2142 if (Line->Link.ForwardLink == HBufferImage.ListHead) { 2143 LastLine = TRUE; 2144 } 2145 2146 HBufferImageDeleteCharacterFromBuffer (FPos, 1, NULL); 2147 2148 // 2149 // if is the last line 2150 // then only this line need to be refreshed 2151 // 2152 if (LastLine) { 2153 HBufferImageNeedRefresh = FALSE; 2154 HBufferImageOnlyLineNeedRefresh = TRUE; 2155 } else { 2156 HBufferImageNeedRefresh = TRUE; 2157 HBufferImageOnlyLineNeedRefresh = FALSE; 2158 } 2159 2160 if (!HBufferImage.Modified) { 2161 HBufferImage.Modified = TRUE; 2162 } 2163 2164 return EFI_SUCCESS; 2165 } 2166 2167 /** 2168 Change the raw buffer to a list of lines for the UI. 2169 2170 @param[in] Buffer The pointer to the buffer to fill. 2171 @param[in] Bytes The size of the buffer in bytes. 2172 2173 @retval EFI_SUCCESS The operation was successful. 2174 @retval EFI_OUT_OF_RESOURCES A memory allocation failed. 2175 **/ 2176 EFI_STATUS 2177 HBufferImageBufferToList ( 2178 IN VOID *Buffer, 2179 IN UINTN Bytes 2180 ) 2181 { 2182 UINTN TempI; 2183 UINTN TempJ; 2184 UINTN Left; 2185 HEFI_EDITOR_LINE *Line; 2186 UINT8 *BufferPtr; 2187 2188 TempI = 0; 2189 Left = 0; 2190 BufferPtr = (UINT8 *) Buffer; 2191 2192 // 2193 // parse file content line by line 2194 // 2195 while (TempI < Bytes) { 2196 if (Bytes - TempI >= 0x10) { 2197 Left = 0x10; 2198 } else { 2199 Left = Bytes - TempI; 2200 } 2201 2202 // 2203 // allocate a new line 2204 // 2205 Line = HBufferImageCreateLine (); 2206 if (Line == NULL) { 2207 return EFI_OUT_OF_RESOURCES; 2208 } 2209 2210 Line->Size = Left; 2211 2212 for (TempJ = 0; TempJ < Left; TempJ++) { 2213 Line->Buffer[TempJ] = BufferPtr[TempI]; 2214 TempI++; 2215 } 2216 2217 } 2218 2219 // 2220 // last line is a full line, SO create a new line 2221 // 2222 if (Left == 0x10 || Bytes == 0) { 2223 Line = HBufferImageCreateLine (); 2224 if (Line == NULL) { 2225 return EFI_OUT_OF_RESOURCES; 2226 } 2227 } 2228 2229 return EFI_SUCCESS; 2230 } 2231 2232 /** 2233 Change the list of lines from the UI to a raw buffer. 2234 2235 @param[in] Buffer The pointer to the buffer to fill. 2236 @param[in] Bytes The size of the buffer in bytes. 2237 2238 @retval EFI_SUCCESS The operation was successful. 2239 **/ 2240 EFI_STATUS 2241 HBufferImageListToBuffer ( 2242 IN VOID *Buffer, 2243 IN UINTN Bytes 2244 ) 2245 { 2246 UINTN Count; 2247 UINTN Index; 2248 HEFI_EDITOR_LINE *Line; 2249 LIST_ENTRY *Link; 2250 UINT8 *BufferPtr; 2251 2252 // 2253 // change the line list to a large buffer 2254 // 2255 if (HBufferImage.Lines == NULL) { 2256 return EFI_SUCCESS; 2257 } 2258 2259 Link = &HBufferImage.Lines->Link; 2260 Count = 0; 2261 BufferPtr = (UINT8 *) Buffer; 2262 2263 // 2264 // deal line by line 2265 // 2266 while (Link != HBufferImage.ListHead) { 2267 2268 Line = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST); 2269 2270 //@todo shouldn't this be an error??? 2271 if (Count + Line->Size > Bytes) { 2272 return EFI_SUCCESS; 2273 } 2274 2275 for (Index = 0; Index < Line->Size; Index++) { 2276 BufferPtr[Index] = Line->Buffer[Index]; 2277 } 2278 2279 Count += Line->Size; 2280 BufferPtr += Line->Size; 2281 2282 Link = Link->ForwardLink; 2283 } 2284 2285 return EFI_SUCCESS; 2286 } 2287 2288 /** 2289 Move the mouse in the image buffer. 2290 2291 @param[in] TextX The x-coordinate. 2292 @param[in] TextY The y-coordinate. 2293 **/ 2294 VOID 2295 HBufferImageAdjustMousePosition ( 2296 IN INT32 TextX, 2297 IN INT32 TextY 2298 ) 2299 { 2300 UINTN TempX; 2301 UINTN TempY; 2302 UINTN AbsX; 2303 UINTN AbsY; 2304 2305 // 2306 // TextX and TextY is mouse movement data returned by mouse driver 2307 // This function will change it to MousePosition 2308 // 2309 // 2310 // get absolute TempX value 2311 // 2312 if (TextX >= 0) { 2313 AbsX = TextX; 2314 } else { 2315 AbsX = -TextX; 2316 } 2317 // 2318 // get absolute TempY value 2319 // 2320 if (TextY >= 0) { 2321 AbsY = TextY; 2322 } else { 2323 AbsY = -TextY; 2324 } 2325 2326 TempX = HBufferImage.MousePosition.Column; 2327 TempY = HBufferImage.MousePosition.Row; 2328 2329 if (TextX >= 0) { 2330 TempX += TextX; 2331 } else { 2332 if (TempX >= AbsX) { 2333 TempX -= AbsX; 2334 } else { 2335 TempX = 0; 2336 } 2337 } 2338 2339 if (TextY >= 0) { 2340 TempY += TextY; 2341 } else { 2342 if (TempY >= AbsY) { 2343 TempY -= AbsY; 2344 } else { 2345 TempY = 0; 2346 } 2347 } 2348 // 2349 // check whether new mouse column position is beyond screen 2350 // if not, adjust it 2351 // 2352 if (TempX >= 10 && TempX <= (10 + 0x10 * 3 - 1)) { 2353 HBufferImage.MousePosition.Column = TempX; 2354 } else if (TempX < 10) { 2355 HBufferImage.MousePosition.Column = 10; 2356 } else if (TempX > (10 + 0x10 * 3 - 1)) { 2357 HBufferImage.MousePosition.Column = 10 + 0x10 * 3 - 1; 2358 } 2359 // 2360 // check whether new mouse row position is beyond screen 2361 // if not, adjust it 2362 // 2363 if (TempY >= 2 && TempY <= (HMainEditor.ScreenSize.Row - 1)) { 2364 HBufferImage.MousePosition.Row = TempY; 2365 } else if (TempY < 2) { 2366 HBufferImage.MousePosition.Row = 2; 2367 } else if (TempY > (HMainEditor.ScreenSize.Row - 1)) { 2368 HBufferImage.MousePosition.Row = (HMainEditor.ScreenSize.Row - 1); 2369 } 2370 2371 } 2372 2373 /** 2374 Dispatch input to different handler 2375 2376 @param[in] Key The input key: 2377 the keys can be: 2378 ASCII KEY 2379 Backspace/Delete 2380 Direction key: up/down/left/right/pgup/pgdn 2381 Home/End 2382 INS 2383 2384 @retval EFI_SUCCESS The operation was successful. 2385 @retval EFI_LOAD_ERROR A load error occured. 2386 @retval EFI_OUT_OF_RESOURCES A Memory allocation failed. 2387 **/ 2388 EFI_STATUS 2389 HBufferImageHandleInput ( 2390 IN EFI_INPUT_KEY *Key 2391 ) 2392 { 2393 EFI_STATUS Status; 2394 2395 Status = EFI_SUCCESS; 2396 2397 switch (Key->ScanCode) { 2398 // 2399 // ordinary key 2400 // 2401 case SCAN_NULL: 2402 Status = HBufferImageDoCharInput (Key->UnicodeChar); 2403 break; 2404 2405 // 2406 // up arrow 2407 // 2408 case SCAN_UP: 2409 Status = HBufferImageScrollUp (); 2410 break; 2411 2412 // 2413 // down arrow 2414 // 2415 case SCAN_DOWN: 2416 Status = HBufferImageScrollDown (); 2417 break; 2418 2419 // 2420 // right arrow 2421 // 2422 case SCAN_RIGHT: 2423 Status = HBufferImageScrollRight (); 2424 break; 2425 2426 // 2427 // left arrow 2428 // 2429 case SCAN_LEFT: 2430 Status = HBufferImageScrollLeft (); 2431 break; 2432 2433 // 2434 // page up 2435 // 2436 case SCAN_PAGE_UP: 2437 Status = HBufferImagePageUp (); 2438 break; 2439 2440 // 2441 // page down 2442 // 2443 case SCAN_PAGE_DOWN: 2444 Status = HBufferImagePageDown (); 2445 break; 2446 2447 // 2448 // delete 2449 // 2450 case SCAN_DELETE: 2451 Status = HBufferImageDoDelete (); 2452 break; 2453 2454 // 2455 // home 2456 // 2457 case SCAN_HOME: 2458 Status = HBufferImageHome (); 2459 break; 2460 2461 // 2462 // end 2463 // 2464 case SCAN_END: 2465 Status = HBufferImageEnd (); 2466 break; 2467 2468 default: 2469 Status = StatusBarSetStatusString (L"Unknown Command"); 2470 break; 2471 } 2472 2473 return Status; 2474 } 2475 2476